日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Arduino成长日记6 - 中断机制

發(fā)布時(shí)間:2024/3/12 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Arduino成长日记6 - 中断机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

中斷是在程序運(yùn)行中經(jīng)常用到的功能,用于處理一下實(shí)時(shí)性比較高的事件,首先來了解一下中斷的概念。

中斷

當(dāng)出現(xiàn)需要及時(shí)處理的事件(中斷請(qǐng)求)時(shí),CPU暫停當(dāng)前工作的執(zhí)行轉(zhuǎn)而處理應(yīng)急事件(中斷)的過程。即在程序運(yùn)行過程中,系統(tǒng)出現(xiàn)了一個(gè)必須由CPU立即處理的情況,此時(shí),CPU暫停當(dāng)前程序去處理這個(gè)新事件的過程就就是中斷。
舉個(gè)栗子:你正在看著一本Arduino程序設(shè)計(jì)的書,看到95頁時(shí)肚子餓了,你記下來頁碼跑去吃東西,吃完東西后繼續(xù)從書的95頁往下看;這里面看書就類似CPU在正常工作,肚子餓了吃東西就像處理中斷,中斷事件處理(吃東西)結(jié)束后(CPU)又從停下來的地方繼續(xù)運(yùn)行(看書)。


Arduino外部中斷

外部中斷是單片機(jī)實(shí)時(shí)地處理外部事件的一種內(nèi)部機(jī)制。當(dāng)某種外部事件發(fā)生時(shí),單片機(jī)的中斷系統(tǒng)將迫使CPU暫停正在執(zhí)行的程序,轉(zhuǎn)而去進(jìn)行中斷事件的處理;中斷處理完畢后.又返回被中斷的程序處,繼續(xù)執(zhí)行下去。
大多數(shù)的Arduino板至少擁有兩個(gè)外部中斷引腳:0號(hào)中斷(引腳2)和1號(hào)中斷(引腳3)。不同的Arduino控制板的中斷引腳還有所區(qū)別,如下表所示。

Arduino控制板int0int1int2int3int4int5
Uno,Ethernet23XXXX
Mega2321201918
Leonardo3201XX
DueIO

表中int表示Arduino板的中斷號(hào)對(duì)應(yīng)的引腳,X 則表示該板沒有對(duì)應(yīng)的中斷引腳, 在所有的Arduino控制板中,Arduino Due比較強(qiáng)大的中斷功能,允許在所有IO腳觸發(fā)外部中斷。
Arduino編程中的中斷均已函數(shù)調(diào)用的形式來配置及使用,相對(duì)來說比較簡單,下面是外部中斷的常用函數(shù)。

1、中斷函數(shù)
attachInterrupt(interrupt,function,mode)

描述:當(dāng)發(fā)生外部中斷時(shí),調(diào)用一個(gè)指定的函數(shù)。在程序中再次調(diào)用時(shí)可以指定新的中斷調(diào)用函數(shù);如在setup函數(shù)中初始化函數(shù)A為中斷0的中斷調(diào)用函數(shù),再次調(diào)用 attachInterrupt 函數(shù)時(shí),可以指定函數(shù)B為中斷0的中斷調(diào)用函數(shù),在程序中有需要可多次調(diào)用更新中斷函數(shù)。
語法:attachInterrupt(interrupt,function,mode)
attachInterrupt(pin,function,mode)(Due專用)
參數(shù):
interrupt,中斷編號(hào);pin,引腳編號(hào)(Due專用);
function:中斷發(fā)生時(shí)調(diào)用的函數(shù),此函數(shù)必須不帶任何參數(shù),不返回任何值。
mode:定義什么情況下觸發(fā)中斷,以下四個(gè)常數(shù)為mode的有效值:

  • LOW: 當(dāng)引腳為低電平時(shí),觸發(fā)中斷;
  • CHANGE:當(dāng)引腳電平發(fā)生變化時(shí),觸發(fā)中斷;
  • RISING:當(dāng)引腳電平由低變高時(shí),觸發(fā)中斷(上升沿中斷);
  • FALLING:當(dāng)引腳電平由高變低時(shí),觸發(fā)中斷(下降沿中斷);
    對(duì)于Due而言,多了一個(gè)專用參數(shù) – HIGH,即當(dāng)引腳為高電平時(shí),觸發(fā)中斷;

注意:不要妄想在中斷函數(shù)中加延時(shí),在Arduino中斷函數(shù)中,delay()不會(huì)生效,millis()不會(huì)持續(xù)累加;當(dāng)中斷發(fā)生時(shí),串口數(shù)據(jù)可能會(huì)出現(xiàn)丟包;在中斷函數(shù)里面使用到的全局變量應(yīng)該聲明為volatile變量。

示例:

const byte ledPin = 13; const byte interruptpin = 2; volatile byte state = LOW;void setup(void) {pinMode(ledPin,OUTPUT);pinMode(interruptPin,INPUT_PULLUP);attachInterrupt(digitalPinToInterrupt(interruptPin),blink,CHANGE); }void loop() {digitalWrite(ledPin,state); }void blink() {state = !state; }
detachInterrupt(interrupt)

描述:關(guān)閉對(duì)應(yīng)的中斷。
參數(shù):interrupt,禁用中斷的編號(hào)(0或1)。

2、中斷使能函數(shù)
interrupts()

描述:啟用中斷/重新啟用中斷(在被禁用中斷過后)。

noInterrupts()

描述:禁用中斷。在程序中如果有一些函數(shù)的運(yùn)行不希望被中斷打斷,可以調(diào)用noInterrupts函數(shù)來禁用中斷的發(fā)生,再配合interrupts函數(shù)恢復(fù)中斷使能。
示例:

void setup(){ }void loop(){...noInterrupts();//放置關(guān)鍵函數(shù)(不想被打斷)interrupts();//放置其他函數(shù)... }
Arduino定時(shí)器中斷

外部中斷是通過檢測(cè)輸入電平的變化,而產(chǎn)生中斷信號(hào)。除了外部中斷方式外,Arduino控制板還可以按時(shí)間變化產(chǎn)生中斷,這里使用到定時(shí)器(Timer),而對(duì)應(yīng)產(chǎn)生的中斷被稱為定時(shí)器中斷。
定時(shí)器是嵌入式系統(tǒng)中的一個(gè)特殊的計(jì)數(shù)器。它可以對(duì)分頻后時(shí)鐘信號(hào)的進(jìn)行計(jì)數(shù),當(dāng)計(jì)數(shù)值達(dá)到設(shè)定值,即會(huì)產(chǎn)生定時(shí)器中斷。且通過時(shí)鐘頻率和計(jì)數(shù)值可以計(jì)算出時(shí)間,所以可以達(dá)到以時(shí)間觸發(fā)中斷的效果。
即當(dāng)需要按一定的時(shí)間間隔執(zhí)行某個(gè)操作時(shí),就需要用到定時(shí)器中斷了。

以UNO為例,一共有3個(gè)定時(shí)器可以使用:Timer0,Timer1,Timer2。
每個(gè)定時(shí)器都有自己的函數(shù)庫,通過使用硬件內(nèi)部計(jì)時(shí)器中斷來實(shí)現(xiàn)中斷效果,下面以Timer1庫的程序?yàn)槔f明~
首先需要安裝TimeOne庫,也就是Timer1的對(duì)應(yīng)庫。下面提供兩種安裝方式,可以點(diǎn)擊鏈接跳到對(duì)應(yīng)的安裝教程:
第一種:Arduino IDE安裝TimerOne庫
第二種:Sublime Text3環(huán)境安裝TimerOne庫
安裝完成后,大概了解一下Timer1的庫函數(shù),打開.h文件TimerOne.h,除了包含 Arduino.h 外,還有一個(gè)宏定義聲明了Timer1是一個(gè)16位定時(shí)器。

#define TIMER1_RESOLUTION 65536UL // Timer1 is 16 bit

隨后在TimerOne類中定義了定時(shí)器相關(guān)函數(shù),在配置函數(shù)中包含了初始化函數(shù)initialize()函數(shù),參數(shù)默認(rèn)為1000000毫秒,也就是1秒;setPeriod()函數(shù)較長就不發(fā)出來了,主要作用是設(shè)置定時(shí)器的觸發(fā)周期,在initialize()函數(shù)中調(diào)用。

//****************************// Configuration//****************************void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {TCCR1B = _BV(WGM13); // set mode as phase and frequency correct pwm, stop the timerTCCR1A = 0; // clear control register A setPeriod(microseconds);}void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {...}

定時(shí)器狀態(tài)控制函數(shù)

//****************************// Run Control//****************************void start() __attribute__((always_inline)) {TCCR1B = 0;TCNT1 = 0; // TODO: does this cause an undesired interrupt?resume();}void stop() __attribute__((always_inline)) {TCCR1B = _BV(WGM13);}void restart() __attribute__((always_inline)) {start();}void resume() __attribute__((always_inline)) {TCCR1B = _BV(WGM13) | clockSelectBits;}

PWM控制相關(guān)函數(shù)(函數(shù)體省略)

//****************************// PWM outputs//****************************void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {...}void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {...}void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {...}void disablePwm(char pin) __attribute__((always_inline)) {...}

最重要的來了,定時(shí)器中斷相關(guān)函數(shù)

//****************************// Interrupt Function//****************************void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {isrCallback = isr;TIMSK1 = _BV(TOIE1);}void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {if(microseconds > 0) setPeriod(microseconds);attachInterrupt(isr);}void detachInterrupt() __attribute__((always_inline)) {TIMSK1 = 0;}

大概了解過定時(shí)器相關(guān)函數(shù)后,可以開始編寫定時(shí)器中斷程序了。
1、添加TimerOne頭文件(安裝庫之后);
2、初始化定時(shí)器,開啟定時(shí)器中斷;
3、編寫定時(shí)器中斷操作;
簡單程序如下

#include "TimerOne.h"//定時(shí)器中斷函數(shù) void Timer1Interrupt() {digitalWrite(13,digitalRead(13)^1); //控制LED閃爍 }void setup() {pinMode(13,OUTPUT); //設(shè)置LED引腳為輸出Timer1.initialize(500000); //Timer1每500毫秒觸發(fā)一次Timer1.attachInterrupt(Timer1Interrupt); //配置定時(shí)器中斷函數(shù),開啟中斷 }void loop(){}

使用定時(shí)器中斷可以很好的解決Arduino的單任務(wù)機(jī)制,但是UNO的3個(gè)定時(shí)器資源同樣跟引腳PWM會(huì)有沖突,比如Timer0定時(shí)器負(fù)責(zé) millis()函數(shù) 和 delay()函數(shù) 的計(jì)時(shí)工作,同時(shí)控制著數(shù)字引腳 pin5,pin6 的PWM功能;Timer1定時(shí)器負(fù)責(zé)數(shù)字引腳 pin9、pin10 的PWM功能,也影響 Servo.h庫 的使用;Timer2定時(shí)器負(fù)責(zé)數(shù)字引腳 pin11,pin3 的PWM功能,也和蜂鳴器的 tone()函數(shù)有關(guān)。

綜上所述,定時(shí)器的使用會(huì)影響對(duì)應(yīng)引腳的PWM功能,和某些時(shí)序函數(shù)的運(yùn)行,比如Timer0負(fù)責(zé)delay()函數(shù)延時(shí)操作的,使用pin5、pin6的PWM輸出可能會(huì)有些微誤差,像analogWrite(5,0)和analogWrite(5,6)可能是一樣的效果

除了對(duì)應(yīng)的硬件定時(shí)器,還可以用Timer庫和SimpleTimer庫來實(shí)現(xiàn)定時(shí)效果,這兩個(gè)庫不用到硬件定時(shí)器,也是用到 millis()函數(shù) 來實(shí)現(xiàn)延時(shí),所以對(duì) delay函數(shù) 也是會(huì)有點(diǎn)影響。


串口中斷(沒這回事兒)

關(guān)于Arduino串口中斷的也是找了一段時(shí)間沒結(jié)果,后來發(fā)現(xiàn)了Arduino沒有串口中斷這回事,但是卻機(jī)緣巧合的在main函數(shù)中找到了串口的端倪。
以下是Arduino中main函數(shù)的內(nèi)容~

int main(void) {init();initVariant(); #if defined(USBCON)USBDevice.attach(); #endifsetup(); for (;;) {loop();if (serialEventRun) serialEventRun();} return 0; }

即是Arduino沒有串口中斷,但是卻用for循環(huán)來檢測(cè)串口事件,與loop函數(shù)在同個(gè)循環(huán)中,相當(dāng)于loop函數(shù)運(yùn)行一次順帶檢測(cè)一次串口事件。

總結(jié)

以上是生活随笔為你收集整理的Arduino成长日记6 - 中断机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。