2011年7月6日 星期三

3) Interrupts

什麼是 Interrupts?
當你在工作的時候,突然電話鈴聲響起,於是你把手邊工作停下來、接電話、講電話,然後回來繼續剛剛工作 -- 這就是所謂的中斷 (Interrupt),而電話便是中斷源。
在微控制器中,中斷的來源有很多,諸如 Reset, 外部中斷, Timer, USART, EEPROM, ADC 等。比如,當 Timer Overflow 時可以引發中斷,當 USART 收到資料或資料傳輸完畢時可以引發中斷…
跟人一樣,在遇到中斷的時候,微控制器的 CPU 也會把手邊的工作停下來,然後跳到預設的位址 (接電話),接著執行一段程式 (講電話),執行完後回來繼續進行剛剛的工作。
在發生中斷的時候,CPU 會老老實實的做這幾個動作:
  1. 執行當前的指令
  2. 把下一個指令的位址 push 到 stack 上,停止程式的正常流程,然後
  3. 跳到預設的位址,這個位址稱為中斷向量表,是由 MCU 製造商預先定義好的。 在中斷向量表中,每個中斷都有一個 entry,就看發生什麼中斷,CPU 就跳到哪個 entry。通常每個 entry 裏只是一條 JMP xxxx 的指令,會讓 CPU 輾轉跳到一段稱為中斷服務函式 (Interrupt Service Routine, ISR) 的副程式。
  4. 接著執行中斷服務函式
  5. 當執行完中斷服務函式後,再從 stack 上 pop 出指令的位址,並從它離開的地方繼續執行程式
電腦比人強的地方,在於它的記憶力好,沒健忘症,當 CPU 處理完中斷後,一定會回去進行原來的工作,除非程式開發者疏忽了把 ISR 寫成跳不出來的無窮迴圈。
Interrupt vectors
底下這張是 ATmega328 的中斷向量表:
image
image
當中斷觸發時,CPU 會跳到預設的位址,例如當 ADC 轉換完成時會引發 ADC 中斷,CPU 這時就會跳到 0x002A 這個位址 (vector 22 所在的位址) 去執行指令。如前面說的,通常中斷向量表的每個 entry 裏只是一條 JMP xxxx 的指令,會讓 CPU 輾轉跳到中斷服務函式 (ISR)。
底下是中斷向量表典型的設定:

以上面的程式為例,當發生 reset 中斷時,MCU 執行的第一條指令是 jmp RESET,因此會跳到 0x0033 的位址,亦即主程式的起始位置。假如是 ADC 中斷,MCU 會先跳到中斷向量表 0x002A 的位址,之後輾轉跳到 ADC 這個中斷服務函式。
Interrupt Service Routine (ISR)
在 Arduino 的程式中,要寫 ISR 是很簡單的一件事。你不需要自己設定中斷向量表,只要會使用 ISR() 這個巨集指令就可以了,例如:

這表示這個是處理 ADC 轉換的中斷服務函式,將來當 ADC 轉換完成時會引發中斷,CPU 就會來執行這個中斷服務函式。
底下這張表列出了 ATmega328 的所有中斷向量:
Vector 說明
INT0_vect External Interrupt Request 0
INT1_vect External Interrupt Request 1
PCINT0_vect Pin Change Interrupt Request 0
PCINT1_vect Pin Change Interrupt Request 1
PCINT2_vect Pin Change Interrupt Request 2
WDT_vect Watchdog Time-out Interrupt
TIMER2_COMPA_vect Timer/Counter2 Compare Match A
TIMER2_COMPB_vect Timer/Counter2 Compare Match B
TIMER2_OVF_vect Timer/Counter2 Overflow
TIMER1_CAPT_vect Timer/Counter1 Capture Event
TIMER1_COMPA_vect Timer/Counter1 Compare Match A
TIMER1_COMPB_vect Timer/Counter1 Compare Match B
TIMER1_OVF_vect Timer/Counter1 Overflow
TIMER0_COMPA_vect TimerCounter0 Compare Match A
TIMER0_COMPB_vect TimerCounter0 Compare Match B
TIMER0_OVF_vect Timer/Couner0 Overflow
SPI_STC_vect SPI Serial Transfer Complete
USART_RX_vect USART Rx Complete
USART_UDRE_vect USART, Data Register Empty
USART_TX_vect USART Tx Complete
ADC_vect ADC Conversion Complete
EE_READY_vect EEPROM Ready
ANALOG_COMP_vect Analog Comparator
TWI_vect Two-wire Serial Interface
SPM_READY_vect Store Program Memory Read
▲ ATmega328 中斷向量表,可在 <avr/iom328p.h> 中找到。
延伸閱讀

6 意見:

Sven Wang 提到...

Cooper好,

非常抱歉...因為短時間閱讀你大量文章
有些文章有印象...但忘記在哪了><

請問我記得有一篇寫到用單張板做到"簡易多工"的效果

請問Cooper您知道是哪一篇有寫到嗎?

我翻遍interupt還有timer都沒找到...

繼續尋找ing~~~

Sven Wang 提到...

補充說明, 我記得那一篇有強調不使用delay....

然後到底是用什麼達到多工...我實在是忘了@@

我超想看那篇文章阿阿阿~~~~~><

coopermaa 提到...

你是說這篇嗎?
不使用延遲的燈號閃爍程式 (Blink without delay)

coopermaa 提到...

這兩篇文章你可能有興趣:

同時執行多個活動與 TimedAction 函式庫簡介

http://yehnan.blogspot.tw/2012/03/arduino.html

Sven Wang 提到...

對對對!!!就是這篇~~~哈哈~~
因為沒有放在首頁的上欄裡面~~
我還在想我是在哪看到的哩~~~~
原來是之前從你網誌翻箱倒櫃找出來的XDDD

coopermaa 提到...

Ask, and it shall be given! haha~