劉賢鍇
(1.山東政法學(xué)院 山東省高校證據(jù)鑒識重點實驗室,濟(jì)南 250014;2.山東政法學(xué)院 信息學(xué)院)
* 基金項目:山東省高校證據(jù)鑒識重點實驗室開放課題(信息隱蔽技術(shù)鑒定研究,KFKT-201410)。
?
同一個外部中斷的Arduino隨機(jī)睡眠與喚醒*
劉賢鍇1,2
(1.山東政法學(xué)院 山東省高校證據(jù)鑒識重點實驗室,濟(jì)南 250014;2.山東政法學(xué)院 信息學(xué)院)
* 基金項目:山東省高校證據(jù)鑒識重點實驗室開放課題(信息隱蔽技術(shù)鑒定研究,KFKT-201410)。
摘要:為了控制Arduino的隨機(jī)睡眠與喚醒,不采用“預(yù)定睡眠-隨機(jī)喚醒”的常規(guī)設(shè)計模式,而是通過一個外部中斷隨機(jī)使Arduino進(jìn)入睡眠,并且通過同一個外部中斷隨機(jī)喚醒Arduino。首先使用開源Enerlib和LowPower庫對Arduino Pro Mini進(jìn)行實驗,然后應(yīng)用于實際的工程設(shè)計中,取得了很好的效果。該方法可以作為成熟的方案推廣到工程設(shè)計的實際應(yīng)用當(dāng)中。
關(guān)鍵詞:Arduino;隨機(jī)睡眠;隨機(jī)喚醒;外部中斷
引言
“預(yù)定睡眠-隨機(jī)喚醒”是嵌入式系統(tǒng)設(shè)計中常用的方法。例如,在完成規(guī)定的數(shù)據(jù)發(fā)送或接收任務(wù)后,MCU立即進(jìn)入休眠以節(jié)約電力,這就是“預(yù)定睡眠”的含義;當(dāng)有新的數(shù)據(jù)發(fā)送和接收任務(wù)時,通過各種方式喚醒MCU執(zhí)行前述任務(wù),這就是“隨機(jī)喚醒”的含義。在實際工程中,完成該功能主要使用軟件,首先整合系統(tǒng)功能,執(zhí)行完功能模塊后馬上執(zhí)行預(yù)定的睡眠指令,而喚醒功能則直接在中斷服務(wù)程序中體現(xiàn)。很多教科書、論壇中廣泛介紹的也都是這種方法,該方法能夠滿足一般工程設(shè)計的需要[1]。但“預(yù)定睡眠”在某些工程中并不適合使用,例如在無線傳感網(wǎng)絡(luò)構(gòu)成的系統(tǒng)中,某個節(jié)點或分系統(tǒng)的睡眠時機(jī)不是由自己決定的,而是遠(yuǎn)程隨機(jī)控制的。在這種情況下,睡眠指令在節(jié)點或分系統(tǒng)執(zhí)行自己任務(wù)的過程中隨機(jī)發(fā)生,同樣,喚醒指令發(fā)出也是隨機(jī)的,通常為節(jié)省系統(tǒng)的硬件開支并提高其可靠性,發(fā)出睡眠和喚醒指令使用同一個信號,所以系統(tǒng)軟件的睡眠指令就不能固定在系統(tǒng)功能程序的預(yù)定位置,甚至不能在功能主程序及其調(diào)用的函數(shù)中出現(xiàn)。
1目前Arduino睡眠與喚醒的方法
在Arduino IDE中控制Arduino睡眠的工具主要有Enerlib[2]和LowPower[3]兩種開源類庫,前一種已被Arduino開源庫收錄,這兩種類庫專門完成Arduino的睡眠控制。Arduino的睡眠效果和典型應(yīng)用在參考文獻(xiàn)[4]中有詳細(xì)的介紹,但也未涉及到隨機(jī)進(jìn)入睡眠的方法。
Enerlib類庫提供的Example代碼說明了如何使用該類庫的功能函數(shù),為閱讀方便起見,筆者添加了行號標(biāo)識和中文注釋,如下所列:
01#include
02Energy energy; //聲明energy庫
03void INT0_ISR(void)//中斷服務(wù)程序
04{
05/*用Enerlib提供的函數(shù)判定系統(tǒng)狀態(tài)*/
06if (energy.WasSleeping())
07{
08/*系統(tǒng)正在睡眠,此處可添加你的代碼*/
09}
10else
11{
12/*系統(tǒng)已被喚醒,此處可添加你的代碼 */
13}
14}
15void setup() //初始化模塊
16{
17attachInterrupt(0, INT0_ISR, LOW);
18/*初始化中斷設(shè)定:Int0外部中斷,低電平觸發(fā)中斷服務(wù)程序INT0_ISR() */
19energy.PowerDown(); //最節(jié)電方式
20energy.Standby();
21energy.PowerSave();
22energy.SleepADC();
23energy.Idle(); //最少節(jié)電方式
24/*從以上5種中選擇一種進(jìn)入睡眠方式*/
25}
26void loop() //主程序模塊
27{
28/*主程序代碼*/
29}
可以看出,進(jìn)入睡眠的代碼在僅執(zhí)行一次的初始化模塊void setup()中,表明系統(tǒng)啟動后做完初始化工作即進(jìn)入睡眠。代碼的19~23行給出了5種睡眠方式,在實際應(yīng)用中選擇一種適合的方式即可。系統(tǒng)的喚醒在Int0外部中斷服務(wù)程序中,Enerlib類庫提供了一個只能在中斷服務(wù)程序中使用的WasSleeping()函數(shù),以判定系統(tǒng)目前的“睡眠/醒著”的狀態(tài),該程序執(zhí)行一次睡眠,然后隨機(jī)喚醒后不能再次進(jìn)入睡眠狀態(tài)。這是一個典型的“預(yù)定睡眠-隨機(jī)喚醒”實例。
LowPower類庫提供的實例代碼如下(行號和中文注釋由筆者添加):
01 #include "LowPower.h"
02 const int wakeUpPin = 2; //Pin2腳用于Int0觸發(fā)
03 void wakeUp() //中斷服務(wù)程序
04 {
05//進(jìn)入此處表明系統(tǒng)已經(jīng)喚醒
06 }
07 void setup() //初始化模塊
08 {
09//定義觸發(fā)中斷的引腳為輸入
10pinMode(wakeUpPin, INPUT);
11 }
12 void loop() //主程序模塊
13 {
14//定義Pin2低電平引發(fā)執(zhí)行wakeUp()
15 attachInterrupt(0, wakeUp, LOW);
16//確定睡眠模式:關(guān)閉ADC和BOD
17LowPower.powerDown( ADC_OFF, BOD_OFF);
18//Pin2低電平時將喚醒
19detachInterrupt(0); //關(guān)閉中斷以防多次喚醒
20//添加功能代碼
21 }
可以看出,進(jìn)入睡眠的代碼在主程序循環(huán)體void loop()內(nèi),系統(tǒng)啟動后即進(jìn)入休眠狀態(tài),一旦有外部中斷即喚醒,喚醒后執(zhí)行完主程序功能后再次進(jìn)入睡眠,這也是典型的“預(yù)定睡眠-隨機(jī)喚醒”實例。
因ATMega單片機(jī)在外部中斷模式下會忽略引起中斷引腳的數(shù)據(jù)方向,所以該例程第10行“pinMode(wakeUpPin, INPUT);”沒有必要。
以上兩種睡眠與喚醒實例均實現(xiàn)不了隨機(jī)進(jìn)入睡眠的功能要求。
2隨機(jī)睡眠與喚醒的方法
如果可以實現(xiàn)在系統(tǒng)工作過程中隨時中止工作進(jìn)入睡眠(如為了節(jié)省電力而遠(yuǎn)程控制終止節(jié)點的監(jiān)測),然后在適當(dāng)?shù)臅r機(jī)再喚醒系統(tǒng)繼續(xù)工作,就是典型的“隨機(jī)睡眠-隨機(jī)喚醒”功能。
在以上兩個實例中,一個是將睡眠指令放于初始化模塊,實現(xiàn)一次性主動睡眠;另一個是將睡眠指令放在主程序循環(huán)體中,在執(zhí)行完預(yù)定功能后主動進(jìn)入睡眠,二者均有外部隨機(jī)喚醒。如果要實現(xiàn)通過外部指令(中斷)隨機(jī)進(jìn)入睡眠,睡眠指令首先不能放在初始化模塊void setup()中,因為這樣僅會引起一次睡眠;如果放到主程序循環(huán)體void loop()中,則必須在由“睡眠/喚醒”指令引起的中斷服務(wù)程序中放置相應(yīng)的標(biāo)志,然后再在主程序中判斷這個標(biāo)志,勢必增加相應(yīng)的軟件開支,而且程序的結(jié)構(gòu)也不明晰。
因此,實現(xiàn)隨機(jī)進(jìn)入睡眠的最簡單的方法就是將睡眠指令直接置于中斷服務(wù)程序當(dāng)中,當(dāng)睡眠指令發(fā)出后,執(zhí)行中斷服務(wù)程序進(jìn)入睡眠;當(dāng)喚醒指令發(fā)出后,只要進(jìn)入了中斷服務(wù)程序即可喚醒。但是在同一個中斷服務(wù)程序中實現(xiàn)該功能,需要透徹地了解相應(yīng)單片機(jī)的中斷處理機(jī)制以及所用的庫函數(shù)對中斷的處理方法。
構(gòu)成Arduino的核心處理器主要是Atmel的AVR ATmega系列MCU(如ATmega328),常用的實驗平臺有UNO、NANO、Pro、Pro Mini、Micro、Lilypad、Leonardo、Duemilanove等,因此Arduino的睡眠與喚醒的控制實質(zhì)是對MCU的控制,也就是控制ATmega328睡眠與喚醒。
實現(xiàn)隨機(jī)睡眠與喚醒的實驗平臺是Arduino Pro Mini 3.3 V、8 MHz/ATmega328,ATmega328的外部中斷機(jī)制[5]主要有:① RESET具有最高的優(yōu)先級,第二個為INT0;②任一中斷發(fā)生時全局中斷使能位被清零,從而禁止了所有其他的中斷;③退出中斷后,總是回到主程序并至少執(zhí)行一條指令才可以去執(zhí)行其他被掛起的中斷;④如果選擇了邊沿觸發(fā)方式或電平變化觸發(fā)方式,那么持續(xù)時間大于一個時鐘周期的脈沖將觸發(fā)中斷,過短的脈沖則不能保證觸發(fā)中斷,如果選擇低電平觸發(fā)方式,那么低電平必須保持到當(dāng)前指令執(zhí)行完成;⑤外部中斷通過引腳INT0、INT1 與INT2 觸發(fā),只要使能中斷且電平發(fā)生了合適的變化,即使引腳INT0~2配置為輸出,中斷也會觸發(fā);⑥若要求INT0與INT1 在信號下降沿或上升沿觸發(fā),則I/O 時鐘必須工作;⑦通過電平方式觸發(fā)中斷,在將MCU從掉電模式喚醒時,要保證電平保持一定的時間,以降低MCU對噪聲的敏感程度;⑧中斷響應(yīng)時間最少為4個時鐘周期,若中斷發(fā)生時MCU處于休眠模式,中斷響應(yīng)時間還需增加4個時鐘周期,此外還要考慮到不同的休眠模式所需要的啟動時間。
兩個類庫中,Enerlib的5種睡眠指令為PowerDown()、Standby()、PowerSave()、SleepADC()、Idle(),LowPower的5種睡眠方式為ADC_OFF、 BOD_OFF、IDLE_OFF、STANDBY、EXT_STANDBY,除了對各種不同設(shè)備進(jìn)行關(guān)斷外,對系統(tǒng)中斷的處理方式均相同,即睡眠前后均不對中斷的使能進(jìn)行處理,而且均提供了打開和關(guān)閉終端使能的函數(shù)。這樣,打開和關(guān)閉中斷的時機(jī)就完全交給了開發(fā)者。
3隨機(jī)睡眠與喚醒的實現(xiàn)與結(jié)果
使用Arduino自帶的LED(Pin13驅(qū)動)來檢驗隨機(jī)睡眠與喚醒,睡眠發(fā)生時LED閃爍0.1 s,表示接收到睡眠命令,然后熄滅LED進(jìn)入睡眠;喚醒發(fā)生時LED閃爍0.1 s,表示接收到喚醒命令,然后LED以1 Hz頻率閃爍工作。以下代碼筆者添加了行號標(biāo)識和中文注釋。
01 #include
02 Energy energy;//聲明"Energy"
03 int led = 13;
04 void SleepWake() //中斷服務(wù)程序
05 {
06 digitalWrite(led, HIGH);
07 delay(100);
08 digitalWrite(led, LOW); //LED閃爍0.1 s
10 if (energy.WasSleeping()) //判別狀態(tài)
11 {
12 delay(100); //睡眠狀態(tài),喚醒
11 }
12else //進(jìn)入睡眠
13{
14interrupts(); //打開中斷,以備喚醒
15energy.PowerDown(); //最節(jié)能睡眠
16}
17 }
18 void setup() //初始化模塊
19 {
20pinMode(led,OUTPUT);
21digitalWrite(led,LOW);
//定義Int0低電平進(jìn)入SleepWake()
22attachInterrupt(0,SleepWake,LOW);
23 }
24 void loop()
25 {
26digitalWrite(led, LOW);
27delay(500);
28digitalWrite(led,HIGH);
29delay(500);
30 }
將Arduino Pro Mini的Pin2(D2)通過一個10 KΩ電阻連接到Vcc,然后在Pin2對地連接一個按鍵開關(guān),下載完程序后上電,系統(tǒng)LED進(jìn)入1 Hz閃亮模式,按一下按鍵,LED閃爍0.1 s,然后進(jìn)入睡眠;再按一下按鍵,LED閃爍0.1 s,然后系統(tǒng)LED進(jìn)入1 Hz閃爍模式,如此重復(fù)。
結(jié)語
Arduino的核心——ATmega系列單片機(jī),以其RISC的可靠結(jié)構(gòu)、主控板、外圍模塊等硬件的規(guī)范設(shè)計,具有較高的可靠性。Arduino之所以風(fēng)靡全球,除了開源的硬件之外,更重要的是配套了開發(fā)軟件的IDE以及眾多的類庫,同時IDE集成、定義了編程方法[6],底層的Bootloader就像是個微型操作系統(tǒng),而不像使用Keil C開發(fā)單片機(jī)軟件那樣自己來組織程序的結(jié)構(gòu)、編寫驅(qū)動程序,Arduino的軟件和硬件設(shè)計使得編程、供電、下載一體化。由于其遵循開源共享的宗旨,相關(guān)類庫會越來越豐富[7],也正是這個IDE將軟件開發(fā)工具和實際硬件隔離,使得軟件開發(fā)變得簡單、快速,開發(fā)者可以專注于方案的實施。當(dāng)然也由于軟件底層與功能模塊硬件的隔離,使得開發(fā)者越來越依賴類庫,這一循環(huán)導(dǎo)致開發(fā)者過分依賴類庫而不去探究問題的實質(zhì),最后導(dǎo)致問題得不到解決或者退而
Random Sleep and Awaken of Arduino with Same External Interrupt
Liu Xiankai1,2
(1.Key Laboratory of Evidence Identifying in Universities of Shandong,Shandong University of Political
Science and Law,Jinan 250014,China;2.Department of Information,Shandong University of Political Science and Law)
Abstract:In order to control the random sleep and wake-up of the Arduino,instead of "scheduled sleep-random wake-up" of the conventional design mode,an external interrupt is used to make the Arduino into sleep,and then the same external interrupt is used to random wake-up the Arduino.First,the open source Enerlib and LowPower library are used to test the Pro Mini Arduino,and then it is applied to the practical engineering design.It works fine,and the method can be used as a mature solution in the application of engineering design.
Key words:Arduino;random sleep;random awaken;external interrupt
中圖分類號:TP273.5
文獻(xiàn)標(biāo)識碼:A