我是嵌入式系統(tǒng)的講師。我繼承了一段運行良好的代碼,但是由于缺少設計圖,并且花了很多條件語句和標志,使我花了一些時間來理解。
該代碼的目的是檢測連接到微控制器端口的幾個按鈕之一何時被激活并記錄事實。這些按鈕為高電平有效,這意味著按下按鈕時會在相應的引腳上產(chǎn)生高電壓。開關彈跳的問題也已在固件中解決,因此同一引腳必須在預定的時間內(nèi)保持高電平,然后才能被接受為有效引腳。
該代碼每10毫秒調(diào)用一次,如果同一引腳為高電平,則計數(shù)器遞增。當計數(shù)器達到預定義的值(在這種情況下為10)時,按鈕按下被認為是有效的。因此,在這種情況下,在認為有效之前,引腳電壓必須穩(wěn)定在100mS的高電平。
為了更好地說明設計,并作為學生的狀態(tài)機設計的另一個示例,我著手使用狀態(tài)機設計方法重新設計系統(tǒng)。
狀態(tài)機
狀態(tài)機圖如下圖1所示。所述Button_PORT是定義為任何端口的按鈕都連接到宏。這允許將按鈕輕松移動到另一個端口。
#define Button_PORT PORTA
聲明了一個聯(lián)合,該聯(lián)合將允許將按鈕作為一個整體或單獨進行訪問。
typedef union { unsigned char Full; 結構{ 無符號字符B0:1; 未簽名的字符B1:1; 未簽名的字符B2:1; 未簽名的字符B3:1; 未簽名的字符B4:1; 未簽名的字符B5:1; 未簽名的字符B6:1; 未簽名的字符B7:1; }; } Button_Type;
使用此類型定義了兩個變量Button_Press和Temp_Press。Button_Press在反跳后保留按鈕的最終值,而Temp_Press在反跳過程中保留按鈕的中間值。
在應用程序代碼中,設置了一個計時器,每10毫秒產(chǎn)生一個中斷,然后評估狀態(tài)機。狀態(tài)機圖將此時間表示為TICK事件(TICK_E)的發(fā)生。
有以下四種狀態(tài):
等待中:等待端口上的任何按鈕被激活。
檢測到:按鈕已激活,因此進入此狀態(tài),并使用Temp_Press記錄按鈕的端口值。每10毫秒,將再次檢查按鈕端口,并且-在其值仍然相同的情況下-計數(shù)器將遞增。用狀態(tài)機的話來說,該變量稱為“擴展狀態(tài)變量”。
WaitForRelease:如果計數(shù)器達到預定義的最小值'MIN_BUTTON_COUNT',則Temp_press現(xiàn)在被視為有效,并且進入WaitForRelease狀態(tài)以等待按鈕釋放,直到變量Button_Press保留了最終的按鈕值。
更新:按鈕已釋放,因此最終值Button_Press已用去抖動的臨時值'Temp_Press'更新。
圖1.按鈕反跳狀態(tài)機(來源:Thomas Gartlan)
該狀態(tài)機繪制在www.draw.io上,并根據(jù)Miro Samek的書《C / C ++中的實用UML狀態(tài)圖:嵌入式系統(tǒng)的事件驅(qū)動編程》中的內(nèi)容使用表示法來表示狀態(tài)。
從教學的角度來看,此狀態(tài)機是狀態(tài),事件,警戒條件,Do操作,OnEntry操作和擴展狀態(tài)變量的一個很好的示例。
正如我們前面提到的,有四個狀態(tài)。唯一的事件是10mS TICK_E。從“等待”到“檢測到”的過渡中,TICK_E上有一個保護狀態(tài),[Button_PORT> 0],在這種情況下,這意味著某些按鈕已被激活。“已檢測”狀態(tài)下的“ OnEntry”操作會重置計數(shù)器,而“已檢測”狀態(tài)下的“執(zhí)行”操作會在計數(shù)器中遞增。計數(shù)器本身是擴展狀態(tài)變量。
與原始的以條件標記為中心的代碼相反,此狀態(tài)機圖提供了非常清晰的設計視圖,因此為學生提供了一個很好的示例。
實施
該設計是使用MPLABX IDE和XC8編譯器實現(xiàn)的。目標器件是Microchip的8位PIC18F4520微控制器。該設計以易于重復使用的方式實現(xiàn)。如前所述,端口是使用宏定義的,因此可以輕松地對其進行更改。而且,該代碼打包在一個庫中并發(fā)布到GitHub,這使得它可以輕松地維護和在任何項目中使用。
庫頭文件包含按鈕結構和端口信息。庫C文件包含狀態(tài)機功能。代碼中使用的名稱與狀態(tài)機圖相匹配,從而更易于理解和調(diào)試設計。函數(shù)指針并不是真正需要的,也沒有使用,因為它們會使學生在此階段對設計的理解更加復雜。狀態(tài)機功能的代碼如下所示。
typedef枚舉{Waiting,Detected,WaitForRelease,Update}狀態(tài); 無效Find_Button_Press(void) { 靜態(tài)狀態(tài)Button_State =正在等待; 靜態(tài)無符號字符Button_Count = 0; 靜態(tài)Button_Type Temp_Press; 開關(按鈕狀態(tài)){ 案例(等待): 如果(Button_PORT) { Button_State =已檢測到; Button_Count = 0; Temp_Press.Full =按鈕_端口; } 休息; 案例(檢測): 如果(Temp_Press.Full == Button_PORT) { ++ Button_Count; 如果(Button_Count> MIN_BUTTON_COUNT) { Button_State = WaitForRelease; } } 別的 { Button_State =等待中; } 休息; 案例(WaitForRelease): 如果(!Button_PORT) { Button_State =更新; } 休息; 案例(更新): { Button_Press = Temp_Press; Button_State =等待中; Button_Count = 0; Temp_Press.Full = 0; } 休息; 默認: { Button_State =等待中; Button_Count = 0; Temp_Press.Full = 0; Button_Press.Full = 0; } } }
應用代碼和測試
開發(fā)了一個簡單的應用程序來說明和測試該設計。該應用程序測試代碼的一部分如下所示。包含頭文件,并定義了Button_Press變量。對頭文件的唯一修改是定義用于按鈕的端口。
/ ***************************************************** *** 包括圖書館 ****************************************************** *** / #include#include #include“ Buttons_Debounce.h” Button_Type Button_Press; //創(chuàng)建Button變量 / **************************************************** 功能原型 ****************************************************** / void Initial(void); void delay_s(unsigned char secs); / ***************************************************** 鐘 ****************************************************** / #define _XTAL_FREQ 19660800 unsigned char count_test = 0; void __interrupt myIsr(void) { //定時器每10毫秒溢出一次 if(INTCONbits.TMR0IE && INTCONbits.TMR0IF){ Find_Button_Press(); //每10毫秒調(diào)用一次 WriteTimer0(40960); INTCONbits.TMR0IF = 0; //清除此中斷條件 } } void main(無效) { Button_Press.Full = 0x00; 最初的(); 而(1) { if(Got_Button_E)//如果已按下某個按鈕 { if(Button_Press.B0)//如果其按鈕為0 PORTCbits.RC0 =?PORTCbits.RC0; if(Button_Press.B1)//如果其按鈕為0 PORTCbits.RC1 =?PORTCbits.RC1; if(Button_Press.B2)//如果其按鈕為0 PORTCbits.RC2 =?PORTCbits.RC2; if(Button_Press.B3)//如果其按鈕為0 PORTCbits.RC3 =?PORTCbits.RC3; Button_Press.Full = 0x00; //清除所有按鈕事件 } } }
將創(chuàng)建一個定時器中斷,每10毫秒發(fā)生一次,并調(diào)用狀態(tài)機功能。在此應用中,按鈕連接到PORTB,而LED連接到PORTC。如果按下任何按鈕,則相應的LED會切換而不會出現(xiàn)任何延遲或彈跳問題。處理按鈕值后,將清除整個變量。
總體而言,該項目被認為是在設計階段如何使用狀態(tài)機方法,從而導致更清晰,更不易出錯的實現(xiàn)的一個很好的例子。
編輯:hfy
-
微控制器
+關注
關注
48文章
7565瀏覽量
151577 -
嵌入式系統(tǒng)
+關注
關注
41文章
3596瀏覽量
129550 -
計數(shù)器
+關注
關注
32文章
2256瀏覽量
94686 -
狀態(tài)機
+關注
關注
2文章
492瀏覽量
27561
發(fā)布評論請先 登錄
相關推薦
評論