2011年4月21日 星期四

attachInterrupt() 與外部中斷

實驗目的

練習使用 attachInterrupt() 函式與外部中斷。在這個實驗中,你將利用 attachInterrupt() 函式設定中斷處理函式(Interrupt Service Routine, ISR),讓程式在 pin 2 產生外部中斷時自動執行 ISR。

材料
  • Arduino 主板 x 1
  • LED x 1
  • Pushbutton x 1
  • 10K 歐姆電阻 x 1
  • 麵包板 x 1
  • 單心線 x N
接線
  1. 把 LED 接到 pin13,長腳(陽極)接到 pin13,短腳(陰極)接到 GND
  2. 把 pushbutton 一支腳接到 +5V,另一支腳接到 pin 2 同時接一顆 10K 電阻連到 GND

image

電路圖

image

程式

先來看非中斷版本的程式(button.pde):

這支是 Arduino 的初級程式,我們在「Lab2 - 使用按鍵 (PushButton)控制 LED 燈號」中看過,程式邏輯很簡單,當按鍵被按下時打開 LED 燈號,在按鍵放開時關閉 LED 燈號。

底下的程式(attachInterrupt.pde)則是使用 attachInterrupt() 版與外部中斷的版本,程式作用是一樣的,當按鍵被按下時打開 LED 燈號,在按鍵放開時關閉 LED 燈號:

要特別注意是,程式裏的 buttonState 變數是宣告成 volatile,這樣做的目的是告訴 Compiler 不要做最佳化,避免變數狀態不同步。給你一個建議,程式主體跟 ISR 都會用到的變數,盡可能把它宣告成 volatile。

attachInterrupt() 函式

attachInterrupt() 函式的用途是用來指定外部中斷的處理函式(Interrupt Service Routine, ISR),就像範例程式所示範的指定 buttonStateChanged() 當作 Interrupt 0 外部中斷的處理函式。

attachInterrupt() 函式有三個參數:

  • interrupt: 外部中斷的編號。大部份 Arduino 板子都有兩個外部中斷,編號 0 (Interrupt 0)是在 pin 2 上,而編號 1 (Interrupt 1)是在 pin 3 上。
  • function: 中斷處理函式(Interrupt Service Routine, ISR)。中斷處理函式必須是不接受參數而且不回傳任何東西。
  • mode: 定義什麼狀況下該觸發中斷,有四個可以設定的常數值:
    • LOW: 當 pin 為 LOW 時觸發中斷
    • CHANGE: 當 pin 狀態改變時觸發中斷,不管是從 HIGH 到 LOW 或從 LOW 到 HIGH
    • RISING: 當 pin 狀態從 LOW 到 HIGH 時觸發中斷,RISING 又稱正緣觸發
    • FALLING: 當 pin 狀態從 HIGH 到 LOW 時觸發中斷,FALLING 又稱負緣觸發

如果要移除外部中斷服務函式,就使用 detachInterrupt() 函式。

啟用與停止中斷

如果要停止 Arduino 所有中斷,可以呼叫 noInterrupt() 函式,要重新啟用中斷,只要呼叫一次 interrupts() 函式即可。

延伸閱讀

5 意見:

華特 提到...
作者已經移除這則留言。
Sven Wang 提到...

哈囉Cooper~~
我希望在中斷發生後能夠閃爍LED燈三次
所以把interrupt 0 中斷處裡函式改寫為下

但執行的時候卻不會閃三次,反倒有點不受控
請問Cooper是哪邊發生問題呢?

我有查詢一下似乎是中斷內不能加delay()??
那該如何解決呢??

void buttonStateChanged() {
for(int i=0;i<3:i++)
{
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
}

Cooper Maa 提到...

對,ISR 通常都只是做很簡單的事,不可以花太多時間

你應該在 ISR 裏設一個旗號,然後在 Loop() 裏不斷檢查旗號決定要不要讓 LED 閃爍

嗯..讓我想一想 提到...

FALLING: 當 pin 狀態從 LOW 到 HIGH 時觸發中斷,FALLING 又稱負緣觸發
這邊是不是沒改道@@?

Cooper Maa 提到...

真的,這篇沒改到
哇,你是我的忠實讀者?