2016年5月12日 星期四

Arduino - 中斷(Interrupt)

中斷(Interrupt)其實是Arduino中,一個很好用的功能。只是當時剛入門,對它很不了解,不知道該如何使用它。接下來我會用一個故事來解釋如何使用中斷這個功能。

想像一下,有一棟剛蓋好的新大樓,而你買了二樓的位置。假設有一個賣消防器材業務員要來推銷他們公司的火災偵測器。為了安全起見,你買了一個並安裝在自己的家中。

這個故事,跟我們的中斷程序有什麼關聯呢?!

你可以把在家中的日常生活,看作是我們Arduino程式裡的Loop()。這個日常生活是一成不變的。有可能你回到家,就會先開電視看一下新聞,然後準備享用晚餐。吃完晚餐,洗完澡後就準備上床睡覺,結束這完美的一天。
假設在這個過程中,不幸地,大樓發生了火災。由於你家裡有裝了火災偵測器,而且它也沒有被觸發,所以你可以知道,火災發生的地方不在你家。

如果今天發生火災是在其它沒有安裝火災偵測器的房子呢?!屋主要怎麼知道究竟家裡是不是有發生火災?!

如果是在沒有安裝偵測器的情況下,該屋主必需在他日常生活內,安排一項"檢查是否失火"的日常工作。例如:回到家,到各個房間檢查是否失火,開電視看新聞...這樣的生活,不是很累嗎?!

如果以上這個情況,你已經能充分了解了,接下來我會說明中斷和這個故事的關聯性。


  1. 我們知道,家中的日常生活就像是Arduino裡面的Loop()
  2. 你買了一個火災偵測器,可以想像成以volatile宣告的變數。Volatile類型的變數,可以被sketch外的動作而改變,中斷就是其中一個例子。
  3. 將火災偵測器安裝在家中,可以想成將中斷初始化(attachInterrupt)。中斷初始化的格式如下:
    attachInterrupt(中斷編號, 呼叫的函數, 中斷模式)
  4. 火災偵測器在偵測到火災時要做的動作(例如:發出警報),就是中斷發生時要呼叫的函式
  5. 而火災偵測器是否被觸發,是利用平時監測屋中的狀態是否有所變動(例如:溫度、濃煙...)。這個監測的狀態,代表在中斷裡的四個模式(LOW, CHANGE, RISING, FALLING)
在上面的這個故事裡,我尚未提了一個中斷編號的概念。不是忘記寫到,而是每個Arduino版本的中斷編號並不一定相同。
中斷編號,你可以想像成火災偵測器的編號。例如1號偵測器你要裝在廚房,2號偵測器你要裝在臥室...。但中斷編號的數量是有限制的

標準的Arduino會有二個中斷:
  1. 中斷0 -- Pin 2
  2. 中斷1 -- Pin 3

Arduino Mega則有六個中斷:
  1. 中斷0 -- Pin 2
  2. 中斷1 -- Pin 3
  3. 中斷2 -- Pin 21
  4. 中斷3 -- Pin 20
  5. 中斷4 -- Pin 19
  6. 中斷5 -- Pin 18

以上的概念如果都懂了,那接下來看官網上的這個程式範例應該就很容易了解了:

/*
     中斷有四種模式:
  1. LOW : Pin在低電位時觸發中斷
  2. CHANGE : Pin值改變時觸發中斷
  3. RISING : Pin由LOW變成HIGH時觸發中斷
  4. FALLING : Pin由HIGH變成LOW時觸發中斷
*/

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
digitalWrite(ledPin, state);
}

void blink() {
state = !state;
}

/*     程式碼結尾     */


PS : 在官網上有提到一點值得注意的地方,在中斷發生時要呼叫的函數裡,不能有參數和傳回值,也不能使用delay()。而如果你在呼叫的函數裡,有使用到millis()這個方法也會無效,因為millis()本身就是依靠中斷來計時。






沒有留言:

張貼留言