在瞭解中斷子系統以前,首先要了解中斷的概念。你正在看書,這時電話響了,你會怎麼作呢?相信大多數人會這樣:先標記看到的位置,接完電話回來後繼續閱讀。這就是一個現實生活中中斷的例子,咱們把「電話響了」成爲中斷源。Arduino UNO R3的主處理器ATMega328P擁有26箇中斷源,以下表所示:git
向量號編程 |
程序地址函數 |
中斷源oop |
中判定義ui |
中斷服務程序名稱spa |
1code |
0x0000blog |
RESET接口 |
外部電平復位,上電覆位,掉電檢測復位,看門狗復位事件 |
|
2 |
0x0002 |
INT0 |
外部中斷請求0 |
INT0_vect |
3 |
0x0004 |
INT1 |
外部中斷請求1 |
INT1_vect |
4 |
0x0006 |
PCINT0 |
引腳電平變化中斷請求0 |
PCINT0_vect |
5 |
0x0008 |
PCINT1 |
引腳電平變化中斷請求1 |
PCINT1_vect |
6 |
0x000A |
PCINT2 |
引腳電平變化中斷請求2 |
PCINT2_vect |
7 |
0x000C |
WDT |
看門狗溢出中斷 |
WDT_vect |
8 |
0x000E |
TIMER2 COMPA |
定時/計數器2比較匹配A |
TIMER2_COMPA_vect |
9 |
0x0010 |
TIMER2 COMPB |
定時/計數器2比較匹配B |
TIMER2_COMPB_vect |
10 |
0x0012 |
TIMER2 OVF |
定時/計數器2溢出 |
TIMER2_OVF_vect |
11 |
0x0014 |
TIMER1 CAPT |
定時/計數器1事件捕捉 |
TIMER1_CAPT_vect |
12 |
0x0016 |
TIMER1 COMPA |
定時/計數器1比較匹配A |
TIMER1_COMPA_vect |
13 |
0x0018 |
TIMER1 COMPB |
定時/計數器1比較匹配B |
TIMER1_COMPB_vect |
14 |
0x001A |
TIMER1 OVF |
定時/計數器1溢出 |
TIMER1_OVF_vect |
15 |
0x001C |
TIMER0 COMPA |
定時/計數器0比較匹配A |
TIMER0_COMPA_vect |
16 |
0x001E |
TIMER0 COMPB |
定時/計數器0比較匹配B |
TIMER0_COMPB_vect |
17 |
0x0020 |
TIMER0 OVF |
定時/計數器0溢出 |
TIMER0_OVF_vect |
18 |
0x0022 |
SPI STC |
SPI串行傳輸結束 |
SPI_STC_vect |
19 |
0x0024 |
USART RX |
USART接收結束 |
USART_RX_vect |
20 |
0x0026 |
USART UDRE |
USART數據寄存器空 |
USART_UDRE_vect |
21 |
0x0028 |
USART TX |
USART,發送結束 |
USART_TX_vect |
22 |
0x002A |
ADC |
模數轉換結束 |
ADC_vect |
23 |
0x002C |
EE READY |
EEPROM準備好 |
EE_READY_vect |
24 |
0x002E |
ANALOG COMP |
模擬比較器 |
ANALOG_COMP_vect |
25 |
0x0030 |
TWI |
兩線串行接口 |
TWI_vect |
26 |
0x0032 |
SPM READY |
保存程序存儲器內容就緒 |
SPM_ready_vect |
這裏之外部中斷0爲例瞭解對中斷子系統的編程,沿用上一章中用於數字輸入示例的電路,這個示例使得按鍵在按下時LED的狀態取反:
1 // Interrupt.ino 2 const byte ledPin = 13; 3 const byte interruptPin = 2; 4 volatile byte state = LOW; 5 6 void setup() { 7 pinMode(ledPin, OUTPUT); 8 pinMode(interruptPin, INPUT_PULLUP); 9 attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE); 10 } 11 12 void loop() { 13 digitalWrite(ledPin, state); 14 } 15 16 void blink() { 17 state = !state; 18 }
與外部中斷相關的Arduino庫函數有:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode):啓用指定引腳的外部中斷並鏈接到指定中斷服務程序
pin:指定外部中斷的引腳
ISR:指定中斷服務程序的名稱
mode:LOW(低電平觸發中斷),CHANG(邏輯電平變化觸發中斷),RISING(上升沿觸發中斷)或FALLING(降低沿觸發中斷)
detachInterrupt(digitalPinToInterrupt(pin)):禁用指定中斷
pin:指定取消外部中斷的引腳
interrupts():開啓總中斷
noInterrupts():禁用總中斷
ATMega328P的外部中斷由2個相關寄存器控制,外部中斷控制寄存器EICRA的結構以下圖所示:
|
|
|
INT1 |
INT0 |
||
|
|
|
ISC11 |
ISC10 |
ISC01 |
ISC00 |
ISCx[1:0](x = 0, 1)位用於設置外部中斷的觸發方式,以下表所示:
ISCx[1:0] (x = 0, 1) |
外部中斷觸發方式 |
00 |
低電平 |
01 |
邏輯電平變化 |
10 |
降低沿 |
11 |
上升沿 |
外部中斷屏蔽寄存器EIMSK用於設置是否屏蔽外部中斷,它的結構以下圖所示:
|
|
|
|
|
INT1 |
INT0 |
若向其中某位寫入1,則該位控制的外部中斷啓用;寫入0則禁用。
經過直接訪問寄存器改寫以上程序爲:
1 // Interrupt_reg.ino 2 volatile byte state = LOW; 3 4 void setup() { 5 DDRB |= (1 << PB5); 6 7 DDRD &= ~(1 << PD2); 8 PORTD |= (1 << PD2); 9 EICRA &= ~(1 << ISC01) & ~(1 << ISC00); 10 EIMSK |= (1 << INT0); 11 sei(); // 啓用總中斷 12 } 13 14 void loop() { 15 if (state == HIGH) { 16 PORTB |= (1 << PB5); 17 } else { 18 PORTB &= ~(1 << PB5); 19 } 20 } 21 22 // 外部中斷0中斷處理函數 23 ISR(INT0_vect) { 24 state = !state; 25 }