背景了解:
按照传统的按键检测方法就是一个按键对应一个GPIO口,进行高低电平输入检测。可是在GPIO口紧缺的情况下,不得不需要一个有效的解决方案,借鉴网上的资料了解到一个简单的方法,希望分享一下。
ADC检测实现简单实用的按键方法:仅需要一个ADC和若干个电阻就可实现多个按键的输入检测。工作原理:按下按键时,通过电阻分压得到不同的电压值,ADC采集在各个范围内的值来判定是哪个按键按下。
实践方案:
摘录网上的图片:
根据上述电路,4个1K的电阻串联后,节点的位置分别接有按键K1,K2,K3,K4,那么按键单独按下,单片机ADC依次检测到3.7V,3.33V,2.5V,0V,只要将分压值用数组保存起来。补充:没有按键按下时:ADC检测为5v。
通过查表法,就可以实现按键检测,在按键检测的过程中也需要进行按键消抖处理。
简单代码示例:
/***************************************************************************************************************************
*功能描述:ADC采集多个按键
*输入参数:无
*输出参数:无
*返回参数:非0为按下按键数,0:无按键按下
****************************************************************************************************************************/
unsigned float Sample_Volt[] = {3.75,3.33,2.5,0}; //对应上图K1,K2,K3,K4,AD口所采集到的电压值,供查表。
unsigned char ADC1_KeySample(void)
{
unsigned float KeyVolt = ADC1_GetVolt();//ADC1_GetVolt为采集到按键电压函数,如果是八位单片机考虑浮点运算压力,可以使用采集ADC模拟量来进行判断
for(unsigned char i = 0; i < 4; i++)
{
if((KeyVolt >= Sample_Volt[i] - 0.2) && KeyVolt <= Sample_Volt[i] + 0.2) //允许电压偏差正负0.2V,但还是会存在由于电源不稳导致误判断
return i + 1;//返回按键数
}
return 0;//返回0:无按键按下
}
电路图存在隐患:按键不能串在分压回路里,分压检测需要各自独立,按键只需连接各分压点和ADC输入点,这样因为ADC的输入阻抗比较大,按键的接触电阻对电阻分压的影响较小,缺点:分压回路会一直消耗电流,对电源耗电不利。
改进方案:
硬件改进:
1、在ADC按键的基础上,可用增加二极管的方式,实现按键中断,并在中断服务程序里进行AD转换,从而识别按键。
2、按键消抖,给按键并联一个104左右的电容,软件上基本不用处理即可避免抖动。
软件改进:
将按键扫描放到定时器中断里面,这样就可周期性地检测按键按下情况,不受主循环的影响。使用按键检测状态机能解析出按键的不同状态,即短按,长按等状态,用以实现更丰富的功能。但需注意两点,一是定时器的定时时间,不可过长也不可过短,过长容易检测不到按下,过短会占用大量时间资源。二是中断服务程序需简单明了,只做检测用,通过全局变量传递,在主循环内完成按键响应,中断服务函数内尽量不要占用太多时间。
欢迎读者交流上述按键方案存在的不足之处,并提出行之有效的改进方案进行分享,不甚感激!!!