引言
在单片机领域中,键盘输入是最常用的人机交互方式。通常实用键盘接口方式有:直接输入、矩阵结构、A/D方式、键盘和显示复用、并行扩展、串口扩充以及用键盘和显示专用控制器件等。但是其中很多方案都需要占用不少单片机有限的I/O口。本文提出一种基于ADC的高性价比键盘输入设计方法。
1ADC按键原理
ADC按键的原理图如图1所示,把多个电阻串联分压,不同的按键将不同的电压进行A/D转换,根据ADC结果,MCU就能识别按键了。例如,key1按下,ADC得到的电压值为:
理论上,只要相邻的两个按键按下时,电压的差值在ADC能最小分辨的电压范围之内,那么MCU就能识别是哪个键被按下了。一个n位的ADC,可以识别2n个不同的电压值,即可以识别2n个按键。例如8位ADC,理论上可以串联256个电阻,识别256个按键。但在实际应用中还要考虑很多的外在因素,如电阻自身的误差、ADC误差、软件计算误差等,因此往往实际能识别的按键的个数小于理论值。
图1ADC按键原理图
2硬件设计
实际的硬件电路如图2所示。为了提高按键响应速度和减轻CPU扫描按键的负担,增加一个比较器,当按键被按下时比较器输出信号触发中断,在中断中第一时间获得键值。这样,既避免了把按键程序放到主程序中循环查询过多而占用CPU资源,又提高了CPU的利用率。当然,为了节省硬件成本,也可以不要比较器。
图2硬件电路图
分压电阻越大越省电,但是实际应用时需要考虑ADC的输入阻抗,不能太大,这里给出经验值10 kΩ。另外,电压比较器还要考虑到运放的特性,为确保第一个键按下时运放同相端电压低于4 V,电阻R1的值就要相对大一些,后面的电阻可以取相同的值。为了减小按键抖动,在电路中串联一个电容C1。当没有键按下时,ADC相当于悬空,需接一上拉电阻。这里R21取220 kΩ。
3软件设计
软件设计是ADC按键的处理核心,一旦检测到的A/D值不准,按键就会得到错误的键值,带来误操作。当按键数目很多时,这种现象会更突出。
ADC按键其实就是一个数据采集过程,软件需要完成数据采集、数据处理、按键解析这3个步骤。首先对按键要有一个认识,它是一个机械开关,在键按下和弹起的过程中很难做到理想的导通和断开,通常有一个抖动过程,需要经过一段时间才能真正地闭合和断开。
在本设计中使用的是自带8路10位ADC的MCU STC90C52AD。驱动起来比较简单,只需要配置几个寄存器就可以进行A/D转换了,并且转换速度很快。ADC代码如下:
sfr P1_ADC_EN=0x97; //A/D转换功能允许寄存器
sfr ADC_CONTR=0xc5; //A/D转换功能寄存器
sfr ADC_DATA=0xc6; //A/D转换结果寄存器高8位
sfr ADC_LOW2=0xc7; //A/D转换结果寄存器低2位
void adc_init(void){
P1 |=0xE0; //将要进行A/D转换的P1.5、
//P1.6、P1.7设置为高
P1_ADC_EN=0xE0; //断开P1.5、P1.6、P1.7口的
//内部上拉电阻
}
unsigned int read_adc(unsigned char channal){
unsigned char ADC_finish=0; //存储A/D转换标志
ADC_CONTR=0x08 | channal;
//选择A/D转换通道与启动ADC
ADC_finish=0;
while(ADC_finish==0) ADC_finish=(ADC_CONTR & 0x10); //ADC_FLAG=1,测试A/D转换是否完毕
ADC_CONTR &=0xF7; //ADC_ARART=0,停止A/D
//转换
return(ADC_DATA);//返回A/D转换结果
}
当键按下时,触发进入外部中断。先延时20 ms,如果有抖动,这个抖动就被有效地滤除掉了。读取第一次ADC值,延时20 ms(有效按键持续时间大于80 ms),再读取第二次ADC的值。只有两次差值在某个小的范围内,这次按键才是有效的,否则就是一次抖动。这几个时间参数是实际测试得到的结果。经过这样的软件处理,机械抖动被有效地滤除掉了。程序代码如下:
delay(20);
temp1=read_adc(7);
delay(20);
temp2=read_adc(7);
if(temp1>temp2) {
if(temp1 temp2<35)temp=(temp1+temp2)/2;
else temp=0;
}
else if(temp1<temp2) {
if(temp2 temp1<35)temp=(temp1+temp2)/2;
else temp=0;
}
else temp=temp1;
经过求平均值后的ADC值也并不是固定不变的,会在某一中心点附近波动。例如重复按下同一个按键,对应一字节的数据为BF C0。若数据有一定的波动,有时还会出现FF 00,说明按键有明显的抖动。通过软件处理,如果ADC两次读到的值相差较大,则确定按键无效。实际完整的键盘方案需要经过多次按键,记下ADC的平均值,建立数组keynum_tab[],再给出一个上下波动范围n,通过ADC的值对比判断,即可得出键值。本例中共有20个按键,程序代码如下:
#define n 4
unsigned char keynum_tab[]={191,186,181,176,172,167,160,152,145, 138,133,126,119,113,103,92,78,61,42,20};
unsigned char i;
for(i=0;i<20;i++) {
if((temp>dat[i]n)&&(temp<dat[i]+n)) keynum=i;
}
结语
本按键方案经过实际运用测试,性能可靠,运行稳定;CPU占用率低,实时性好;只用到一个I/O口,节省了单片机的I/O口资源,并且可以根据实际需要增减按键数量,具有一定的实用价值。
本设计是在湖北师范学院电子电工实验中心田开坤老师的精心指导下,经过小组成员的共同努力完成的。在此特别感谢田老师的指导,以及同学们的帮助。