单片机开发独立按键扫描最最最最最精简代码篇

单片机开发独立按键扫描最最最最精简代码篇

前言

以下是我在学习嵌入式蓝桥杯开发中遇到了一个算法,不需要传统的延时消抖,也不需要加标志位的长篇大论的按键消抖,只需要三行语句即可解决你对独立按键的看法,那就不吹牛进入主题。

C语言算法简化表达式

对!!!你没看错只需要三行你就可以实现无数个独立按键的扫描操作,下面我们对这个算法进行展开分析。

//其中Trg:触发,Cont:连续按下
unsigned char Trg;
unsigned char Cont;
void KeyRead(void)
{
	unsigned char ReadData = PINB^0xff; //算法一
	Trg = ReadData & (ReadData ^ Cont); //算法二
	Cont = ReadData;					//算法二
}
算法一:我们使用的是八个按键进行扫描时,我们
采用与0xff异或的方式,根据异或的表达式含义:相
同为0,不同为1,所以我们在表达式使用1111 1111
与我们对应按键的PB口进行相异或,实现的效果就是
取反的效果。
例:当我们读到的IO口为PB=0X01时,我们与0XFF相
异或后读到的结果ReadData的值为0XFE, 也就是将
PB进行了取反的操作,其他IO口类似于此功能。其次
此算法完全可以用取反操作进行,然后送入下一步。
算法二:根据表达式可以看出来,首先是将ReadData
与Cont进行异或操作,当我们第一次按下的时候,Cont
记录的是上一次的ReadData数值,第一次按下前PB=0XFF,
所以得到ReadData=0X00,也就是第一次按之前ReadData=0X00。
第一次按下:PB=0XFE,ReadData=0X01,与Cont异或得到结果
(ReadData ^ Cont)=0X01然后再与自己相与得到0X01,最后将数值存进Cont中。
(1)第一次按下松开:松开后,此时PB=0XFF,ReadData=0X00,进入算法二后,
Trg = 0X00 & (0X00 ^ 0X01) = 0X00;
Cont = 0X00;
结果:
ReadData = 0x01;
Trg = 0x01;//Trg只会在这个时候对应位的值为1,其它时候都为0
//所以按键就利用这个特性,实现按键消抖。
Cont = 0x01;
以上结果显示,按键松开,此时所有变量都回到了最初的状态。
(2)第一次按下没有松开:按键持续在按下的状态,根据算法得出各个表达式的数值。
此时PB=0XFE,ReadData=0X01,进入算法二后,Trg = 0X01 & (0X01 ^ 0X01);
计算括号中的根据异或的性质,相同为0,不同为1,得出数值为:0x00,然后再进行按位与得到结果Trg=0X00;
结果:
ReadData = 0x01;
Trg = 0x00;
Cont = 0x01;
因为现在按键是长按着,所以MCU会不断的执行这个函数,那么下次执行的时候
情况会是怎么样的呢?
ReadData = 0x01;//这个不会变,因为按键没有松开
Trg = ReadData & (ReadData ^ Cont)0x01 & (0x01 ^ 0x01) = 0 
只要按键没有松开,这个Trg值永远为 0 !!!
Cont = 0x01;只要按键没有松开,这个值永远是0x01!!!

总结

以上算法可以利用在各大可以执行MCU上,算法可以一直在各种语言上面。
不知道以上的解释懂了没有?其实原理很简单,答案如下:
Trg 表示的就是触发的意思,也就是跳变,只要有按键按下(电平从10的跳变)
那么Trg在对应按键的位上面会置一,我们用了PB0则Trg的值为0x01。
类似,如果我们PB7按下的话,Trg的值就应该为 0x80,这个很好理解。
最关键的地方,Trg 的值每次按下只会出现一次,然后立刻被清除,完全不需要人工
去干预。所以按键功能处理程序不会重复执行,省下了一大堆的条件判断--精粹。
Cont代表的是长按键,如果PB0按着不放,那么Cont的值就为 0x01,
相对应PB7按着不放,那么Cont的值应该为0x80,同样很好理解。
如果还是想不懂的话,可以自己演算一下那两个表达式,应该不难理解的。
因为有了这个支持,那么按键处理就变得很爽了.

应用

应用一:一次触发的按键处理
假设PB0为蜂鸣器按键,按一下,蜂鸣器beep的响一声。
这个很简单,但是大家以前是怎么做的呢?对比一下看谁的方便?
#define KEY_BEEP 0x01
void KeyProc(void)
{
	if (Trg & KEY_BEEP) // 如果按下的是KEY_BEEP
	{
		Beep(); // 执行蜂鸣器处理函数
	}
}
//以上完全能够达到按键消抖的功能,精粹所在与那个Trg变量,我按下一次后,它在下次按下之前都会变成0X00的状态,所以整个程序就相当于只进入一次,嘻嘻嘻。
应用2:长按键的处理
项目中经常会遇到一些要求,例如:一个按键如果短按一下执行功能A,
如果长按2秒不放的话会执行功能B,又或者是要求3秒按着不放,计数
连加什么什么的功能。不知道大家以前是怎么做的呢?我承认以前做的很郁闷。
但是看我们这里怎么处理吧,或许你会大吃一惊,原来程序可以这么简单
这里具个简单例子,为了只是说明原理,PB0是模式按键,短按则切换模式。
PB1就是加,如果长按的话则连加(玩过电子表吧?没错,就是那个!!!)
#define KEY_MODE 0x01 // 模式按键
#define KEY_PLUS 0x02 // 加
void KeyProc(void)
{
	// 如果按下的是KEY_MODE
	//而且你常按这按键也没有用
	//它是不会执行第二次的哦 , 必须先松开再按下
	if (Trg & KEY_MODE)  
	{
		Mode++; // 模式寄存器加1,当然,这里只是演示。
		// 执行的任何代码
	}
	if (Cont & KEY_PLUS) // 如果“加”按键被按着不放
	{
		cnt_plus++; // 计时 //整个程序是放在定时器中。
		if (cnt_plus > 100) // 20ms*100 = 2S 如果时间到
		{
			Func(); // 你需要的执行的程序
		}
	}
}
应用3:点触型按键和开关型按键的混合使用
点触形按键估计用的最多,特别是单片机。开关型其实也很常见。
例如家里的电灯,那些按下就不松开,除非关。这是两种按键形式的处理。
原理也没啥特别,但是你有没有想过,如果一个系统里面这两种按键是怎么处理的?
我想起了我以前的处理,分开两个非常类似的处理程序。
现在看起来真的是笨的不行了,但是也没有办法啊,结构决定了程序。
不过现在好了,用上面介绍的办法,很轻松就可以搞定。
原理么?可能你也会想到,对于点触开关,按照上面的办法处理一次按下和长按。
对于开关型,我们只需要处理Cont就OK了。
为什么?很简单嘛,把它当成是一个长按键,这样就找到了共同点,屏蔽了所有
的细节。程序就不给了,完全就是应用2的内容,在这里提为了就是说明原理……

总结(haha、再写一点!!!)

好了,这个好用的按键处理算是说完了。
可能会有朋友会问,为什么不说延时消抖问题?
哈哈,被看穿了。果然不能偷懒。下面谈谈这个问题,以及是如何消抖的。
延时消抖的办法是非常传统,也就是第一次判断有按键,延时一定的时间
(一般习惯是20ms)再读端口,如果两次读到的数据一样,说明了是真正的按键,
而不是抖动,则进入按键处理程序。
当然,不要跟我说你delay(20)那样去死循环去,真是那样的话,我衷心的建议
你先放下手上所有的东西,好好的去了解一下操作系统的分时工作原理,大概知道
思想就可以,不需要详细看原理。否则你永远逃不出“菜鸟”这个圈子。当然我也是
菜鸟。我的意思是,真正的单片机入门,是从学会处理多任务开始的,这个也是学校
程序跟公司程序的最大差别。当然,本文不是专门说这个的,所以也不献丑了。
貌似扯远了,回到我们刚才的问题,也就是怎么做按键消抖处理。我们将读按键的
程序放在了主循环,也就是说,每20ms我们会执行一次KeyRead()函数来得到新的
Trg 和 Cont 值。好了,下面是我的消抖部分:很简单
基本架构如上,当然这个配合,每个子程序必须执行时间不长,更加不能死循环,一般
采用有限状态机的办法来实现,具体参考其它资料咯。
懂得基本原理之后,至于怎么用就大家慢慢思考了,我想也难不到聪明的工程师们。例如还有一些处理,
怎么判断按键释放?很简单,Trg 和Cont都为0 则肯定已经释放了。
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学好单片机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值