按键消抖与时间按键
case 0xef:return 5;break;
case 0xdf:return 6;break;
case 0xbf:return 7;break;
case 0x7f:return 0;break;
}
}
}
定时器函数
void timer0 ()interrupt1
TR0=1;
if(T>100)
{
TR0=0;
T=0;
}
if(TR0=1&&T<100)
continue;//在定时器里面设置初值让定时器中断一次1ms并且T自加1,100次就100ms
switch(key)
{//返回键值
case 0xfe:return 1;break;
case 0xfd:return 2;break;
消抖分硬件和软件消抖,
硬件消抖有《模拟电子技术》上提到用三态门实现,当然还有周立功那个7920(管理数码管和按键的芯片),当然还有很多硬件电路以及一些按键有自带消抖电路,但是如果要做产品硬件消抖肯定会增加成本,一般都会考虑软件消抖
软件消抖我们先来看看书上消抖方法如下图
例程
Unsignedchar keyscan()//这里是用的P2口作为按键的输入口
第4个问题了,从物理上我们可以知道,既然是阻尼振动,必定到振动到某个时候肯定是和稳定的状态一致的,所以肯定不是必须10ms的延时的,比如按下去假设10ms振动后机械才稳定,但是电平上当触点挨得很近振动的时候就算触点不是挨着,还是显示低电平
第5个问题实际上前面已经说了,有硬件消抖肯定对CPU占用最少,软件消抖当然就是尽量不要用些没用的语句,分配好时序
2.如何消抖
3.是不是按键都要消抖,不是的话,哪些需要消抖,哪些不需要消抖
4.消抖的时间是不是必须10ms
5.按键消抖的方式是不是一定像书上的那样,如何消抖更节省CPU,且更简单
按键如果不消除抖动,那么单片机检测到的低电平的次数就不止一次,那我们按键一次,单片机会检测到多次,比如我们把按某个按键设置按一次成某个变量加1,结果按一次就加了很多次,这样我们就不能精确的通过按键来调整我们想要的参数,所以我们消除抖动的目的就是要实现按一次按键让单片机读出一次按键操作
{
TH0=(66636-1000)/256;//对应12M晶振是1ms
TL0=(66636-1000)%256;
T++;
}
至于定时器初始化和主函数就不需要我一一说明了吧,初学单片机一般都会先学到中断里面就有定时器中断
前面是用的定时器作为时间,书上用的空语句作为延时时间,其实我们写的其他和扫描不相关的语句还是可以作为延时;这就是我的第二种方法:
接下来我们来讨论时间按键,什么叫时间按键?
就是通过按键的时间长短来执行不同的功能,不如手机关机键,大概在按键按住3s后就会提示或直接关机,按一下就直接是关闭背光,再比如我们要设置一个参数,本来按一下只加1,我们要设置上百次或者上千次怎么办,可以按住时间比较长以后直接快速的加或者快速的减,时间按键是首选了了呀是不是呀,当然还可以加一个位选键直接设置对应的位也可以,不过要增加按键
{
Unsigned char key;//定义按键的键值变量
if(P2!=0xff)
{
delay(10);//延时10ms
key=P2;
while(P2!=0xff)
delay(10);//延时10ms
switch(key)
{//返回键值
case 0xfe:return 1;break;
case 0xfd:return 2;break;
现在我就来说一下这是怎么实现的吧
在说按键消抖的时候,书上的例程里面有一个等待按键释放,用的while语句,等待的时候是用的空语句;即是按下去一直执行空语句,放开之后才返回键值,是不是对大家已经有了提示呀:就是直接在检测到按键按下去以后直接执行要执行的语句然后做一个时间内不检测键值或者延时来控制按键的执行的速度
用写好的其他函数作为延时时间控制时序,执行一次扫描后执行其他函数占用100ms左右
这个历程因为有其他函数,只有在编程序的时候才来考虑了用些什么函数语句,这里就不列了哈
第一种方法是大多数情况都能用,这种方法是利用CPU效率比较高的一种(说不定谁做出更牛的,所以就不说最牛的了,当然希望大家能做出更高效率的程序了,哈哈),因为CPU没有执行空语句之类的一些没用的语句,但是必须控制后面所执行的程序是百ms级的所以不是每个程序都能用
还有一种硬件加软件的方法
在所有的按键上接IO口的线上并联一根线接到与门上,与门的另一端接外中断输入口,然后在外中断函数里面扫描键值,当然效率还行,不过加了硬件还要用软件成本上升了不说软件上还要外中断,按键少的时候可以没问题,多了就麻烦了,特别是独立按键,不经济也不好用,但是特别情况还是可以考虑
第3个问题当然肯定不是所有的按键都要消抖的,比如说我们设置按键是按了按键实现电机转动,没有其他功能了,不管抖动几次,只要开启了就不会关闭嘛,是不是呀,嘿嘿,或者设置成按键按一次后关闭,就算抖动,电机关闭了一次就已经关闭了,再关闭还是关闭状态是不是呀
为了节省CPU这里就不用延时函数了,看看下面的例程
Unsignedchar keyscan()//这里是用的P2口作为按键的输入口
{
Static T=0;
Unsigned char key;//定义按键的键值变量
if(P2!=0xff)
{
key=P2;
while(P2!=0xff)
{
if(TR0=0)
要提高首先要把软件延时换成定时器,或者不用这种方法
下面介绍我自己改进的两种方法
首先我们消抖的目的就是为了按键一次只让单片机采集到一次按键操作,所以我就让单片机采集到一次操作以后不再检测,当然是在按键时间内,前面提到人按键一次操作数百ms,所以这儿我们可以再检测到一次按键后打开定时器,在数百ms内不再检测
从上面这两个例子我们可以看出:按键只要设置的一些单一的功能就算出现抖动也不会影响我们设置的功能;假如我们设置的按键一次实现数码管显示的数字加1,那没有加消抖的话单片机会读到好几次按键,那我们按一次出现的结果就是加3或者加4或者某个未知数X了哦,又假如,我们的按键功能是按一次实现led灯打开,再按一次实现led灯关闭,这个是一个按键2个功能了,假设现在状态是led开启的,我们想关闭它,没有消抖的话,单片机读出来的按键次数是个未知数X,X是3,5,7之类的奇数还好能关闭,如果X是偶数的话,那我们不管按多少次那个led灯是不是都开启的呀,由上面两个例子可以看出:按键设置的如果是重复操作或者一个按键有2个以上的功能就必须消抖了
case 0xfb:return 3;break;
case 0xf7:return 4;break;
case 0xef:return 5;break;
case 0xdf:return 6;break;
case 0xbf:return 7;break;
case 0x7f:return 8;break;
continue;//在定时器里面设置初值让定时器中断一次1ms并且T自加1,100次就100ms
switch(key)
{//返回键值
case 0xfe:return 1;break;
case 0xfd:return 2;break;
case 0xfb:return 3;break;
case 0xf7:return 4;break;
(上面的时间都是老师说的和书上现成的,没有实际测试,而且不同的按键应该也会有差异,作为学习研究确实不应该,找个时间锅锅会测出这个时间供大家参考,嘿嘿)
由图我们可以看出,按下去瞬间会出现抖动,弹起来也会出现抖动,明显是个阻尼振动,按键扫描程序是按顺序执行的;
首先提出三个问题大家思考一下
1.为什么要消除抖动
按键消抖与时间按键
这篇文章写给正在学51单片机的或者刚入门51单片机准备进阶的的朋友,我们来着重讨论一下按键消抖和时间按键这两项。
我们常用的按键大多都是机械的,机械开关就会出现机械振动,这个由物理学或者实验可以推出来,抖动会在单片机上面出现重复扫描次数,次数多少与单片机的时钟晶振有关,时钟晶振越高单片机执行速度越快,重复次数就越多
default:return 0;break;
}
}
}
当然延时函数delay肯定要写才能用这个函数
void delay(unsigned char x)//对应12M的晶振是1ms
{
unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<10*x;j++)
;
}
这个消抖里面有延时函数如果时序处理不好就要出问题;被我们单片机老师称为“弱智程序”,原因就是用了软件延时(软件延时会占用CPU资源),当然对于刚入门还是可以学一下,很容易理解,方便以后提升(学习嘛当然由易到难还是值得推荐的)
Unsignedchar keyscan()//这里是用的P2口作为按键的输入口
{
Static T=0;
Unsigned char key;//定义按键的键值变量
if(P2!=0xff)
{
key=P2;
while(P2!=0xff)
;
if(TR0=0)
TR0=1;
if(T>100)
TR0=0;
if(TR0=1&&T<100)
case 0xfb:return 3;break;
case 0xf7:return 4;break;
case 0xef:return 5;break;
case 0xdf:return 6;break;