天天看點

AVR開發 Arduino方法(二) 中斷子系統

  在了解中斷子系統之前,首先要了解中斷的概念。你正在看書,這時電話響了,你會怎麼做呢?相信大多數人會這樣:先标記看到的位置,接完電話回來後繼續閱讀。這就是一個現實生活中中斷的例子,我們把“電話響了”成為中斷源。Arduino UNO R3的主處理器ATMega328P擁有26個中斷源,如下表所示:

向量号 程式位址 中斷源 中斷定義 中斷服務程式名稱
1 0x0000 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 }