直接貼上源碼和測試例程,附帶的都有中文註釋很少作解釋。函數
底層驅動:測試
1 #define key_state_0 0 2 #define key_state_1 1 3 #define key_state_2 2 4 #define key_state_3 3 5 6 #define key_no 0 7 #define key_click 1 8 #define key_double 2 9 #define key_long 3 10 11 #define key_input P30 12 /*************************************************************************** 13 程序功能:一個按鍵的單擊、雙擊、長按。三種按鍵方式,而後作不一樣的處理。 14 ***************************************************************************/ 15 16 static unsigned char key_driver(void) 17 { 18 static unsigned char key_state_buffer1 = key_state_0; 19 static unsigned char key_timer_cnt1 = 0; 20 unsigned char key_return = key_no; 21 unsigned char key; 22 23 key = key_input; //read the I/O states 24 25 switch(key_state_buffer1) 26 { 27 case key_state_0: 28 if(key == 0) 29 key_state_buffer1 = key_state_1; 30 //按鍵被按下,狀態轉換到按鍵消抖和確認狀態// 31 break; 32 33 case key_state_1: 34 if(key == 0) 35 { 36 key_timer_cnt1 = 0; 37 key_state_buffer1 = key_state_2; 38 //按鍵仍然處於按下狀態 39 //消抖完成,key_timer開始準備計時 40 //狀態切換到按下時間計時狀態 41 } 42 else 43 key_state_buffer1 = key_state_0; 44 //按鍵已經擡起,回到按鍵初始狀態 45 break; //完成軟件消抖 46 47 case key_state_2: 48 if(key == 1) 49 { 50 key_return = key_click; //按鍵擡起,產生一次click操做 51 key_state_buffer1 = key_state_0; //轉換到按鍵初始狀態 52 } 53 else if(++key_timer_cnt1 >= 100) //按鍵繼續按下,計時超過1000ms 54 { 55 key_return = key_long; //送回長按事件 56 key_state_buffer1 = key_state_3; //轉換到等待按鍵釋放狀態 57 } 58 break; 59 60 case key_state_3: //等待按鍵釋放 61 if(key == 1) //按鍵釋放 62 key_state_buffer1 = key_state_0; //切回按鍵初始狀態 63 break; 64 } 65 return key_return; 66 } 67 68 /*************************************************************************** 69 函數功能:中層按鍵處理函數,調用底層函數一次,處理雙擊事件的判斷, 70 返回上層正確的無鍵、單擊、雙擊、長按四種狀態 71 本函數由上層循環調用,間隔10ms 72 ***************************************************************************/ 73 unsigned char key_read(void) 74 { 75 static unsigned char key_state_buffer2 = key_state_0; 76 static unsigned char key_timer_cnt2 = 0; 77 unsigned char key_return = key_no; 78 unsigned char key; 79 80 key = key_driver(); 81 82 switch(key_state_buffer2) 83 { 84 case key_state_0: 85 if(key == key_click) 86 { 87 key_timer_cnt2 = 0; //第一次單擊,不返回,到下個狀態判斷是否會出現雙擊 88 key_state_buffer2 = key_state_1; 89 } 90 else 91 key_return = key; //對於無鍵、長按,返回原事件 92 break; 93 94 case key_state_1: 95 if(key == key_click) //又一次單擊,時間間隔小於500ms 96 { 97 key_return = key_double; //返回雙擊事件,回到初始狀態 98 key_state_buffer2 = key_state_0; 99 } 100 else if(++key_timer_cnt2 >= 50) 101 { 102 //這裏500ms內確定讀到的都是無鍵事件,由於長按大於1000ms 103 //在1s前底層返回的都是無鍵 104 105 key_return = key_click; //500ms內沒有再次出現單擊事件,返回單擊事件 106 key_state_buffer2 = key_state_0; //返回初始狀態 107 108 } 109 break; 110 } 111 112 return key_return; 113 }
測試例程(基於51內核)spa
1 void main(void) 2 { 3 u8 cnt_1ms=0,cnt_100ms=0; 4 u8 key_value = 0; 5 u8 led_flash=0; 6 GPIO_Configuration(); 7 P3M1 &= ~(1<<0);P3M2 &= ~(1<<0); //P30準雙向 8 P1M1 &= ~(1<<2);P1M2 |= (1<<2); //P12推輓 9 10 P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed(); 11 P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed(); 12 P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed(); 13 P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed(); 14 15 enableInterrupts(); 16 IWDG_Configuration(); 17 while(1) 18 { 19 if(++cnt_1ms>=10) 20 { 21 cnt_1ms=0; 22 key_value = key_read(); 23 if(key_value != key_no) led_flash = key_value*2; 24 } 25 if(++cnt_100ms>=100) 26 { 27 cnt_100ms=0; 28 if(led_flash) 29 { 30 led_flash--; 31 P12 = ~P12; 32 } 33 } 34 } 35 }