想像一下,有一棟剛蓋好的新大樓,而你買了二樓的位置。假設有一個賣消防器材業務員要來推銷他們公司的火災偵測器。為了安全起見,你買了一個並安裝在自己的家中。
這個故事,跟我們的中斷程序有什麼關聯呢?!
你可以把在家中的日常生活,看作是我們Arduino程式裡的Loop()。這個日常生活是一成不變的。有可能你回到家,就會先開電視看一下新聞,然後準備享用晚餐。吃完晚餐,洗完澡後就準備上床睡覺,結束這完美的一天。
假設在這個過程中,不幸地,大樓發生了火災。由於你家裡有裝了火災偵測器,而且它也沒有被觸發,所以你可以知道,火災發生的地方不在你家。
如果今天發生火災是在其它沒有安裝火災偵測器的房子呢?!屋主要怎麼知道究竟家裡是不是有發生火災?!
如果是在沒有安裝偵測器的情況下,該屋主必需在他日常生活內,安排一項"檢查是否失火"的日常工作。例如:回到家,到各個房間檢查是否失火,開電視看新聞...這樣的生活,不是很累嗎?!
如果以上這個情況,你已經能充分了解了,接下來我會說明中斷和這個故事的關聯性。
- 我們知道,家中的日常生活就像是Arduino裡面的Loop()。
- 你買了一個火災偵測器,可以想像成以volatile宣告的變數。Volatile類型的變數,可以被sketch外的動作而改變,中斷就是其中一個例子。
- 將火災偵測器安裝在家中,可以想成將中斷初始化(attachInterrupt)。中斷初始化的格式如下:
attachInterrupt(中斷編號, 呼叫的函數, 中斷模式) - 火災偵測器在偵測到火災時要做的動作(例如:發出警報),就是中斷發生時要呼叫的函式。
- 而火災偵測器是否被觸發,是利用平時監測屋中的狀態是否有所變動(例如:溫度、濃煙...)。這個監測的狀態,代表在中斷裡的四個模式(LOW, CHANGE, RISING, FALLING)。
在上面的這個故事裡,我尚未提了一個中斷編號的概念。不是忘記寫到,而是每個Arduino版本的中斷編號並不一定相同。
中斷編號,你可以想像成火災偵測器的編號。例如1號偵測器你要裝在廚房,2號偵測器你要裝在臥室...。但中斷編號的數量是有限制的。
標準的Arduino會有二個中斷:
- 中斷0 -- Pin 2
- 中斷1 -- Pin 3
Arduino Mega則有六個中斷:
- 中斷0 -- Pin 2
- 中斷1 -- Pin 3
- 中斷2 -- Pin 21
- 中斷3 -- Pin 20
- 中斷4 -- Pin 19
- 中斷5 -- Pin 18
以上的概念如果都懂了,那接下來看官網上的這個程式範例應該就很容易了解了:
/*
中斷有四種模式:
- LOW : Pin在低電位時觸發中斷
- CHANGE : Pin值改變時觸發中斷
- RISING : Pin由LOW變成HIGH時觸發中斷
- 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;
}
/* 程式碼結尾 */
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()本身就是依靠中斷來計時。
沒有留言:
張貼留言