一般來說按鍵可以用一個ADC通道來做按鍵的掃描工作,根據各個按鍵上的下拉電阻不同而識別不同種的按鍵狀態,在按鍵數不多且不適合做矩陣鍵盤的時候而且按鍵數又不可忽略的占用過多的IO口這個時候可以使用ADC掃描來做按鍵的掃描。普通情況下一個按鍵可用普通IO口或者ADC端口做按鍵掃描。
如圖,按鍵的AD掃描原理圖分配。
普通IO口掃描按鍵
AD按鍵掃描與長短按鍵可以用如下的C代碼實現:
1 typedef unsigned char u8; 2 typedef unsigned int u16; 3 void AdcInit(void); 4 u16 AdcConverts(unsigned char Channel); 5 u8 KeyRead(void)//讀取鍵的狀態 6 { 7 u16 keyAdcValue = 0; 8 keyAdcValue = AdcConverts(KEY_CHANNEL); 9 if ((keyAdcValue < (KEY0_ADC + KEY_ADC_DELTA)) && (keyAdcValue >(KEY0_ADC - KEY_ADC_DELTA))){ 10 return KEY_0; 11 } 12 else if ((keyAdcValue < (KEY1_ADC + KEY_ADC_DELTA)) && (keyAdcValue >(KEY1_ADC - KEY_ADC_DELTA))){ 13 return KEY_1; 14 } 15 else if........ 16 } 17 else{ 18 return KEY_NULL; 19 } 20 } 21 void KeyScan(void) 22 { 23 static unsigned char g_ucLastKeypad, KeyNum, ShortKey, LongKey; 24 static unsigned char KeyValue = KEY_NULL; 25 unsigned char KeyStatus = 0; 26 KeyStatus = KeyRead(); 27 ShortKey = ShortKey; 28 LongKey = LongKey; 29 if(g_ucLastKeypad == KEY_NULL && KeyStatus != g_ucLastKeypad){ //按鍵剛被按下 30 KeyNum = 0; 31 ShortKey = 0; 32 LongKey = 0; 33 KeyValue = KEY_NULL; 34 } 35 else if(KeyStatus == g_ucLastKeypad && KeyStatus != KEY_NULL){ //按鍵正被按着 36 KeyNum++; 37 if(KeyNum == KEY_LONG_TIMES){ 38 ShortKey = 0; 39 LongKey = 1; 40 KeyValue = g_ucLastKeypad; 41 } 42 } 43 else if(KeyStatus == KEY_NULL && KeyStatus != g_ucLastKeypad){ //按鍵被放開 44 if(KeyNum < KEY_LONG_TIMES && KeyNum > KEY_SHORT_TIMES){ 45 KeyNum = 0; 46 ShortKey = 1; 47 LongKey = 0; 48 KeyValue= g_ucLastKeypad; 49 } 50 } 51 else{ 52 KeyNum = 0; 53 ShortKey = 0; 54 LongKey = 0; 55 KeyValue = KEY_NULL; 56 } 57 g_ucLastKeypad = KeyStatus; 58 60 }
普通IO口的按鍵的長短按也可以利用AD的識別來做,唯一不同就是按鍵掃描方式不一樣。下面給出一個按鍵識別實例。
u8 KeyScan(void)//0為無按鍵按下,1為短按,2為長按。 { static u8 Press_Flag=0,g_Press_Flag=0,ReturnFlag=0; static u16 KeyNum=0; u8 KeyStatus=0; KeyStatus=ReadGPIOKey(); if(Press_Flag==0) { if(KeyNum<1) { KeyNum++; if(KeyStatus==0) KeyNum=0; return 0; } else { KeyNum=0; Press_Flag=1; return 0; } } else { if(KeyNum <= 15) { if(KeyStatus==1) { KeyNum++; return 0; } if(g_Press_Flag<1) { if(KeyStatus==0) g_Press_Flag++; } else { Press_Flag=0; g_Press_Flag=0; KeyNum=0; return 1; } } else if(KeyNum < 400 && KeyNum >15) { if(KeyStatus==1) { KeyNum++; return 0; } if(g_Press_Flag<1) { if(KeyStatus==0) g_Press_Flag++; } else { Press_Flag=0; g_Press_Flag=0; KeyNum=0; return 2; } } else if(KeyNum >= 400) { if(KeyStatus==1) { if(ReturnFlag==0) { KeyNum++; ReturnFlag=1; return 3; } } if(g_Press_Flag<1) { if(KeyStatus==0) g_Press_Flag++; } else { Press_Flag=0; g_Press_Flag=0; ReturnFlag=0; KeyNum=0; return 0; } } return 0; } }
經測試,這兩種都能很好的工作,都可以放到主循環中做按鍵掃描。