中斷的定義
程序運(yùn)行過程中時(shí)常需要監(jiān)控一些事件的發(fā)生晾腔,如對某一傳感器的檢測結(jié)果做出反應(yīng)灯荧。使用輪詢的方式進(jìn)行檢測時(shí)效率較低列肢,等待時(shí)間較長华蜒,而使用中斷方式進(jìn)行檢測時(shí)則可以達(dá)到實(shí)時(shí)檢測的效果载庭。
當(dāng)中斷被觸發(fā)時(shí)看彼,控制器會(huì)暫停當(dāng)前正在運(yùn)行的主程序,而跳去運(yùn)行中斷程序囚聚,當(dāng)中斷程序運(yùn)行完后靖榕,會(huì)再回到之前主程序暫停的位置,繼續(xù)運(yùn)行主程序顽铸。如此便可以達(dá)到實(shí)時(shí)響應(yīng)處理事件的效果茁计。
外部中斷是由外部設(shè)備發(fā)起請求的中斷。要想使用外部中斷谓松,就需要了解中斷引腳的位置星压,根據(jù)外部設(shè)備選擇中斷模式,以及編寫一個(gè)中斷被觸發(fā)后需要執(zhí)行的中斷函數(shù)鬼譬。
中斷引腳
ARDUINO中的外部中斷通常是由Pin口電平改變觸發(fā)的娜膘。每種型號(hào)的ARDUINO板都有數(shù)個(gè)PIn口可以用來注冊中斷
常見開發(fā)板外部引腳圖:常見開發(fā)板引腳圖
中斷模式
為了設(shè)置中斷模式,還需要了解設(shè)備觸發(fā)外部中斷的輸入 信號(hào)類型优质。中斷模式也就是中斷觸發(fā)的方式劲绪。在大多數(shù)ARDUINO上支持以下幾個(gè)中斷觸發(fā)方式
LOW 低電平觸發(fā)
CHANGE 電平變化觸發(fā)
RISING 上升沿觸發(fā),即高電平變低電平
FALLING 下降沿觸發(fā)盆赤,即低電平變高電平
中斷函數(shù)
除了設(shè)置中斷模式外,還需要編寫一個(gè)響應(yīng)中斷的處理程序——中斷函數(shù)歉眷,當(dāng)中斷被觸發(fā)后牺六,便可以讓Arduino運(yùn)行該中斷函數(shù)。中斷函數(shù)就是當(dāng)中斷被觸發(fā)后要去執(zhí)行的函數(shù)汗捡,該函數(shù)不能帶有任何參數(shù)淑际,且返回類型為空
這些準(zhǔn)備工作完成后,還需要在setup()中使用attachInterrrupt()函數(shù)對中斷引腳進(jìn)行初始化配置扇住,以開啟arduino的外部中斷功能春缕,其用法如下:
attachInterrupt(interrupt, function,mode)
功能:對中斷引腳進(jìn)行初始化配置
參數(shù):
interrupt,中斷編號(hào),注意艘蹋,這里的中斷編號(hào)并不是引腳編號(hào)
function锄贼,中斷函數(shù)名,當(dāng)中斷被觸發(fā)后即會(huì)運(yùn)行此函數(shù)所代表的中斷函數(shù)女阀。
mode宅荤,中斷模式
detachInterrupt(interrupt)
功能:禁用外部中斷
參數(shù):
interrrupt,需要禁用的中斷編號(hào)
實(shí)驗(yàn)代碼
#define LED A2
#define KEY 2
volatile byte state;
volatile unsigned long last_time;
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
pinMode(LED, OUTPUT);
pinMode(KEY, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(KEY), keyInterrupt, RISING);
state = LOW;
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(LED, state);
}
void keyInterrupt() {
if ((millis() - last_time) > 500) {
Serial.println("檢測到中斷");
if (state == LOW) {
state = HIGH;
} else {
state = LOW;
}
last_time = millis();
}
}
嘗試自己模擬運(yùn)行下吧:https://wokwi.com/projects/347197223040189011
可能會(huì)遇到的問題
當(dāng)實(shí)際操作的時(shí)候你會(huì)發(fā)現(xiàn)你的中斷函數(shù)被觸發(fā)很多次屑迂,這個(gè)當(dāng)然不是我們想要看到的。這是由于我們按鍵是機(jī)械結(jié)構(gòu)所造成的抖動(dòng)冯键,而需求就是消除這個(gè)抖動(dòng)惹盼。
if ((millis() - last_time) > 500) {
Serial.println("檢測到中斷");
if (state == LOW) {
state = HIGH;
} else {
state = LOW;
}
last_time = millis();
}
此方法是加入時(shí)間函數(shù)利用時(shí)間差進(jìn)行處理抖動(dòng)效果。
當(dāng)然還有另外的一種方案筆者沒有嘗試過惫确,利用在按鈕兩端并聯(lián)一顆電容利用它的特性過濾按鈕的抖動(dòng)手报,感興趣的可以自己測試。
定時(shí)器庫的使用
引入庫: TimerOne
代碼中使用:#include "TimerOne.h"
#include "TimerOne.h"
#define LED 7
volatile byte state = LOW;
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
pinMode(LED, OUTPUT);
digitalWrite(LED, state);
Timer1.initialize( 500000 ); // 初始化, interval 以 micro sec 為單位
Timer1.attachInterrupt( timer_task ); // attach the service routine here
}
void loop() {
digitalWrite(LED, state);
}
void timer_task() {
Serial.println("timer_task 執(zhí)行了");
state = ~state;
}