張錫林
(廣東省特種設(shè)備檢測(cè)研究院 珠海檢測(cè)院,珠海 519000)
?
嵌入式操作系統(tǒng)下“單鍵多態(tài)”的通用處理方法
張錫林
(廣東省特種設(shè)備檢測(cè)研究院 珠海檢測(cè)院,珠海 519000)
介紹了一種在實(shí)時(shí)嵌入式操作系統(tǒng)平臺(tái)上單鍵輸入的通用處理方法。該方法通過(guò)監(jiān)控按鍵的電平觸發(fā),配合操作系統(tǒng)內(nèi)置的軟定時(shí)器,高效實(shí)現(xiàn)了單個(gè)按鍵輸入時(shí)去抖動(dòng)、單按、雙按、多按,以及納秒延時(shí)長(zhǎng)按的不同狀態(tài)區(qū)分處理。該方法實(shí)現(xiàn)原理清晰簡(jiǎn)單,不占用微處理器運(yùn)行時(shí)間,并且可移植到等其他類(lèi)似的系統(tǒng)中(如μC/OS、FreeRTOS、trochili RTOS),具有較高的應(yīng)用價(jià)值。
實(shí)時(shí)嵌入式系統(tǒng);按鍵處理;GD32F207;ThreadX
隨著ARM公司推出的Cortex系列32位處理器迅速在智能測(cè)量、人機(jī)接口、汽車(chē)工業(yè)、控制系統(tǒng)、家用電器等應(yīng)用場(chǎng)合得到廣泛的應(yīng)用,為了更合理地調(diào)度多任務(wù),高效利用系統(tǒng)資源、系統(tǒng)函數(shù)以及與專用庫(kù)函數(shù)的接口,通常使用實(shí)時(shí)嵌入式操作系統(tǒng)作為開(kāi)發(fā)平臺(tái),這樣既保證了程序執(zhí)行的實(shí)時(shí)性,又減少了產(chǎn)品開(kāi)發(fā)時(shí)間,提高了軟件的維護(hù)性,縮短了新設(shè)備的上市時(shí)間。
在該系統(tǒng)的應(yīng)用開(kāi)發(fā)中,經(jīng)常遇到需要在單個(gè)按鍵內(nèi)實(shí)現(xiàn)單按、雙按、多按、延時(shí)長(zhǎng)按等多種組合的功能。本文以兆易創(chuàng)新(GigaDevice)公司的入門(mén)級(jí)開(kāi)發(fā)板GD32-Colibri-F207ZE(下稱GD32F207ZE)作為硬件平臺(tái),并通過(guò)ExpressLogic公司的商用高性能實(shí)時(shí)嵌入式操作系統(tǒng)——ThreadX測(cè)試版作為軟件開(kāi)發(fā)平臺(tái),實(shí)現(xiàn)了這些功能。
在大多數(shù)常見(jiàn)的按鍵輸入處理方法中,通常方法是監(jiān)控輸入端口的單一電平變化。而本方法同時(shí)還監(jiān)控了按鍵輸入電平的兩種變化——從高電平變?yōu)榈碗娖交蛘邚牡碗娖阶優(yōu)楦唠娖剑⑼ㄟ^(guò)處理器輸入I/O的上升沿觸發(fā)和下降沿觸發(fā),分別在中斷服務(wù)函數(shù)里面取得其觸發(fā)時(shí)刻的系統(tǒng)時(shí)鐘節(jié)拍,從而計(jì)算出兩種觸發(fā)變化時(shí)刻的時(shí)鐘節(jié)拍差異,判斷出按鍵輸入的類(lèi)型,并通過(guò)一個(gè)全局變量傳遞至預(yù)先設(shè)置激活的軟定時(shí)器函數(shù)里,最終由軟定時(shí)器函數(shù)實(shí)現(xiàn)不同的按鍵處理。
2.1按鍵輸入電路

圖1 按鍵輸入電路及信號(hào)
按鍵輸入電路及信號(hào)如圖1所示,按鍵KEY1連接至微處理器GD32F207ZE的PD14輸入端口,并通過(guò)一個(gè)上拉電阻R30將輸入信號(hào)的初始穩(wěn)定狀態(tài)鉗位到高電平。當(dāng)按鍵KEY1觸發(fā)后,會(huì)呈現(xiàn)圖1(b)的實(shí)際電平信號(hào)。可以看出,在輸入信號(hào)電平切換過(guò)程中,均有一段電平信號(hào)的抖動(dòng)過(guò)程,需使用處理程序?qū)ζ溥M(jìn)行過(guò)濾。
2.2處理結(jié)果輸出電路

圖2 按鍵處理輸出電路
GD32F207ZE開(kāi)發(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ū)動(dòng)3個(gè)LED的I/O均設(shè)置為普通推挽輸出,同時(shí)將按鍵KEY1的I/O設(shè)置為懸空輸入,即在處理器芯片內(nèi)部既沒(méi)有接上拉電阻,也沒(méi)有接下拉電阻,其工作電平由外部電路決定(根據(jù)圖1,其穩(wěn)定初始狀態(tài)為高電平)。需注意兩點(diǎn),在第30行代碼中,把按鍵KEY1的中斷觸發(fā)模式設(shè)置為上升沿和下降沿均引起中斷觸發(fā),這是整個(gè)實(shí)現(xiàn)方法中的關(guān)鍵;在第10行代碼中,由于使用了按鍵輸入端口PD14的中斷功能,因此需要將其復(fù)用功能RCC_APB2PERIPH_AF的時(shí)鐘同時(shí)開(kāi)啟。
2.4ThreadX軟定時(shí)器函數(shù)
ThreadX軟定時(shí)器函數(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行代碼是實(shí)時(shí)嵌入式操作系統(tǒng)ThreadX的系統(tǒng)函數(shù),功能是建立一個(gè)按鍵處理的軟定時(shí)器,并處于關(guān)閉狀態(tài)。其中在該定時(shí)器函數(shù)中,buton_pushed_counter是一個(gè)UINT類(lèi)型的全局變量,它由以下的按鍵中斷服務(wù)函數(shù)賦值,傳遞不同的按鍵輸入類(lèi)型到這里進(jìn)行判斷并分別處理。由代碼可以看出,處理結(jié)果就是分別切換開(kāi)發(fā)板上板載的3顆不同顏色的LED的狀態(tài)。另外在處理完畢后,務(wù)必將buton_pushed_counter設(shè)置為0,并關(guān)閉定時(shí)器。
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 } 該段代碼的重點(diǎn)是第14行和第19行,分別獲得下降沿和上升沿觸發(fā)時(shí)刻的系統(tǒng)時(shí)鐘節(jié)拍,并在第22行計(jì)算其時(shí)鐘節(jié)拍差。在第24行代碼中,利用時(shí)鐘節(jié)拍差必須大于100 ms的特點(diǎn)來(lái)過(guò)濾按鍵觸發(fā)階段的抖動(dòng)態(tài)。另外,第24~32行代碼在發(fā)生按鍵單按后,buton_pushed_counter增加1,同時(shí)設(shè)置軟定時(shí)器在800 ms后觸發(fā),目的是等待是否還有下一次短按,從而實(shí)現(xiàn)按鍵單按和多按兼并判斷的效果。 剩下其余代碼,均是處理單鍵延時(shí)長(zhǎng)按的,可對(duì)比代碼注釋自行推敲,不再一一贅述。 綜上所述,通過(guò)監(jiān)控單個(gè)按鍵輸入的電平觸發(fā),配合實(shí)時(shí)嵌入式操作系統(tǒng)的軟定時(shí)器,可以高效地實(shí)現(xiàn)在單個(gè)按鍵輸入下去抖動(dòng)、單按、雙按、多按,以及延時(shí)長(zhǎng)按的不同輸入?yún)^(qū)分處理。本方法不使用延時(shí)消抖或等待,不會(huì)空占MCU的運(yùn)行時(shí)間,具有很強(qiáng)的實(shí)時(shí)性。另外,本方法實(shí)現(xiàn)原理架構(gòu)是通用的,只要替換幾個(gè)重要的系統(tǒng)函數(shù),即可輕松移植到其他實(shí)時(shí)嵌入式操作系統(tǒng)中,具有較高的推廣價(jià)值。 [1] GigaDevice Semiconductor (Beijing) Inc.GD32F207xx_Datasheet_Rev1.01,2015. [2] Express Logic Inc.ThreadX User Guide Version 5.0,2006. 張錫林,從事電梯安全技術(shù)檢驗(yàn)工作。 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é) 語(yǔ)