張錫林
(廣東省特種設(shè)備檢測研究院 珠海檢測院,珠海 519000)
?
嵌入式操作系統(tǒng)下“單鍵多態(tài)”的通用處理方法
張錫林
(廣東省特種設(shè)備檢測研究院 珠海檢測院,珠海 519000)
介紹了一種在實時嵌入式操作系統(tǒng)平臺上單鍵輸入的通用處理方法。該方法通過監(jiān)控按鍵的電平觸發(fā),配合操作系統(tǒng)內(nèi)置的軟定時器,高效實現(xiàn)了單個按鍵輸入時去抖動、單按、雙按、多按,以及納秒延時長按的不同狀態(tài)區(qū)分處理。該方法實現(xiàn)原理清晰簡單,不占用微處理器運行時間,并且可移植到等其他類似的系統(tǒng)中(如μC/OS、FreeRTOS、trochili RTOS),具有較高的應(yīng)用價值。
實時嵌入式系統(tǒng);按鍵處理;GD32F207;ThreadX
隨著ARM公司推出的Cortex系列32位處理器迅速在智能測量、人機接口、汽車工業(yè)、控制系統(tǒng)、家用電器等應(yīng)用場合得到廣泛的應(yīng)用,為了更合理地調(diào)度多任務(wù),高效利用系統(tǒng)資源、系統(tǒng)函數(shù)以及與專用庫函數(shù)的接口,通常使用實時嵌入式操作系統(tǒng)作為開發(fā)平臺,這樣既保證了程序執(zhí)行的實時性,又減少了產(chǎn)品開發(fā)時間,提高了軟件的維護性,縮短了新設(shè)備的上市時間。
在該系統(tǒng)的應(yīng)用開發(fā)中,經(jīng)常遇到需要在單個按鍵內(nèi)實現(xiàn)單按、雙按、多按、延時長按等多種組合的功能。本文以兆易創(chuàng)新(GigaDevice)公司的入門級開發(fā)板GD32-Colibri-F207ZE(下稱GD32F207ZE)作為硬件平臺,并通過ExpressLogic公司的商用高性能實時嵌入式操作系統(tǒng)——ThreadX測試版作為軟件開發(fā)平臺,實現(xiàn)了這些功能。
在大多數(shù)常見的按鍵輸入處理方法中,通常方法是監(jiān)控輸入端口的單一電平變化。而本方法同時還監(jiān)控了按鍵輸入電平的兩種變化——從高電平變?yōu)榈碗娖交蛘邚牡碗娖阶優(yōu)楦唠娖?,并通過處理器輸入I/O的上升沿觸發(fā)和下降沿觸發(fā),分別在中斷服務(wù)函數(shù)里面取得其觸發(fā)時刻的系統(tǒng)時鐘節(jié)拍,從而計算出兩種觸發(fā)變化時刻的時鐘節(jié)拍差異,判斷出按鍵輸入的類型,并通過一個全局變量傳遞至預(yù)先設(shè)置激活的軟定時器函數(shù)里,最終由軟定時器函數(shù)實現(xiàn)不同的按鍵處理。
2.1按鍵輸入電路
圖1 按鍵輸入電路及信號
按鍵輸入電路及信號如圖1所示,按鍵KEY1連接至微處理器GD32F207ZE的PD14輸入端口,并通過一個上拉電阻R30將輸入信號的初始穩(wěn)定狀態(tài)鉗位到高電平。當(dāng)按鍵KEY1觸發(fā)后,會呈現(xiàn)圖1(b)的實際電平信號??梢钥闯觯谳斎胄盘栯娖角袚Q過程中,均有一段電平信號的抖動過程,需使用處理程序?qū)ζ溥M行過濾。
2.2處理結(jié)果輸出電路
圖2 按鍵處理輸出電路
GD32F207ZE開發(fā)板板載了3顆不同顏色的LED,其電路形式如圖2所示,分別連接至微處理器GD32F207ZE的PD11、PD12和PD13輸入端口,可作為按鍵處理的輸出結(jié)果顯示,直觀方便。
2.3按鍵輸入及LED輸出I/O的初始化代碼
按鍵輸入I/O以及LED輸出I/O的初始化代碼如下:
01 #define BSP_LED_REDGPIO_PIN_11
02 #define BSP_LED_GREENGPIO_PIN_12
03 #define BSP_LED_YELLOWGPIO_PIN_13
04 #define BSP_BTN_KEY1GPIO_PIN_14
05 #define BSP_KEY1_EXTI_PIN_SOURCEGPIO_PINSOURCE14
06 #define BSP_KEY1_EXTI_LINEEXTI_LINE14
07 #define BSP_KEYS_EXTI_IRQChannelEXTI15_10_IRQn
08
09 /* Enable APB2 Clock */
10 RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOD|RCC_APB2PERIPH_AF,ENABLE);
11
12 /* Configure LED I/O mode */
13 GPIO_InitStructure.GPIO_Pin = BSP_LED_RED|BSP_LED_GREEN|BSP_LED_YELLOW;
14 GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
15 GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
16 GPIO_Init(GPIOD,&GPIO_InitStructure);
17
18 /* Configure BSP_BTN_KEYs IO mode*/
19 GPIO_InitStructure.GPIO_Pin = BSP_BTN_KEY1;
20 GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING;
21 GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
22 GPIO_Init(GPIOD,&GPIO_InitStructure);
23
24 /* Connect EXTI Line to pin */
25 GPIO_EXTILineConfig(GPIO_PORT_SOURCE_GPIOD, BSP_KEY1_EXTI_PIN_SOURCE);
26
27 /* Configure EXTI line trigger mode*/
28 EXTI_InitStructure.EXTI_LINE = BSP_KEY1_EXTI_LINE;
29 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
30 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
31 EXTI_InitStructure.EXTI_LINEEnable = ENABLE;
32 EXTI_Init(&EXTI_InitStructure);
33
34 /* Enable and set EXTI Line Interrupt */
35 NVIC_InitStructure.NVIC_IRQ = BSP_KEYS_EXTI_IRQChannel;
36 NVIC_InitStructure.NVIC_IRQPreemptPriority = 0x0F;
37 NVIC_InitStructure.NVIC_IRQSubPriority = 0x0F;
38 NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
39 NVIC_Init(&NVIC_InitStructure);
這部分代碼將驅(qū)動3個LED的I/O均設(shè)置為普通推挽輸出,同時將按鍵KEY1的I/O設(shè)置為懸空輸入,即在處理器芯片內(nèi)部既沒有接上拉電阻,也沒有接下拉電阻,其工作電平由外部電路決定(根據(jù)圖1,其穩(wěn)定初始狀態(tài)為高電平)。需注意兩點,在第30行代碼中,把按鍵KEY1的中斷觸發(fā)模式設(shè)置為上升沿和下降沿均引起中斷觸發(fā),這是整個實現(xiàn)方法中的關(guān)鍵;在第10行代碼中,由于使用了按鍵輸入端口PD14的中斷功能,因此需要將其復(fù)用功能RCC_APB2PERIPH_AF的時鐘同時開啟。
2.4ThreadX軟定時器函數(shù)
ThreadX軟定時器函數(shù)代碼如下所示:
01 tx_timer_create (&button_timer, "button_timer", button_timer_entry, 0x00, 100, 100, TX_NO_ACTIVATE);
02
03 void button_timer_entry(ULONG invalue){
04 switch(buton_pushed_counter){
05 case 1:
06 GPIOD->DOR ^= BSP_LED_RED;
07 break;
08 case 2:
09 GPIOD->DOR ^= BSP_LED_GREEN;
10 break;
11 case 3:
12 GPIOD->DOR ^= BSP_LED_YELLOW;
13 break;
14 case 20:
15 GPIOD->DOR ^= BSP_LED_RED;
16 break;
17 case 50:
18 GPIOD->DOR ^= BSP_LED_GREEN;
19 break;
20 case 90:
21 GPIOD->DOR ^= BSP_LED_YELLOW;
22 break;
23 default:
24 break;
25 }
26 buton_pushed_counter = 0;
27 tx_timer_deactivate(&button_timer);
28 }
以上代碼中,其中第01行代碼是實時嵌入式操作系統(tǒng)ThreadX的系統(tǒng)函數(shù),功能是建立一個按鍵處理的軟定時器,并處于關(guān)閉狀態(tài)。其中在該定時器函數(shù)中,buton_pushed_counter是一個UINT類型的全局變量,它由以下的按鍵中斷服務(wù)函數(shù)賦值,傳遞不同的按鍵輸入類型到這里進行判斷并分別處理。由代碼可以看出,處理結(jié)果就是分別切換開發(fā)板上板載的3顆不同顏色的LED的狀態(tài)。另外在處理完畢后,務(wù)必將buton_pushed_counter設(shè)置為0,并關(guān)閉定時器。
2.5按鍵中斷服務(wù)函數(shù)
按鍵中斷服務(wù)函數(shù)代碼如下:
01 /* In Threadx, the timer-ticks is 10ms */
02 #definebtn_0100_PUSH_MS 10UL
03 #definebtn_2000_PUSH_MS 200UL
04 #definebtn_5000_PUSH_MS 500UL
05 #definebtn_9000_PUSH_MS 900UL
06
07 void IrqHandler_BTN(void){
08 static ULONGxTimeKeyRising1, xTimeKeyFalling1;
09 ULONG xTimeKeyBetween1;
10
11 if(EXTI_GetIntBitState(BSP_KEY1_EXTI_LINE) != RESET){
12 if(GPIO_ReadInputBit(GPIOD, BSP_BTN_KEY1) == 0){
13 /* Return Values system clock ticks */
14 xTimeKeyFalling1 = tx_time_get();
15 xTimeKeyRising1 = NULL;
16 }
17 else if(GPIO_ReadInputBit(GPIOD, BSP_BTN_KEY1) == 1){
18 if(xTimeKeyFalling1 !=NULL)
19 xTimeKeyRising1 = tx_time_get();
20 }
21 if(xTimeKeyRising1 !=NULL && xTimeKeyFalling1 != NULL){
22 xTimeKeyBetween1 = xTimeKeyRising1 - xTimeKeyFalling1;
23 /* 1.單按鍵處理,包括雙按、多按鍵*/
24 if(xTimeKeyBetween1>btn_0100_PUSH_MS && xTimeKeyBetween1 25 buton_pushed_counter ++; 26 //active the timer,sometimes to wait for the next push 27 tx_timer_deactivate(&button_timer); 28 tx_timer_change(&button_timer,80, 80); 29 tx_timer_activate(&button_timer); 30 xTimeKeyRising1 = NULL; 31 xTimeKeyFalling1 = NULL; 32 } 33 /* 2.連續(xù)按下2~5 s */ 34 else if(xTimeKeyBetween1>btn_2000_PUSH_MS && xTimeKeyBetween1 35 buton_pushed_counter = 20; 36 //active the timer,set it expired in 10ms 37 tx_timer_deactivate(&button_timer); 38 tx_timer_change(&button_timer,10, 10); 39 tx_timer_activate(&button_timer); 40 xTimeKeyRising1 = NULL; 41 xTimeKeyFalling1 = NULL; 42 } 43 /* 3.連續(xù)按下5~9 s */ 44 else if(xTimeKeyBetween1>btn_5000_PUSH_MS && xTimeKeyBetween1 45 buton_pushed_counter = 50; 46 tx_timer_deactivate(&button_timer); 47 tx_timer_change(&button_timer,10, 10); 48 tx_timer_activate(&button_timer); 49 xTimeKeyRising1 = NULL; 50 xTimeKeyFalling1 = NULL; 51 } 52 /* 4.連續(xù)按下9 s以上 */ 53 else if(xTimeKeyBetween1>btn_9000_PUSH_MS){ 54 buton_pushed_counter = 90; 55 tx_timer_deactivate(&button_timer); 56 tx_timer_change(&button_timer,10, 10); 57 tx_timer_activate(&button_timer); 58 xTimeKeyRising1 = NULL; 59 xTimeKeyFalling1 = NULL; 60 } 61 } 62 /* Clear the EXTI line pending bit */ 63 EXTI_ClearIntBitState(BSP_KEY1_EXTI_LINE); 64 } 65 } 該段代碼的重點是第14行和第19行,分別獲得下降沿和上升沿觸發(fā)時刻的系統(tǒng)時鐘節(jié)拍,并在第22行計算其時鐘節(jié)拍差。在第24行代碼中,利用時鐘節(jié)拍差必須大于100 ms的特點來過濾按鍵觸發(fā)階段的抖動態(tài)。另外,第24~32行代碼在發(fā)生按鍵單按后,buton_pushed_counter增加1,同時設(shè)置軟定時器在800 ms后觸發(fā),目的是等待是否還有下一次短按,從而實現(xiàn)按鍵單按和多按兼并判斷的效果。 剩下其余代碼,均是處理單鍵延時長按的,可對比代碼注釋自行推敲,不再一一贅述。 綜上所述,通過監(jiān)控單個按鍵輸入的電平觸發(fā),配合實時嵌入式操作系統(tǒng)的軟定時器,可以高效地實現(xiàn)在單個按鍵輸入下去抖動、單按、雙按、多按,以及延時長按的不同輸入?yún)^(qū)分處理。本方法不使用延時消抖或等待,不會空占MCU的運行時間,具有很強的實時性。另外,本方法實現(xiàn)原理架構(gòu)是通用的,只要替換幾個重要的系統(tǒng)函數(shù),即可輕松移植到其他實時嵌入式操作系統(tǒng)中,具有較高的推廣價值。 [1] GigaDevice Semiconductor (Beijing) Inc.GD32F207xx_Datasheet_Rev1.01,2015. [2] Express Logic Inc.ThreadX User Guide Version 5.0,2006. 張錫林,從事電梯安全技術(shù)檢驗工作。 General Method for Single Polymorphism in Embedded Operating System Zhang Xilin (Zhuhai Academy of Detection,Guangdong Special Equipment Inspection and Research Institute,Zhuhai 519000,China) In the paper,a general method of single input in the real-time embedded operating system is introduced.The method achieves a single key input to jitter,single click,double press,press and nano second long delay according to the different states of distinguishing and processing through monitoring the key level trigger and the soft timer built in the operating system.The implementation of the method is simple and clear without occupying the microprocessor running time,and can port to the other similar systems such as μC/OS,FreeRTOS,trochili RTOS. real-time embedded system;key processing;GD32F207;ThreadX TP368.1 A (責(zé)任編輯:薛士然2016-03-22)結(jié) 語