一般来说按键可以用一个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; } }
经测试,这两种都能很好的工作,都可以放到主循环中做按键扫描。