Bộ vi điều khiển AVR bao gồm một số lượng lớn các thiết bị ngoại vi (ADC, Bộ đếm thời gian/Bộ đếm, EXTI, Bộ so sánh tương tự, EEPROM, USART, SPI, I2C, v.v.), mỗi thiết bị có thể thực hiện một số hành động nhất định đối với dữ liệu/tín hiệu và thông tin khác. Các thiết bị này được tích hợp vào bộ vi điều khiển để nâng cao hiệu quả ứng dụng và giảm chi phí khi phát triển tất cả các loại thiết bị dựa trên bộ vi điều khiển AVR.
Bộ xử lý giao tiếp/điều khiển các thiết bị ngoại vi thông qua các Thanh ghi I/O nằm trong Bộ nhớ dữ liệu, cho phép chúng được sử dụng như các biến thông thường. Mỗi thiết bị có thanh ghi I/O riêng.
Tất cả các thanh ghi I/O có thể được chia thành ba nhóm: thanh ghi dữ liệu, thanh ghi điều khiển và thanh ghi trạng thái.
Sử dụng Thanh ghi điều khiển, thiết bị được cấu hình để hoạt động ở chế độ này hay chế độ khác, với tần số, độ chính xác nhất định, v.v. và sử dụng Thanh ghi dữ liệu, kết quả hoạt động của thiết bị này được đọc (chuyển đổi tương tự sang số, nhận dữ liệu, giá trị bộ đếm thời gian/bộ đếm, v.v.). Có vẻ như không có gì phức tạp ở đây (thực tế là không có gì phức tạp ở đây :)), bật thiết bị, chỉ định chế độ vận hành mong muốn và tất cả những gì còn lại là cắt phiếu giảm giá, đọc dữ liệu làm sẵn và sử dụng chúng trong tính toán. Toàn bộ câu hỏi là “khi nào” đọc chính dữ liệu này (thiết bị đã hoàn thành công việc của mình hay vẫn đang xử lý dữ liệu), bởi vì tất cả các thiết bị ngoại vi đều hoạt động song song với lõi vi điều khiển và thậm chí ở các tần số khác nhau. và đồng bộ hóa giữa bộ xử lý và thiết bị ngoại vi.
Như bạn có thể đã đoán, để thực hiện giao tiếp và đồng bộ hóa giữa thiết bị và bộ xử lý, “Thanh ghi trạng thái” được sử dụng để lưu trữ trạng thái hoạt động hiện tại của một thiết bị cụ thể. Mỗi trạng thái mà thiết bị có thể tương ứng với một “bit in”. trạng thái đăng ký” (cờ), giá trị hiện tại “nói” về trạng thái hiện tại của thiết bị này hoặc chức năng riêng của nó (công việc đã hoàn thành/chưa hoàn thành, lỗi trong quá trình xử lý dữ liệu, đăng ký trống, v.v.).
Cơ chế giao tiếp giữa bộ xử lý và thiết bị ngoại vi được thực hiện bằng cách bỏ phiếu, chịu trách nhiệm về một chức năng cụ thể của thiết bị này. Tùy thuộc vào giá trị của một cờ cụ thể (trạng thái thiết bị), bạn có thể thay đổi luồng thực thi chương trình (phân nhánh). Ví dụ:
Kiểm tra xem một cờ nhất định có được đặt hay không (một số sự kiện đã xảy ra):
nếu (RegX & (1<<
Flag)
)
// nếu cờ trong thanh ghi RegX được đặt
{
// làm điều gì đó
}
Đang chờ hoàn thành một số hành động (sự kiện):
while(!(RegX & (1< Cờ truy vấn là một nhiệm vụ khá tốn tài nguyên, cả về kích thước chương trình và tốc độ chương trình. Do tổng số cờ trong bộ vi điều khiển AVR khá lớn (một lợi thế) nên việc thực hiện giao tiếp giữa bộ xử lý và thiết bị bằng cờ thăm dò dẫn đến giảm hiệu quả (tốc độ mã/kích thước mã) của chương trình bạn viết, Ngoài ra, chương trình trở nên rất khó hiểu, góp phần xuất hiện các lỗi khó phát hiện ngay cả khi gỡ lỗi mã chi tiết. Để tăng hiệu quả của các chương trình dành cho bộ vi điều khiển AVR, cũng như để tạo điều kiện thuận lợi cho quá trình tạo và gỡ lỗi các chương trình này, các nhà phát triển đã trang bị cho tất cả các thiết bị ngoại vi “nguồn ngắt” ( Nguồn ngắt), một số thiết bị có thể có nhiều nguồn ngắt. Sử dụng các nguồn ngắt, nó được thực hiện cơ chế đồng bộ hóa, giữa bộ xử lý và thiết bị ngoại vi, nghĩa là bộ xử lý sẽ bắt đầu nhận dữ liệu, cờ thăm dò và các hành động khác trên thiết bị ngoại vi chỉ khi thiết bị sẵn sàng cho việc này (nó sẽ báo cáo việc hoàn tất xử lý dữ liệu, có lỗi trong quá trình xử lý dữ liệu, thanh ghi trống, v.v.), v.v.), bằng cách tạo ra một "yêu cầu ngắt" ( Yêu cầu ngắt), tùy thuộc vào giá trị của một số cờ (trạng thái thiết bị/chức năng/sự kiện). Trong tài liệu, rất thường xuyên, toàn bộ chuỗi sự kiện, bắt đầu từ “yêu cầu ngắt” (IRQ) đến “thủ tục dịch vụ ngắt” (ISR), được viết tắt là ngắt ( Ngắt).
Ngắt là gì?
Ngắt là tín hiệu thông báo cho bộ xử lý về sự xuất hiện của một sự kiện. Trong trường hợp này, việc thực thi chuỗi lệnh hiện tại bị tạm dừng và điều khiển được chuyển sang quy trình xử lý ngắt tương ứng với sự kiện này, sau đó việc thực thi mã tiếp tục chính xác từ điểm bị gián đoạn (trả lại quyền điều khiển). (Wiki)
thói quen ngắt(Thói quen dịch vụ ngắt) không gì khác hơn là một hàm/chương trình con sẽ được thực thi khi một sự kiện nhất định xảy ra. Chúng ta sẽ sử dụng từ “thủ tục” để nhấn mạnh sự khác biệt của nó với tất cả các chức năng khác. Sự khác biệt chính giữa thủ tục và các hàm đơn giản là thay vì “trả về từ hàm” thông thường (lệnh hợp ngữ RET), bạn nên sử dụng “trả về từ ngắt” (lệnh hợp ngữ RETI) - " TRỞ LẠI từ ngắt".
Thuộc tính ngắt AVR: Ngắt Reset, không giống như tất cả các ngắt khác, không thể bị vô hiệu hóa. Những gián đoạn như vậy còn được gọi là những ngắt không thể che dấu được.
Bảng vectơ ngắt, ngoại trừ vectơ Đặt lại, có thể được di chuyển đến đầu phần Khởi động của bộ nhớ Flash bằng cách đặt bit IVSEL trong thanh ghi GICR. Vectơ đặt lại cũng có thể được di chuyển đến đầu phần Khởi động của bộ nhớ Flash bằng cách lập trình bit cầu chì - BOOTRST.
Hình 1 Bảng vectơ ngắt ATmega16 Nguyên mẫu thường trình ngắt
Để khai báo một hàm như một quy trình xử lý ngắt, bạn phải tuân theo các quy tắc tạo mẫu nhất định để trình biên dịch/trình liên kết có thể xác định chính xác và liên kết ngắt bạn cần với quy trình xử lý của nó. Thứ nhất, quy trình phục vụ ngắt không thể chấp nhận bất cứ thứ gì làm đối số (void) và cũng không thể trả về bất cứ thứ gì (void). Điều này là do tất cả các ngắt trong AVR đều không đồng bộ nên không biết việc thực thi chương trình sẽ bị gián đoạn ở đâu, nhận giá trị từ ai và trả về giá trị cho ai, đồng thời cũng để giảm thiểu thời gian vào và ra. từ sự gián đoạn. khoảng trống isr(void) Thứ hai, trước nguyên mẫu hàm, bạn nên chỉ ra rằng đó là một quy trình xử lý ngắt. Như bạn đã biết, trong ngôn ngữ C chỉ có mã được sử dụng trong hàm chính được thực thi. Vì thủ tục xử lý ngắt trong hàm chính không được sử dụng ở bất kỳ đâu, do đó trình biên dịch không "loại bỏ" nó khi không cần thiết, nên trước nguyên mẫu thủ tục cần chỉ ra rằng hàm này là một thủ tục xử lý ngắt. Nguyên mẫu của quy trình xử lý ngắt trong môi trường AVR Studio
#bao gồm ISR (XXX_vect) Trong AVR Studio (AVR GCC), mỗi quy trình ngắt bắt đầu bằng định nghĩa macro ISR, theo sau là cấu trúc sau trong ngoặc đơn: XXX_vect trong đó “XXX” là tên của vectơ ngắt cho một bộ vi điều khiển AVR cụ thể có thể được tìm thấy trong “bảng vectơ ngắt” của biểu dữ liệu của bộ vi điều khiển hoặc trong tệp tiêu đề của nó. Ví dụ: “bảng vectơ ngắt” cho bộ vi điều khiển ATmega16 được hiển thị trong Hình 1, trong đó trong cột Nguồn, tất cả tên của các vectơ ngắt cũng có thể được tìm thấy trong tệp tiêu đề của bộ vi điều khiển này (C). :\Program Files\Atmel\AVR Tools\AVR Toolchain\avr\include\avr\iom16.h), xem Hình 2. Tất cả những gì chúng ta cần làm là tìm tên của vectơ chúng ta cần trong bảng và thêm hậu tố “_vect” với nó.
{
}
Hình 2 Tệp tiêu đề ATmega16 cho AVR Studio
Ví dụ: hãy viết quy trình xử lý ngắt để nhận byte qua USART (USART, Rx Complete):
ISR (USART_RXC_vect)
{
// Phần thân xử lý ngắt
}
Nhân tiện: trước khi sử dụng bất kỳ ngắt nào trong AVR Studio, bạn nên bao gồm các tệp tiêu đề io.h và Interrupt.h trong dự án:
#bao gồm
#bao gồm
Bạn có thể đọc thêm về trình xử lý ngắt trong AVR Studio (AVR GCC) trong phần Giới thiệu về xử lý ngắt của avr-libc.
Nguyên mẫu của thủ tục xử lý ngắt trong môi trường ImageCraft
#pragma ngắt_handler
trống rỗng<
handler_name>(vô hiệu)
{
// Phần thân xử lý ngắt
}
Trong môi trường ImageCraft, quy trình ngắt nguyên mẫu trông như thế này:
trống rỗng< handler_name>(vô hiệu)
Ở đâu
#pragma ngắt_handler
Ở đâu
Hình 3 Tệp tiêu đề ATmega16 cho ImageCraft IDE
Ví dụ: quy trình xử lý ngắt để nhận byte qua USART (USART, Rx Complete) trong môi trường ImageCraft sẽ như sau:
#pragma ngắt_handler usart_rxc_isr: iv_USART_RXC
void usart_rxc_isr(void)
{
// Phần thân xử lý ngắt
}
Thông tin thêm về quy trình xử lý ngắt trong ImageCraft IDE có thể được tìm thấy trong menu Trợ giúp-> Lập trình AVR-> Trình xử lý ngắt của môi trường phát triển.
Đôi khi, nếu một số trình xử lý ngắt cần thực hiện cùng một việc, thì để tiết kiệm bộ nhớ chương trình, bạn có thể hướng một số vectơ ngắt tới cùng một chương trình ngắt.
Trong AVR Studio nó trông như thế này:
ISR (INT0_vect)
{
// Làm gì đó
}
ISR(INT1_vect, ISR_ALIASOF(INT0_vect) ) ;
Đầu tiên là thủ tục xử lý ngắt cho một vectơ cụ thể, trong trường hợp này là INT0. Tất cả các thủ tục khác có thể tham chiếu đến bất kỳ trình xử lý ngắt nào bằng cách sử dụng cấu trúc:
ISR (YYY_vect, ISR_ALIASOF(XXX_vect) ) ;
trong đó YYY là tên của vectơ ngắt đề cập đến trình xử lý ngắt được khai báo trước đó cho vectơ XXX.
Trong ImageCraft nó trông như thế này:
#pragma ngắt_handler
trống rỗng<
handler_name>(vô hiệu)
{
// Phần thân xử lý ngắt
}
#pragma ngắt_handler
#pragma ngắt_handler
trống rỗng<
handler_name>(vô hiệu)
{
// Phần thân xử lý ngắt
}
trong đó vectơ XXX và YYY tham chiếu đến cùng một trình xử lý ngắt
Ngắt hoạt động như thế nào trong bộ vi điều khiển AVR?
1. Giả sử “đã xảy ra” yêu cầu ngắt”(IRQ).
Nhân tiện: nếu một số yêu cầu xử lý ngắt xảy ra đồng thời, ngắt có mức ưu tiên cao nhất sẽ được xử lý trước, tất cả các yêu cầu khác sẽ được xử lý sau khi hoàn thành ngắt có mức ưu tiên cao.
2. Bài kiểm tra.
Nếu bit kích hoạt cho ngắt này được đặt (bit cho phép ngắt) và bit I (bit cho phép ngắt chung) của thanh ghi trạng thái bộ xử lý (SREG) được đặt thì bộ xử lý bắt đầu chuẩn bị quy trình dịch vụ ngắt, trong khi lệnh chung Bit cho phép ngắt (bit I của thanh ghi SREG) được đặt lại, do đó vô hiệu hóa tất cả các ngắt khác. Điều này xảy ra để không có sự kiện nào khác có thể làm gián đoạn quá trình xử lý ngắt hiện tại.
Nhân tiện: nếu trong quy trình xử lý ngắt, bạn đặt I-bit ở trạng thái nhật ký. thì bất kỳ ngắt nào được kích hoạt đều có thể làm gián đoạn quá trình xử lý ngắt hiện tại. Các ngắt như vậy được gọi là các ngắt lồng nhau.
3. Sự chuẩn bị.
Bộ xử lý hoàn thành việc thực hiện lệnh hợp ngữ hiện tại và sau đó đặt địa chỉ của lệnh tiếp theo vào ngăn xếp (PC->STACK). Tiếp theo, bộ xử lý kiểm tra xem nguồn ngắt nào đã gửi “yêu cầu ngắt” (IRQ), sau đó, sử dụng vectơ của nguồn này (liên kết) từ bảng vectơ (được gán chắc chắn cho từng nguồn ngắt), nó sẽ tiến tới thủ tục xử lý ngắt (lệnh JMP). Chỉ vậy thôi, bộ xử lý dành ít nhất 4 chu kỳ xung nhịp (tùy thuộc vào thời điểm yêu cầu xuất hiện và thời lượng của lệnh hiện tại). các nhà sản xuất khác.
Nhân tiện: nếu IRQ xảy ra khi bộ vi điều khiển ở chế độ ngủ, thời gian phản hồi với IRQ sẽ tăng thêm bốn chu kỳ xung nhịp nữa, cộng với thời gian được lưu trong các bit cầu chì SUT1 và SUT0 (Thời gian khởi động).
Ngắt bên ngoài được sử dụng để làm gì?
Gián đoạn là sự kiện trong đó việc thực thi mã chương trình chính (ví dụ: chức năng chính) bị gián đoạn và quyền điều khiển được chuyển đến bộ xử lý ngắt của chức năng. Theo đó, các ngắt bên ngoài là các sự kiện bên ngoài nhất định làm gián đoạn việc thực thi mã chương trình chính.
Các ngắt bên ngoài cho phép bạn nhận được phản hồi nhanh chóng, đảm bảo đối với các sự kiện bên ngoài. Do đó, công dụng phổ biến nhất của ngắt ngoài là thực hiện bộ đếm xung, đo tần số hoặc độ dài xung, triển khai phần mềm uart, one-wire, i2c, spi, cũng như xử lý tín hiệu từ các thiết bị ngoại vi bên ngoài.
Nguyên lý hoạt động của ngắt ngoài trong AVR
Để bộ vi điều khiển tìm hiểu về các sự kiện bên ngoài, các đầu vào rời rạc INT0 INT1, v.v. được sử dụng. Rời rạc có nghĩa là chúng hoạt động với các mức logic: 0 và 1.
0 là không có điện áp ở đầu vào
1 - sự hiện diện của điện áp ở đầu vào, bằng với điện áp cung cấp của vi điều khiển.
Ngắt bên ngoài có thể được chia thành hai loại:
- ngắt bên ngoài theo cấp độ
- ngắt cạnh bên ngoài
Ngắt bên ngoài theo cấp độ
Bộ kích hoạt ngắt bên ngoài có thể được cấu hình ở mức thấp hoặc cao. Ví dụ: nếu ngắt được đặt ở mức logic thấp thì nó sẽ xảy ra khi điện áp ở đầu vào INT bằng 0. Nếu ngắt được đặt ở mức cao thì nó sẽ xảy ra khi đầu vào ở mức logic 1.
Khi làm việc với các ngắt theo cấp độ, bạn phải nhớ rằng chỉ cần đầu vào INT có mức phù hợp thì ngắt sẽ xảy ra liên tục. Những thứ kia. nếu một ngắt xảy ra, chẳng hạn ở mức thấp và chương trình xử lý nó, nhưng nếu khi thoát khỏi trình xử lý ngắt, đầu vào vẫn ở mức thấp thì ngắt sẽ kích hoạt lại và trình xử lý ngắt sẽ được gọi lại, và điều này sẽ tiếp tục cho đến khi mức cao đầu vào xuất hiện. Để ngăn điều này xảy ra, bạn cần tắt loại gián đoạn này trong trình xử lý hoặc cấu hình lại nó ở cấp độ khác.
Ngắt cạnh ngoài
Ngắt trên cạnh tăng, hay như đôi khi người ta nói, tín hiệu tăng, xảy ra khi mức tín hiệu ở đầu vào INT thay đổi từ 0 thành 1. Ngắt trên cạnh giảm (tín hiệu giảm), xảy ra khi mức tín hiệu ở đầu vào INT thay đổi từ 1 thành 0.
Cũng có thể cấu hình ngắt để nó phản ứng với bất kỳ thay đổi nào ở đầu vào INT, tức là. nó sẽ xảy ra dọc theo cả cạnh đầu và cuối.
Cấu hình các ngắt ngoài trong AVR
Ngắt bên ngoài trong avr atmega8 được cấu hình bằng bit ISCxx đăng ký MCUCR .
Sự phụ thuộc của điều kiện kích hoạt của ngắt ngoài INT0 vào bit ISC0x của thanh ghi MCUCR trong avr atmega8
Đối với ngắt bên ngoài INT1 , việc thiết lập được thực hiện theo cách tương tự, chỉ sử dụng các bit ISC11 ISC10 .
Ví dụcài đặt ngắt bên ngoài cho avr atmega8:
// đặt lại tất cả các bit ISCxx MCUCR &= ~( (1 <<ISC11) | (1<<ISC10) | (1<< ISC01) | (1<<ISC00) ) MCUCR |= (1 << ISC01) | (1 << ISC00); |
// đặt lại tất cả các bit ISCxx MCUCR &= ~((1< Để các ngắt ngoài hoạt động, chúng phải được kích hoạt bằng cách đặt các bit tương ứng trong thanh ghi thành 1 GICR
. Chút INT0
chịu trách nhiệm kích hoạt/vô hiệu hóa các ngắt bên ngoài INT0
, và chút INT1
, tương ứng, đối với sự gián đoạn bên ngoài INT1
. Cờ cho phép ngắt toàn cục cũng cần được đặt. Mã ví dụ để kích hoạt ngắt ngoài INT0 cho avr atmega8:
//cho phép ngắt ngoài INT0 GICR |= (1< Để làm ví dụ, tôi sẽ đưa ra một chương trình đếm xung. Chương trình đếm số xung ở đầu vào INT0 và mỗi giây một lần sẽ hiển thị kết quả đếm trong uart. #bao gồm // biến tạm thời Khi bộ vi xử lý gặp một trong các lệnh gọi rcall/call/ecall/icall/eicall, địa chỉ của từ tiếp theo trong bộ nhớ chương trình sẽ được phần cứng sao chép vào ngăn xếp. Khi chương trình con thoát bằng lệnh ret, địa chỉ trả về sẽ được khôi phục từ ngăn xếp về bộ đếm chương trình. Trong các mô hình có dung lượng bộ nhớ chương trình là 128 và 256 kword, việc lưu PC vào ngăn xếp sẽ cần 3 byte, đối với tất cả các mô hình khác - 2 byte. Khi lưu trữ từng byte, nội dung của SP sẽ giảm đi một và khi được khôi phục, chúng sẽ tăng lên tương ứng. Hình 9 Vị trí ngăn xếp trong bộ nhớ dữ liệu Người lập trình phải xác định độc lập vị trí của ngăn xếp ngay từ đầu chương trình. Từ quan điểm về độ sâu tối đa của nó, đỉnh của ngăn xếp phải được đặt ở cuối SRAM, như trong Hình 9: Bao gồm "m8def.inc" ldi temp,low(RAMEND) ;đặt SP = RAMEND out SPL,temp ;đối với ATmega8 SP = 0x045F ldi temp,high(RAMEND) out SPH,temp Hằng số RAMEND từ tệp tiêu đề m8def.inc tiêu chuẩn có giá trị địa chỉ của ô SRAM cuối cùng. Các biến chương trình ứng dụng được đặt trong dải địa chỉ SRAM giữa RBB và vị trí SP hiện tại. Vì vậy, điều rất quan trọng trước tiên là ước tính kích thước ngăn xếp tối đa (độ sâu ngăn xếp). Có thể xảy ra trường hợp đỉnh ngăn xếp tăng quá cao và bắt đầu “ghi đè” dữ liệu người dùng và đây là một trong những lỗi khó phát hiện nhất! Ngăn xếp AVR, ngoài việc lưu trữ các địa chỉ trả về, còn có một mục đích rất quan trọng khác. Nó cho phép bạn lưu bất kỳ dữ liệu nào bằng cách sử dụng các lệnh push Rr (tải vào ngăn xếp) và pop Rd (dỡ khỏi ngăn xếp) được thiết kế đặc biệt cho mục đích này. Mỗi lần thực hiện push Rr, nội dung của Rr sẽ được sao chép vào ngăn xếp, sau đó SP sẽ giảm đi một. Khi pop Rr được thực thi, nội dung của ô ngăn xếp được trỏ tới bởi SP sẽ được khôi phục về Rr và giá trị của chính SP sẽ tăng lên. Loại ngăn xếp này có tổ chức Last In First Out: thanh ghi được lưu bằng lệnh push cuối cùng sẽ được khôi phục bằng lệnh pop đầu tiên: ; SP Mức ngăn xếp sau lệnh đẩy R16 ;lưu R16 0x045F R16 ? ? đẩy R17; lưu R17 0x045E R16 R17? đẩy R18 ;lưu R18 0x045D R16 R17 R18 ̣̣̣̣̣̣̣ bật R18 ;khôi phục R18 0x045D R16 R17 ?<->bật R17; khôi phục R17 0x045E R16? ? Sử dụng ngăn xếp, bạn có thể dễ dàng trao đổi nội dung của các thanh ghi: ; Trao đổi R16 R17 SP Mức ngăn xếp sau lệnh đẩy R16 ;lưu R16 0x045F R16 ?đẩy R17; lưu R17 0x045E R16 R17 pop R16; khôi phục R16 0x045E R16? bật R17; khôi phục R17 0x045F? ? MCUCR Hình 10 Ví dụ về thao tác ngăn xếp Hình 10 cho thấy một đoạn mã nhỏ thể hiện quy trình từng bước thay đổi ngăn xếp khi vào và thoát khỏi chương trình con chuyển đổi cũng như lưu và khôi phục thanh ghi R17. Đây là một ví dụ điển hình trong đó có thể cần đến hướng dẫn đẩy/bật. Chương trình con chuyển đổi sử dụng R17 RON cho nhu cầu của nó, nhưng thanh ghi tương tự cũng có thể được sử dụng trong chương trình chính. Do đó, để tránh dữ liệu bị hỏng, R17 được tải vào ngăn xếp trước khi sửa đổi và được khôi phục từ ngăn xếp đó trước lệnh ret. Một trong những ưu điểm của bộ vi điều khiển ATmega8 là có nhiều loại ngắt khác nhau. Ngắt là một sự kiện khi xảy ra việc thực thi chương trình chính bị tạm dừng và một hàm được gọi để xử lý một loại ngắt nhất định. 4 thanh ghi chịu trách nhiệm quản lý các ngắt trong ATmega8: GIMSK(còn gọi là GICR) - cấm/cho phép ngắt dựa trên tín hiệu ở đầu vào INT0, INT1 GIFR- quản lý tất cả các ngắt bên ngoài TIMSK, TIFR- quản lý sự gián đoạn từ bộ tính giờ/bộ đếm Đăng ký GIMSK(GICR) INTFx=1: xảy ra ngắt ở đầu vào INTx. Khi vào quy trình xử lý ngắt, INTFx sẽ tự động được đặt lại về trạng thái nhật ký. 0 Đăng ký TIMSK TOIE1=1: Đã bật ngắt tràn T/C1 OCIE1A=1: ngắt khi thanh ghi so sánh A khớp với nội dung của bộ đếm T/C1 được kích hoạt OCIE1B=1: ngắt khi thanh ghi so sánh B khớp với nội dung của bộ đếm T/C1 được kích hoạt TICIE=1: ngắt được kích hoạt khi điều kiện chụp được đáp ứng TOIE0=1: Đã bật ngắt tràn T/C0 Đăng ký TIFR TOV1=1: Xảy ra tràn T/C1 OCF1A=1: thanh ghi so sánh A trùng với nội dung của bộ đếm T/C1 cho phép OCF1B=1: thanh ghi so sánh B khớp với nội dung của bộ đếm T/C1 được phép ICF=1: đáp ứng điều kiện chụp TOV0=1: Đã xảy ra tràn T/C0 Khi vào chương trình con xử lý ngắt, cờ đăng ký TIFR tương ứng với ngắt sẽ tự động được đặt lại về trạng thái nhật ký. 0 Ngắt chỉ hoạt động khi ngắt chung được bật trong thanh ghi trạng thái SREG (bit 7 = 1). Khi xảy ra ngắt, bit này sẽ tự động được đặt lại về 0, vô hiệu hóa các ngắt tiếp theo. Trong ví dụ này, chân INT0 được bật ở chế độ đầu vào kéo lên. Khi chân được nối đất bằng một nút, logic 0 được đặt trên đó (cạnh của tín hiệu giảm từ điện áp nguồn xuống 0) và bộ xử lý ngắt được kích hoạt, bật bóng đèn được nối với chân 0 của cổng B đèn trốngON() ngắt void ext_int0_isr(void) DDRD.2=0; SREG|= (1 trong khi(1) ( Ví dụ trên cũng cho thấy cách đặt vectơ ngắt trong Code Vision AVR (ngắt void ext_int0_isr(void)). Các vectơ ngắt được đặt tương tự cho các trường hợp khác: EXT_INT0 2 Hôm nay chúng ta sẽ xem xét khái niệm gián đoạn và cách sử dụng nó. Đương nhiên, chúng tôi sẽ không làm được nếu không có chương trình đào tạo, nhưng lần này chúng tôi sẽ không nhấp nháy đèn LED. Tốt rồi. Hãy làm một cái gì đó giống như chuông cửa. Nhiệm vụ: làm cho bộ vi điều khiển phát ra tiếng bíp khi nhấn nút. Chúng tôi tạo một dự án vòng trong không gian làm việc cũ. Chọn loại vi điều khiển. Cho phép sử dụng tên bit được xác định trong tệp tiêu đề Thay đổi loại tập tin đầu ra. Lưu dự án và không gian làm việc. Hãy tưởng tượng tình huống này. Bạn đang ngồi làm việc và nghiền ngẫm một chương trình vi điều khiển khác. Sếp đến gặp bạn và nói: “Nghe này, Pash, chúng tôi đã mua máy hiện sóng cho bộ phận của mình - Tektronix, bốn kênh. Hãy giúp Vasya kéo chúng đi.” Bạn nghĩ: “Ôi trời, chỉ là ý nghĩ đó đã cản trở bạn… và bạn thôi.” Và ông chủ nhìn bạn như thế, ánh mắt của ông ấy thật hiền lành, thật tốt bụng. Làm sao bạn có thể từ chối anh ấy? Chà, bạn bỏ tất cả mọi thứ và đi cùng một người bạn để mua máy hiện sóng. Họ đã mang nó vào. Chúng tôi đã báo cáo. Và họ lại ngồi xuống chương trình của mình. Đây gần như là cơ chế ngắt trông như thế nào. Khá đơn giản, nhưng có một số điểm cơ bản. Thứ hai: Tất cả điều này rất giống với những gì xảy ra trong một bộ vi điều khiển. Bộ vi điều khiển AVR bao gồm một loạt các thiết bị ngoại vi (bộ định thời/bộ đếm, bộ chuyển đổi tương tự sang số, bộ so sánh tương tự, bộ thu phát không đồng bộ, v.v.). Sức mạnh của bộ vi điều khiển là tất cả các thiết bị này có thể hoạt động song song và độc lập với nhau cũng như song song với chương trình đang được thực thi. Mỗi thiết bị ngoại vi có thể kích hoạt ngắt khi một sự kiện cụ thể xảy ra. Sự gián đoạn sẽ chỉ xảy ra nếu nó được kích hoạt. Kích hoạt ngắt được đặt riêng cho từng thiết bị. Ngoài ra, còn có cờ bật/tắt toàn cục cho tất cả các ngắt - đây là cờ I trong thanh ghi SREG. Khi xảy ra ngắt, bộ vi điều khiển sẽ lưu trữ nội dung của bộ đếm chương trình PC trên ngăn xếp, nghĩa là nó ghi nhớ vị trí mà nó bị gián đoạn. Nạp địa chỉ của vectơ ngắt tương ứng vào bộ đếm chương trình và nhảy tới địa chỉ đó. Nó chạm vào một lệnh nhảy vô điều kiện, đi tới chương trình con xử lý ngắt. Vô hiệu hóa các ngắt bằng cách đặt lại cờ I, thực thi chương trình con. Sau khi thực hiện quy trình xử lý ngắt, bộ vi điều khiển cho phép ngắt bằng cách đặt cờ I và khôi phục nội dung của bộ đếm chương trình, nghĩa là nó quay trở lại vị trí cũ trong chương trình mà nó bị gián đoạn. Về lý thuyết, bộ xử lý ngắt không được làm hỏng nội dung của các thanh ghi vi điều khiển vì chúng có thể chứa dữ liệu từ chương trình đang được thực thi tại thời điểm đó. Để thực hiện điều này, khi bắt đầu chương trình con xử lý ngắt, nội dung của các thanh ghi vi điều khiển được lưu trữ trên ngăn xếp và khi kết thúc chương trình con, chúng sẽ được khôi phục. Do đó, sau khi thoát khỏi ngắt, bộ vi điều khiển sẽ có thể tiếp tục thực hiện chương trình như không có chuyện gì xảy ra. Khi lập trình trong trình biên dịch mã, người lập trình tự quy định việc lưu thanh ghi trong C, việc này được thực hiện bởi trình biên dịch. Bây giờ hãy nói về bộ đếm thời gian. ATmega8535 có ba bộ định thời/bộ đếm trên bo mạch - hai bộ đếm 8 bit (T0, T2) và một bộ đếm 16 bit (T1). Chúng ta sẽ sử dụng bộ định thời/bộ đếm 8 bit T0. Bộ định thời này bao gồm ba thanh ghi - thanh ghi điều khiển TCCR0, thanh ghi đếm TCNT0 và thanh ghi so sánh OCR0. Khi bộ định thời được khởi động, thanh ghi bộ đếm TCNT0 sẽ tăng giá trị của nó lên một cho mỗi cạnh đồng hồ. Tần số xung nhịp được chọn từ một số giá trị có thể có trong thanh ghi điều khiển TCCR0. Ngoài ra, bằng cách sử dụng thanh ghi này, chế độ hoạt động của bộ hẹn giờ được thiết lập. Bộ định thời T0 có thể kích hoạt ngắt khi xảy ra sự kiện “tràn” - đây là khi thanh ghi đếm TCNT0 bị tràn và khi xảy ra sự kiện “trùng hợp” - đây là khi giá trị của thanh ghi đếm TCNT0 trở thành giá trị của thanh ghi so sánh OCR0. Các cờ cho phép các ngắt này được đặt trong thanh ghi TIMSK. Bây giờ về chương trình. Viết chương trình từng dòng một không được nữa nên tôi sẽ đưa nội dung của nó ngay. Dưới đây chúng tôi sẽ phân tích từng dòng một và mọi thứ sẽ trở nên rõ ràng. Tôi đã cố tình không sử dụng macro; chương trình này nhỏ và tôi không muốn làm nó lộn xộn. int chủ yếu( trống rỗng
) //thiết lập bộ đếm thời gian T0 //đợi kết thúc quá trình truyền byte trước đó // vòng lặp chương trình chính – thăm dò nút //trình xử lý ngắt cho bộ định thời T0 Cài đặt cổng Trong mạch của chúng tôi, một nút và loa Piezo được kết nối với cổng D. Chân mà nút được kết nối phải được cấu hình làm đầu vào và phải bật điện trở kéo lên. Chân mà loa Piezo được kết nối phải được đặt thành đầu ra. DDRD = (0< Đặt hẹn giờ Chế độ hoạt động của bộ định thời T0 là CTC (reset ngẫu nhiên), tín hiệu đồng hồ là clk/8. Chúng tôi phản ánh điều này trong sổ đăng ký TCCR0 TCCR0 = (1< Để đề phòng, chúng ta reset lại thanh ghi đếm TCNT0 Viết 0xc8 vào thanh ghi so sánh OCR0. Tại sao? Bởi vì tôi đã tính nó vào máy tính. Vâng, trên giấy tờ, phép tính này trông như thế này. Để biết mô tả chi tiết về bộ định thời T0, hãy xem tài liệu về ATMega8535. Chúng tôi đã định cấu hình bộ hẹn giờ và kích hoạt ngắt chung bằng chức năng tích hợp sẵn. __enable_interrupt();
Nút thăm dò ý kiến Khi không nhấn nút, đầu ra của bộ vi điều khiển được kết nối với nguồn điện thông qua một điện trở kéo lên bên trong, nghĩa là có một điện trở ở đầu ra; khi nhấn nút, đầu ra được nối đất, nghĩa là ở đó; là số 0 ở đầu ra. Để xác định xem nút có được nhấn hay không, bạn cần đọc nội dung của thanh ghi PIND và kiểm tra giá trị của bit 0 (nút được kết nối với PD0). Chúng tôi sẽ thăm dò nút trong một vòng lặp vô tận. trong khi
(1) Đừng quên == không phải là toán tử gán =. Xử lý thao tác nhấn/nhả nút Bằng cách nhấn nút, chúng tôi sẽ kích hoạt tính năng gián đoạn của bộ hẹn giờ T0 và bằng cách nhả nút này, chúng tôi sẽ vô hiệu hóa nó. Để làm điều này, chúng ta sẽ thao tác với bit OCIE0 của thanh ghi TIMSK TIMSK = (1< TIMSK = 0; // vô hiệu hóa gián đoạn Vì chúng ta chỉ sử dụng một bộ đếm thời gian nên không cần thiết lập hoặc đặt lại các bit riêng lẻ. Hàm ngắt được chỉ định bằng cách sử dụng lệnh #pragma vector= và một từ hàm __ngắt. Hàm phải thuộc loại void và không được nhận bất kỳ tham số nào. #pragma vector = Địa chỉ Tên– tên hàm chúng ta tự chọn Đối với nhiệm vụ của chúng tôi, hàm xử lý ngắt trông như thế này #vectơ thực dụng = TIMER0_COMP_vect Vâng, đó là tất cả. Tôi hy vọng mọi thứ đều rõ ràng. Kích hoạt các ngắt bên ngoài trong avr atmega
Ví dụ về sử dụng các ngắt ngoài trong AVR atmega
#bao gồm
Hầu như tất cả các bộ vi điều khiển AVR đều có ngăn xếp trong SRAM. Để đánh địa chỉ phần tử hiện tại (trên cùng của ngăn xếp), con trỏ ngăn xếp SP (Con trỏ ngăn xếp) được sử dụng. Đây là RVV SPL một byte dành cho các kiểu máy có dung lượng bộ nhớ dữ liệu lên tới 256 byte hoặc SPH:SPL hai byte (SPH - byte cao, SPL - byte thấp).
bật R16; khôi phục R16 0x045F? ? ?Ngắt được chia thành bên trong và bên ngoài. Các nguồn ngắt bên trong bao gồm các mô-đun vi điều khiển tích hợp (bộ hẹn giờ, bộ thu phát USART, v.v.). Ngắt bên ngoài xảy ra khi tín hiệu bên ngoài đến các chân của bộ vi điều khiển (ví dụ: tín hiệu ở chân RESET và INT). Bản chất của các tín hiệu dẫn đến xảy ra ngắt được đặt trong thanh ghi điều khiển
, đặc biệt là ở các bit - ISC00 (bit 0) và ISC01 (bit 1) cho đầu vào INT 0; ISC10 (bit2) và ISC11 (bit3) cho đầu vào INT1.
Trong bộ vi điều khiển ATmega8, mỗi ngắt có một ngắt riêng
vectơ ngắt
(địa chỉ ở đầu vùng bộ nhớ chương trình trong đó lệnh nhảy tới chương trình ngắt đã chỉ định được lưu trữ). Trong mega8, tất cả các ngắt đều có cùng mức độ ưu tiên. Nếu có nhiều ngắt xảy ra đồng thời thì ngắt có số vectơ thấp hơn sẽ được xử lý trước.
Các vectơ ngắt trong Atmega8
Địa chỉ
INT0
Nguồn ngắt
Sự miêu tả
INT1
0x0000
CÀI LẠI
Đặt lại tín hiệu
Chụp hẹn giờ T/C1
0x0004
Đặt lại tín hiệu
So sánh bộ định thời T/C1 So sánh thanh ghi A
0x0005
Đặt lại tín hiệu
Khớp với thanh ghi so sánh B của bộ định thời T/C1
0x0006
Đặt lại tín hiệu
Tràn bộ đếm T/C1
0x0007
T/C0
Tràn bộ đếm T/C0
0x0008
SPI
Quá trình truyền dữ liệu SPI đã hoàn tất
0x0009
UART
Bộ thu phát UART đã hoàn tất việc nhận dữ liệu.
0x000A
UART
Thanh ghi dữ liệu UART trống
0x000B
UART
Việc truyền dữ liệu bằng bộ thu phát UART đã hoàn tất
0x000C
ANA_COMP
Ngắt từ bộ so sánh tương tự
Quản lý ngắt
7
6
5
4
3
2
1
0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-
7
6
5
4
3
2
1
0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-
{
PORTB.0=1;
DDRB.0=1;
}
{
đènON();
}
PORTD.2=1;
EXT_INT1 3
TIM2_COMP 4
TIM2_OVF 5
TIM1_CAPT 6
TIM1_COMPA 7
TIM1_COMPB 8
TIM1_OVF 9
TIM0_OVF 10
SPI_STC 11
USART_RXC 12
USART_DRE 13
USART_TXC 14
ADC_INT 15
EE_RDY 16
ANA_COMP 17
TWI 18
SPM_READY 19
Sơ đồ cho ví dụ của chúng tôi. Các tập tin dự án.
Đặt cài đặt dự án cho cấu hình Phát hành:
Tùy chọn chung > Mục tiêu > Cấu hình bộ xử lý
Tôi có ATmega8535 này.
Trong Tùy chọn chung > Hệ thống, chọn hộp Bật định nghĩa bit trong tệp I/O-Bao gồm
Cho đến nay chúng ta chưa sử dụng tên bit nhưng hôm nay chúng ta sẽ cần đến chúng.
Trình liên kết > Đầu ra.
Trong trường Tệp đầu ra, chọn hộp Ghi đè mặc định và thay thế phần mở rộng d90 bằng hex
Trong trường Định dạng, chọn Khác và trong menu thả xuống Định dạng đầu ra, chọn loại tệp intel-standart______________________________ Ngắt ___________________________
Trước hết:
- bạn đã làm xong việc của mình
- cùng lúc đó, có người đang mua máy hiện sóng
- khi xảy ra sự kiện "đã mua máy hiện sóng" - bạn sẽ gián đoạn công việc của mình
- trong một thời gian bạn đang làm công việc khác - mang theo máy hiện sóng
- sau đó bạn quay lại nơi làm việc và tiếp tục làm công việc của mình từ nơi bạn đã dừng lại
- bạn có thể dễ dàng gửi sếp của mình và không đi đâu cả
- sau khi rời khỏi máy hiện sóng, bạn có thể ở đó một thời gian dài hoặc thậm chí không quay lại
- khi bạn trở lại nơi làm việc, bạn có thể đã quên mất những ý tưởng tuyệt vời của mình_______________________________________________________________
Chúng tôi sẽ định cấu hình bộ định thời/bộ đếm T0 để kích hoạt ngắt sự kiện “khớp” ở tần số 5 kHz. Trong hàm xử lý, chúng ta sẽ đảo ngược trạng thái của đầu ra vi điều khiển mà loa áp điện được kết nối. Do đó, tần số âm thanh áp điện sẽ bằng 2,5 kHz. (Đó là loa áp điện được kết nối! Đừng nhầm lẫn. Điện trở của loa áp điện phụ thuộc vào tần số và ở 2,5 KHz thường là đơn vị của Com nên có thể kết nối trực tiếp với đầu ra của vi điều khiển mà không cần điện trở giới hạn) .
{
//thiết lập cổng I/O
DDRD = (0<
TCCR0 = (1<
OCR0 = 0xc8;
__enable_interrupt();
trong khi(1){
nếu như((PIND & (1<
TIMSK = 0;
}
trở lại
0;
}
__ngắt trống rỗng
Hẹn giờ0CompVect( trống rỗng)
{
CỔNG ^= (1<
Tần số xung nhịp của vi điều khiển 8 MHz
Tín hiệu đồng hồ hẹn giờ là 8000000 Hz/8 = 1000000 Hz.
Thời gian của một đồng hồ hẹn giờ 1/1000000 = 1 µs
Thời gian của một chu kỳ tần số chúng ta cần là 1/5000 Hz = 200 μs
Có bao nhiêu tích tắc hẹn giờ phù hợp với 200 µs? 200/1 = 200 tích tắc
200 ở dạng thập lục phân = 0xc8
{
nếu như((PIND & (1<
}
khác
{
//nếu không thì im lặng như cá
}
}
Chức năng ngắt_____________________ Cú pháp hàm ngắt _____________________
__ngắt
trống rỗng Tên( trống rỗng)
{
// mã của chúng tôi nằm ở đây
}
Địa chỉ– địa chỉ vectơ ngắt, có thể được chỉ định theo số hoặc theo tên được xác định trong tệp tiêu đề vi điều khiển (iom8535.h – phần Định nghĩa vectơ ngắt)______________________________________________________________
__ngắt trống rỗng
Hẹn giờ0CompVect( trống rỗng)
{
CỔNG ^= (1<
}
Trong bài viết tiếp theo, chúng tôi sẽ làm cho bộ vi điều khiển phát một giai điệu.
Lập báo cáo “Doanh thu của thợ thủ công”
Bạn có cần một lớp màng bảo vệ cho máy tính bảng của mình không?
thuộc tính chkdsk. CHKDSK - nó là gì? Tiện ích CHKDSK. CHKDSK - cách chạy
Tại sao Vodafone lại theo bước MTS và giới thiệu khu vực hóa?
Bitdefender Antivirus: Trình bảo vệ hiệu quả mà không cần thắc mắc