非阻塞式读取矩阵按键
这个教程是在电协培训新生的一点点心得,旨在解决许多人学习单片机,对按键的一个困惑:按键的非阻塞式消抖。如何在不消耗很多时间的情况下,有效地消抖,具有非常实际的意义。
本文就把一个循序渐进的对按键处理的理解记录下来,方便大家学习,由于本人已投入半导体器件的学习,很久没有接触数字电路,如有错误,还请读者指出。
本文注重方法的连续演化,遵循事物的发展规律,如需要计数式非阻塞矩阵按键读取方法,直接翻到最后即可,最后我将给出本文所讲的所有代码,屏蔽掉,稍加修改端口可以在51单片机上实现,体会每种方法的利弊,和更好的方法的思想。
另外我将给出一个应用,证明非阻塞,特征次数可变的按键检测的优势。
1、按键的基本读取
如上图,是单片机常用的两种开关,其内部结构,由于弹性金属触点的接触,进而触发了两个引脚的开路和短路。
独立按键的检测原理:
从单片机核心板的原理图上可以看到,在按键未按下时,KEY是断开的,单片机IO口通过限流电阻与VCC相连,则IO口处于被拉高的状态。
按键被按下时,则KEY接通,电阻右端为理想的0V状态,IO口接在电阻右端,处于被拉低的状态。
单片机通过读这些引脚状态就能够判断按键处于什么状态。
根据这个思想,代码如下:
void main(void)
{
while (1)
{
if (key0 == 0)
{
led = !led;
}
}
}
2、delay延时消抖:解决抖动问题
上面的代码,效果不好?那一定是按键消抖的问题
通常按键所用的开关都是机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹 性作用,一个按键开关在闭合时不会马上就稳定的接通,在断开时也不会一下子彻底断开, 而是在闭合和断开的瞬间伴随了一连串的抖动。
那么,如何消抖呢?
一种是硬件消抖,用电容导走信号的高频分量,也就是抖动部分。
另一种就是软件消抖:
void main(void)
{
while (1)
{
if (!key0)
{
delay_ms(10);
if (!key0)
{
led = !led;
//while (!key0);
}
}
}
}
这种方法也有弊端,不用while卡住,那么按住按键,则每次都会进入循环,大多数应用情景,我们都希望按一次按键,单片机做一次响应,用了while,那么主循环就会卡在这里不能往下进行,这对于大多数情况下都是致命的,应该尽量避免。
3、标志位:解决单次按下难题
这种方法基于上面提到的问题做了改进,主要思想是定义一个变量,储存按键的状态,只有在弹起状态的时候按下,才算做一次有效按下,在else if中更新为按键弹起状态。
void main(void)
{
unsigned char key0_stat;
while (1)
{
if (key0_stat == 1 && key0 == 0)
{
delay_ms(10);
key0_stat = 0;
led = !led;
}
else if (key0_stat == 0 && key0 == 1) key0_stat = 1;
}
}
4、 计数:解决阻塞问题
上一种方法已经能用,但是远远称不上好用,为什么?因为那个10ms的延时,我们说延时的目的是为了避开那个我们处理不了的抖动过程,但是延时必然有弊端,尤其是这种延时这么长时间,什么事都不干,无论从系统实时性角度,还是资源利用率角度,都是不能允许存在的。那么有没有别的方法避免呢?
上面的图,展示了按键从按下到松开,单片机以较高频率采集IO口状态的过