有限狀態(tài)機在單片機編程中的應(yīng)用_第1頁
有限狀態(tài)機在單片機編程中的應(yīng)用_第2頁
有限狀態(tài)機在單片機編程中的應(yīng)用_第3頁
有限狀態(tài)機在單片機編程中的應(yīng)用_第4頁
有限狀態(tài)機在單片機編程中的應(yīng)用_第5頁
已閱讀5頁,還剩14頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

學(xué)習(xí)筆記有限狀態(tài)機在單片機編程中的應(yīng)用在單片機編程中,如果在不使用操作系統(tǒng)的情況下同時執(zhí)行多個任務(wù),可能會遇到下面這些情況:一個任務(wù)的執(zhí)行時間過長,導(dǎo)致其他任務(wù)無法及時執(zhí)行在一些任務(wù)中大量使用delay()等函數(shù)進行軟件延時,這些延時函數(shù)占用過多時間,影響其他任務(wù)的執(zhí)行一些復(fù)雜任務(wù)的程序邏輯不清晰,不便于以后對程序進行維護,或添加新功能本文介紹的有限狀態(tài)機,可以做到將一個耗時較長的復(fù)雜任務(wù)分解為多個簡單任務(wù),同時使代碼邏輯更加清晰,從而解決上述問題。目錄:什么是有限狀態(tài)機有限狀態(tài)機的作用2.1分解耗時過長的任務(wù)2.2避免軟件延時對CPU資源造成浪費2.3使程序邏輯更加清晰有限狀態(tài)機的實現(xiàn)3.1通過switch-casel吾句實現(xiàn)3.2通過Arduino庫實現(xiàn)3.3其他方式示例一:按鍵去抖動程序的優(yōu)化4.1傳統(tǒng)的按鍵去抖動程序4.2優(yōu)化后的按鍵去抖動程序示例二:通過有限狀態(tài)機實現(xiàn)的鬧鐘程序后記什么是有限狀態(tài)機根據(jù)維基百科上的定義,有限狀態(tài)機(finite-statemachine,FSM簡稱狀態(tài)機)是表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學(xué)模型。1為了理解這句話,假設(shè)自己還有三天就要考試,這時候就要進入緊張的備考狀態(tài),將空閑時間用復(fù)習(xí)上。但是,為了保證足夠的精力,小睡一會兒也是十分有必要的。那么,什么時候復(fù)習(xí),什么時候睡覺呢?可以這樣描述:在復(fù)習(xí)的時候:如果感到瞌睡,則睡覺如果沒有感覺到瞌睡,則繼續(xù)復(fù)習(xí)在小睡的時候:如果感覺不再瞌睡,則開始復(fù)習(xí)如果感覺依舊瞌睡,則繼續(xù)睡覺也可通過一幅簡單的示意圖(也叫「狀態(tài)轉(zhuǎn)移圖」)表示出來:感覺清醒這個例子其實就是一個簡單的有限狀態(tài)機,其中,復(fù)習(xí)和小睡是兩個狀態(tài),感覺瞌睡和感覺清醒這兩個條件可以使狀態(tài)發(fā)生轉(zhuǎn)換。2另外,ProgrammingBasics3網(wǎng)站上也提供了狀態(tài)機相關(guān)的教程,用形象化的圖片解釋了什么是有限狀態(tài)機,可通過此鏈接訪問在嵌入式程序設(shè)計中,如果一個系統(tǒng)需要處理一系列連續(xù)發(fā)生的任務(wù),或在不同的模式下對輸入進行不同的處理,常常使用有限狀態(tài)機實現(xiàn)。例如測量、監(jiān)測、控制等控制邏輯型應(yīng)用。4

有限狀態(tài)機的作用2.1分解耗時過長的任務(wù)大家應(yīng)該都知道,CPU沒有并行執(zhí)行任務(wù)的能力。計算機「同時」運行多個程序,其實是多個程序依次交替執(zhí)行,給人以程序同時運行的錯覺。各個程序在什么時候開始執(zhí)行,執(zhí)行多長時間后切換到下一個程序,由操作系統(tǒng)決定。單片機執(zhí)行多任務(wù)也是類似的過程,但由于其資源有限,為了節(jié)省對CPU和存儲空間的占用,在很多情況下沒有使用操作系統(tǒng)。這時,單片機中運行的各個任務(wù)必須在一定時間內(nèi)主動執(zhí)行完畢,才能保證下一個任務(wù)能夠及時執(zhí)行對于一些需要長時間執(zhí)行的任務(wù),例如按鍵去除抖動、讀取和播放MP3文件等,采用有限狀態(tài)機的方式,將任務(wù)劃分為多個小的步驟(狀態(tài)),每次只執(zhí)行其中的一步。這樣,其他任務(wù)就有機會「插入」到這個任務(wù)之中,確保了各個任務(wù)都能按時執(zhí)行。任務(wù)B任務(wù)B任務(wù)A任務(wù)女我要執(zhí)行一件審斐的事,能否始我讓出點時間?任努A:不行,我還沒執(zhí)行完。任務(wù)A未使用狀態(tài)機,其他任會不能及時執(zhí)行任務(wù)史我要執(zhí)行一件審耍的事'能杏給我讓出點時間?任封A:好的.我很快就會把我的第一部分執(zhí)行完,剩下的時間伽來執(zhí)行,然后我在執(zhí)行我的其余部分任務(wù)Afill分為三個狀態(tài),其他任務(wù)可以及時執(zhí)行

2.2避免軟件延時對CPU資源造成浪費對于一些簡單的程序,可通過delay(),delay_ms(之類的函數(shù)進行軟件延時。這些延時函數(shù),一般是通過將某個變量循環(huán)遞加或遞加,到達一定值后跳出循環(huán),從而通過消耗CPU時間實現(xiàn)了延時這種方式雖然簡單,但在延時函數(shù)執(zhí)行的過程中,其他程序無法運行,消耗了大量CPU資源。而通過狀態(tài)機,有助于減少軟件延時的使用,提高CPU利用率任務(wù)此第一部分延時函數(shù)占用

大量時間任務(wù)A;第任務(wù)此第一部分延時函數(shù)占用

大量時間任務(wù)A;第二部分滿足適當(dāng)?shù)臈l件時.發(fā)生狀態(tài)轉(zhuǎn)換未使用狀態(tài)機

軟件延時占用了較多時間使用狀態(tài)機需要延時的時間可以讓其他任務(wù)執(zhí)行請參考下文中的示例一:按鍵去抖動程序的優(yōu)化,這一例子展示了如何通過軟件延時分解耗時較長的任務(wù),同時減少軟件延時的使用。2.3使程序邏輯更加清晰通過狀態(tài)機,將一個復(fù)雜任務(wù)劃分為多個狀態(tài),可以使程序清晰易懂,便于維護。以后想要添加、刪除程序中的功能,都會變得非常容易。

113ELLLELIJIllimiLCUULE113ELLLELIJIllimiLCUULE……functionf)…… case…else...switchu—gbtD一2……define頃"return fun2() 5倉…“ ■*扣w.if .else....,…,^..functian()…… LlddSswitch define.return fun2() ^case - els已....….if,gfurKtion()心if,gfurKtion()心程序諾輯不清晰 程序邏輯清晰下文中的示例二:通過狀態(tài)機實現(xiàn)的鬧鐘展示了如何通過狀態(tài)機優(yōu)化程序邏輯。有限狀態(tài)機的實現(xiàn)如果使用C語言,switch-case吾句,即可簡單地實現(xiàn)有限狀態(tài)機。3.1通過switch-case語句實現(xiàn)如果使用C語言,switch-case吾句,即可簡單地實現(xiàn)有限狀態(tài)機。/*通過狀態(tài)機實現(xiàn)的某個任務(wù),*需要放入while(1)等地方循環(huán)執(zhí)行*/switch(currentStatus)/*根據(jù)現(xiàn)在的狀態(tài)執(zhí)行相應(yīng)的程序*/^3cOSe^?A?US_A^^狀^^*^^^^^^^^^^^^BdoThingsForStatusA();/*執(zhí)行狀態(tài)A中需要執(zhí)行的任務(wù)*/*若滿足狀態(tài)轉(zhuǎn)換的條件,則轉(zhuǎn)換到另一個狀態(tài)*/if(condition_1X^urreniSiatus^^TATUEaB^^^^^^^^^Mbreak;doThingsForStatusB();/*執(zhí)行狀態(tài)B中需要執(zhí)行的任務(wù)*/*若滿足狀態(tài)轉(zhuǎn)換的條件,則轉(zhuǎn)換到另一個狀態(tài)*/if(condition_2){currentStatus=STATUE_C;^^^^^^^^^^if(conditipn_3){^urrenSiatus^^TATUE_A^^^^^^^^^Ibreak;doThingsForStatusB();/*執(zhí)行狀態(tài)B中需要執(zhí)行的任務(wù)*/*若滿足狀態(tài)轉(zhuǎn)換的條件,則轉(zhuǎn)換到另一個狀態(tài)*/if(condition_4)^urrenSatus^^TATUE_Ai^^^^^^^^^lbreak;default:通過這段程序,即可實現(xiàn)一個具有三個狀態(tài)的狀態(tài)機。狀態(tài)轉(zhuǎn)移圖如下圖所示:3.2通過Arduino庫實現(xiàn)對于Arduino用戶,還可以使用FSMLibrary實現(xiàn)。這一庫將有限狀態(tài)機進行了封裝,可以以更簡潔的方式實現(xiàn)狀態(tài)機。下載地址及使用說明:http://playground.arduino.cc/Code/FiniteStateMachine3.3其他方式對于一些更復(fù)雜的任務(wù),使用switch-case語句,代碼可能會太簡潔。這時候,使用其他方式實現(xiàn)狀態(tài)機,可能會更好。具體請查閱相關(guān)資料。示例一:按鍵去抖動程序的優(yōu)化4.1傳統(tǒng)的按鍵去抖動程序初學(xué)單片機時,我們接觸的按鍵去抖動程序一般是這樣的5

技鍵技下?延時函數(shù)占用時回較長執(zhí)行按下按擢后需要執(zhí)行的程序結(jié)束從流程圖中可知,delayms()延時函數(shù)和最后的等待按鍵釋放的程序,會占用過多時間。4.2技鍵技下?延時函數(shù)占用時回較長執(zhí)行按下按擢后需要執(zhí)行的程序結(jié)束從流程圖中可知,delayms()延時函數(shù)和最后的等待按鍵釋放的程序,會占用過多時間。4.2優(yōu)化后的按鍵去抖動程序?qū)?yīng)的流程圖如下:if(key1==0)//再次檢測按鍵1,如果依舊按下{doSomething();//此時說明按鍵1已按下,執(zhí)行按鍵1需要執(zhí)行的任務(wù)while(!key1);//等待按鍵釋放}此封CPU—直在等待按禎粹放,如果不翔州CPU就無法執(zhí)行其他任務(wù)延時10ms如果按譴依舊按下如果使用有限狀態(tài)機的思路,可以按照下圖方式實現(xiàn):該狀態(tài)機有三個狀態(tài),分別是按鍵未按下,等待,按鍵按下。當(dāng)按鍵按下時,則會進入等待狀態(tài),若在等待狀態(tài)中按鍵一直保持按下,說明按鍵已經(jīng)穩(wěn)定地按下,進入按鍵按下的狀態(tài),等待按鍵釋放。程序代碼如下:/其他情況返回not_pressedkeyState=KEY_STATE_RELEASE;其他情況返回not_pressedkeyState=KEY_STATE_RELEASE;returnN#defineKEY_STATE_RELEASE //鍵未按#defineKEY_STATE_WAITING //等待(消抖<^^[^^^^^^^^^|「defineKEY_STATE_PRESSED //按鍵按下(等待釋放/*等待狀態(tài)持續(xù)時間*需要根據(jù)單片機速度和按鍵消抖程序被調(diào)用的速度來進行調(diào)整*//*按鍵檢測函數(shù)的返回值,按下為1,未按下為0*/#definePRESSED1「defineNOT_PREsSEdO^^^^^^^^^^^^^^^^^^^^^^^B/*按鍵掃描程序所處的狀態(tài)|*初始狀態(tài)為:按鍵按下Tey_staTE_RELEASET^^^^^^^^^J*/Uint8_tkeyState=KEY_STATE_RELeASE^^^^^^^^^^^^^^^M/*按鍵檢測函數(shù),通過有限狀態(tài)機實現(xiàn)*函數(shù)在從等待狀態(tài)轉(zhuǎn)換到按鍵按下狀態(tài)時返回PRESSED,代表按鍵已被觸發(fā)*/{staticuint8_tduration;//用于在等待狀態(tài)中計數(shù)switch(keyState)H^CaSe^|x_^^TE_RELEA^^^^^^^^^^^^^^^^^^^^^^^^HifreadKey()==1) /7^果按鍵按下^^eySSBS|_S?A?S_WA!S^^換至下一個狀return^O?_mSi5^^^回:按鍵未按break;if(readKey()==1) //如果按鍵按下duriation++;{ //說明沒有抖動了,可以確定按鍵已按下duriation=0;keyState=k£Y_SJATE_PRESSED;//轉(zhuǎn)換至下一個狀態(tài)returnPRESSED;^^IS^^果此時按鍵松{ //可能存在抖動或干擾duriation=0;//清零的目的是便于下次重新計數(shù)break;caseif(readKey()==0) //如果按鍵松開{松開的狀returnNOT_PRESSED,break;default:該程序也可經(jīng)過擴展,實現(xiàn)判斷按鍵雙擊、長按等功能。只需增加相應(yīng)的狀態(tài)和轉(zhuǎn)移條件即可。示例二:通過有限狀態(tài)機實現(xiàn)的鬧鐘程序最近正在制作一個鬧鐘。這個鬧鐘支持播放MP3格式的鬧鐘聲6,支持貪睡模式,同時還有一些功能打算以后再添加上。為了使程序邏輯更加清晰,也為了更方便地添加新功能,我打算采用有限狀態(tài)機實現(xiàn)。相關(guān)程序如下:^nZiude<USART1.h"^^^^^^^^^^^^^^^^^^^^^^^Minclude"diag/Trace.h"*相關(guān)常量定義 displayMessege()用于在顯示屏上顯示相關(guān)的提示信息 displayMessege()用于在顯示屏上顯示相關(guān)的提示信息*/用嘉。MESSEGE_SET_ALARM_TIME (0)//提示:設(shè)置鬧鐘時間{ //如果打開了鬧鐘alarmState=PLAY_ALARM_MUSIC;//進入下一個狀態(tài):播放鬧鐘音樂成fineALARM_MUSlC_END0 //鬧鐘音樂播放完畢用efineFORMAT_OK 0 〃格式正確用efineFORMAT_ERROR (-1) //格式錯誤*輸入信息定義*作為函數(shù)的返回值供函數(shù)getInput()使用getInput()將獲取并返回鍵盤或觸摸屏等設(shè)備中輸入的控制命令或鬧鐘時間值*/用efineINPUT_CANCEL (-2) //輸入了「取消」命令用efineINPUT_SNOOZE (-3) //輸入了「小睡」命令用efineINPUT_ALARM_ON(-4) //輸入了「打開鬧鐘」"命用efineNO_INPUT (-10)//沒有輸X^J^^^^^^^^^^B*輸出信息定義*作為為函數(shù)的參數(shù)供函數(shù)displayMessege()使用

defineMESSEGE_CLEAR (1)//提示:已取消,defineMESSEGE_GET_UP (5)//提示:節(jié)起床了/*鬧鐘的狀態(tài)*/enumalarmStates{鬧鐘關(guān)閉1//默認狀態(tài):鬧鐘關(guān)閉/*相關(guān)函數(shù)的定義*/int16_tgetInput(void);|1nt8_tcheckSnoozeFormat(int16_t);**鬧鐘主程序,需要放入while(1)中循環(huán)調(diào)用/oidalarmApp(void),//輸入值暫存在這個變量中switch(alarmState)//獲取鬧鐘狀態(tài),下面程序?qū)⒏鶕?jù)鬧鐘的狀態(tài)執(zhí)行相應(yīng)的任務(wù)/*狀態(tài):鬧鐘關(guān)閉*在此狀態(tài)中,將會不斷檢查是否打開鬧鐘,如果打開了鬧鐘,則會進入下一個狀態(tài):設(shè)置鬧鐘時間*/caseif(getInput()==INPUT_ALARM_ON)//檢查是否打開了鬧鐘請設(shè)置鬧鐘時間| break;/*狀態(tài):設(shè)置鬧鐘時間*在此狀態(tài)中,將會檢查輸入值,*如果輸入“取消”命令,則取消鬧鐘設(shè)置,返回到鬧鐘關(guān)閉的狀態(tài)輸入鬧鐘時間格式錯誤,則狀態(tài)不變,等待下一次重新輸入輸入了正確的鬧鐘時間,則設(shè)置鬧鐘,顯示鬧鐘設(shè)置成功,并進入下一狀態(tài):等待鬧鐘響casesetalarm"time:^^^^B^^^^^^^^^^^^^^^^^^^^^Minput=getInput(); //獲取輸入值ifi^put==INPUT_CANCEL) //如果輸入了取消^^i!PlayMe!Sege(MESSEGE_CLEAR)^^示“已取消I alarmstate=ALARM_OFF; //進入狀態(tài):關(guān)閉鬧鐘~ejs^fCheckAlarmFormst(!nput)^=^ORMAT_OK^^^^如果輸入格式正I ^^iplayMEg!(MESIE5E_ALARM_IS_ON^^示“成功設(shè)置鬧鐘^鬧鐘已^動”setAlarm(input);//根據(jù)輸入值設(shè)置鬧鐘| break;/*狀態(tài):等待鬧鐘響起*在此狀態(tài)中,將會檢查是否到達鬧鐘時間,如果到達,則進入下一狀態(tài):播放鬧鐘音樂*同時,在此狀態(tài)中也會檢查輸入,如果輸入了“取消”的命令,則進入鬧鐘關(guān)閉的狀態(tài)=/] casewating_for_alarm:^^^^^^^^^^^^^^^^^^^^^^^^^^displayMessege(MESSEGE_WAITING);//顯示等待鬧鐘響起的信息,例如離鬧鐘響起|還有多長時間if(alarmTimeDiff()<=0)//檢查離鬧鐘響起還有多少時間,如果時間小于等于零(到達鬧鐘時間)if^SPSSmS_CAS^/F如果輸入了取消命■alarmState=ALARM_OFF; //進入鬧鐘關(guān)閉的狀態(tài)break/*狀態(tài):播放鬧鐘音樂*在此狀態(tài)中,將播放鬧鐘音樂,若播放完畢,進入鬧鐘關(guān)閉的狀態(tài)*同時,在此狀態(tài)中也會檢查輸入,如果輸入了“小睡”的命令,則進入狀態(tài):設(shè)置小睡時間如果輸入了“取消”的命令,則進入狀態(tài):鬧鐘關(guān)閉*/cas;PLAY_ALARM_MUS^C^^^^^^^^B^^^^^^^^^^^^^^^^jdisplayMessege(MESSEGE_GE?_UpT^^示消息:該起床了if(playAlarmMusic()無ALARM_MUSIC_END)//播放鬧鐘音樂{//若音樂播放完畢alarmState=ALARM_OFF;//進入狀態(tài):鬧鐘關(guān)閉input=getInput();ifi?put==INPUT_SNOOZE)//若輸入了“小睡”的命令^^ipsyMEg!(MESGE_SS_

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論