和我一起学51单片机(3)——不用定时器的非阻塞延时消抖?
文章目录
- 和我一起学51单片机(3)——不用定时器的非阻塞延时消抖?
- 前言
- 一、什么是非阻塞延时?
- 二、非阻塞到底关键在哪?
- 三、代码实现
- 总结
前言
笔者食言了。。。。。。
再写一篇51吧
建议明白定时器非阻塞延时之后再看
定时器的非阻塞延时
一、什么是非阻塞延时?
非阻塞延时是利用CPU对计数值加/减,计数值达到设定值才证明延时时间到,CPU对计数值进行一次操作后就可以跳出来执行其他任务了,不会“卡死”在某个代码处。
二、非阻塞到底关键在哪?
延时是为了渡过那段按键抖动的时间,阻塞延时时,为了不直接检测,使用了延时函数,但是代码也无法持续运行了。
其实相当于小明在吃饭,吃着吃着必须停止20秒再吃。那么我只要实现停止20s吃饭就可以了,期间干啥都行。
这时通常会使用中断函数去实现,(1)定义一个变量,(2)在中断里不断++,(3)等到时间了给标志位,(4)在while里面实现按键检测。不过这就消耗了定时器的资源。
所以,既然不用定时器,那我们就没有定时器中断,除了(1)不能实现,其他都可以实现。那么这时我们其实也可以在while里面++。就解决了所有问题,不过是没有那么准确罢了。
三、代码实现
if(key==0&&flag1==0)
{
hd1++;
if(hd1>=10)
{
hd1=0;
flag1=1;
}
}
else if(key==1&&flag1==1)
{
ld1++;
if(ld1>=10)
{
ld1=0;
//要执行代码放这里
flag1=0;
}
}
分块解释
if(key==0&&flag1==0)
{
hd1++;
if(hd1>=10)
{
hd1=0;
flag1=1;
}
}
当你按键按下的时候,因为抖动你会瞬间有一个低电平,(并且不止一次)这时你就满足判断条件进来了第一个if。然后就给计时变量hd1不断++,经过一段时间后你将hd1清零,并把标志位flag1置1。
else if(key==1&&flag1==1)
{
ld1++;
if(ld1>=10)
{
ld1=0;
//要执行代码放这里
flag1=0;
}
}
当为高电平时候,说明进入第二次消抖了。道理同上
但是值得注意的是
hd1是需要根据你while中的代码数量而修改的,一般是1-10,大于10的话,可以考虑以5或者10步进(悲)
而且
如果你这是也开了定时器,并且频率开的很高,你就要把这一大段按键检测代码放在一个函数里面keyscan(),并且要在while里边多放几个keyscan(),但是值得庆幸的是不会影响其他代码正常进行(喜)
魔幻:其实很多时候,你不用阻塞法只是不想让数码管闪,也可以用数码管当延时,10ms遍历一次数码管,一举两得(严肃)
如下
先不要害怕,这是因为笔者这个代码里面用了五个中断,主函数的while几乎没有生存空间(悲)
while(1)
{
if(changeflag)
{
endflag++;
}
keyscan();
keyscan();
F_OP=50+x1;
FM_OP=50+x1;
phase_OP=72+x2;
compute_OP(F_OP,D_OP,FM_OP,DM_OP,T_OP);
keyscan();
compute();
keyscan();
keyscan();
show();
keyscan();
keyscan();
keyscan();
send();
keyscan();
keyscan();
keyscan();
serial();
keyscan();
keyscan();
if(P2_0==1&&P2_1==0)
{
break;
}
}
总结
其实用定时器实现非阻塞延时也不错,但是如果你在做有关PWM或要求中断十分精简的时候,中断里面一般不允许塞太多东西,这时用while的优势就体现出来了。