当前位置: 首页 > news >正文

由一个按键程序引发的思考(上)

  说起按键程序,只要会单片机的肯定都很熟悉。一般开始学习单片机的时候,入门程序基本都是LED灯和按键。那么这个按键程序有什么特别的吗,还需要专门去思考吗?如果我刚开始学单片机的时候也会这么想,但是随着项目的积累,经验的增加,越来越觉得复杂的事情简单做,简单的事情复杂做,这句话很有哲理,越是看起来简单的事情,真正做好却很不容易。下面就抽丝剥茧的来慢慢分析下这个按键程序有什么特别之处。

  首先来看一下按键的硬件原理图。
在这里插入图片描述

  这是一个很常见的按键硬件连接图,电源接一个上拉电阻,在接按键,按键的另一端接地,电阻和按键的连接点接到单片机的IO口。按键未按下的时候输出高电平,当按键按下的时候输出低电平。由于按键是机械开关,所以在按下的一瞬间可能会产生毛刺。按键的实际波形如下:
在这里插入图片描述
  由于按键在按下或者弹起的瞬间会产生毛刺,所以在写程序判断的时候,需要加上10ms的延时。如果10ms后按键依然是低电平就认为按键有效,否则就认为出现了干扰,按键无效。

在这里插入图片描述

u8 key_scan(void)
{
	if(key==0)
	{
		delay_ms(10);
		if(key==0)
			return 1;
		else
			return 0;
	}
}

  这种是很常见的方法,使用起来也最简单。看起来也没什么问题,现在将问题复杂化一下。假设按键被用户按下了一次,那么会有以下这些情况。

在这里插入图片描述
  第一种情况是正常按键按下时间大概0.2秒左右,第二种情况是按键的时间非常短只有0.02秒,第三种情况是持续按下2秒。那么这三种情况都会被程序正常识别到。但是程序运行的结果可能会出现不同的效果。

  假如现在的程序实现的功能是,在主程序中循环检测按键,如果发现按键按下,就让LED灯的状态翻转一下。也就是按一下按键LED灯亮,再按一下按键LED灯灭。程序执行流程如下。

在这里插入图片描述

void main(void)
{
	char value = 0;
	while(1)
	{
		value = key_scan();
		if(value)
			LED = !LED;
	}
}

  在主函数中一直循环检测按键,如果有按键按下,那么就翻转LED灯的状态。在实际测试过程中会发现按键有时候好像不怎么灵敏,当LED灯亮的时候,按一下按键,LED灯还是亮的。如果用示波器观察LED灯的波形,会发现按键按下一次时,LED的状态会翻转很多次。

在这里插入图片描述
  按键按下的时候越长,LED翻转的次数越多。LED最后是亮还是灭就得靠运气了,通过按键很难控制一下灭,一下亮。那么为什么会出现这种情况。下面就根据波形分析一下程序执行的流程。
在这里插入图片描述
  由于主程序干的事情很少,所以代码消耗的时间,主要是在按键检测的10ms中,也就是主程序基本10ms就能执行完一圈。假如按键按下的时间比较长,当按键程序检测完成之后,LED灯的状态也翻转了,此时按键依然没有弹起,那么程序会再次进入按键检测函数中。此时会再次检测到按键按下。这样LED灯在按键按下的这段时间中就会一直翻转。所以LED灯基本10ms翻转一次,由于人的视觉暂留时间时是20ms,翻转的时间小于20ms所以人眼看不到LED灯的闪烁。如果将按键的10ms延时改为100ms,那么在按键按下的时候,就会看到LED灯一直在闪烁。单次按键功能变成了连续按键的功能。

  那么如果想要这个程序实现正常的功能要怎么办呢?第一种方法是在主程序中加入延时,让程序执行一圈花费的时间更多一点。第二种方法是按键检测的延时时间加长一点。第三种方法是当发现按键按下时直接进入死循环中,直到按键弹起,才退出按键检测程序。

  前两种方法看着能解决问题,但是实际中不同的人按键的时间长短很难把握,有的人轻轻按一下,有的人使劲按半天。这样延时时间太长,感觉按键比较迟钝,延时时间太短,又会导致按一次按键,灯闪好几次的情况出现。这样同一个产品在不同客户的手里就有不同的客户体验,就会导致有的客户感觉产品的功能和设计的不符。那么最有效的解决方法只能是第三种,当按键按下后,等待按键弹起,然后在执行LED状态翻转的功能。

  那么按键检测的流程改为下面这种:
在这里插入图片描述

u8 key_scan(void)
{
	if(key==0)
	{
		delay_ms(10);
		if(key==0)
		{
			while(key==0);
			return 1;
		}
		else
			return 0;
	}
}

  这样当按键按下的时候,就一直在while循环中等待按键释放。LED灯的状态在按键弹起的时候才会翻转。

在这里插入图片描述
  不论按键按的快还是慢,LED的状态在按键的时候每次只会改变一次。这样就比较符合设计的期望。

  但是这样又会引入一个新的问题,就是在按键按下的时候,程序就会一直停留在那里,其他的事情就不能干了。如果此时还有数码管动态显示函数,那么在按键按下的时候就数码管就会闪烁一下,如果按键按下时间很长,那么数码管就会熄灭。这样产品使用的时候体验就很不好。
在这里插入图片描述

  那按键既不能在按下的时候让LED状态翻转,又不能在弹起的时候让LED翻转,难道就无解了吗?那这个LED灯如如何控制呢?要知按键如何判断?且听下回分解。

由一个按键程序引发的思考(中)

相关文章:

  • CDH大数据平台 21Cloudera Manager Console之azkaban与freeIPA、Kerberos等组合配置(markdown新版二)
  • Web开发:Web开发中的域概念整理与解读
  • html制作一个酷炫的记事本(源码)
  • Java项目:超市管理系统(java+SSM+JSP+LayUI+jQ+Mysql)
  • MATLAB 2--结构化程式与自定义函数
  • Go学习笔记 -- 并发原理
  • 【MindSpore产品】【数据处理功能】加入数据增强之后,报出卷积输入类型不同的问题
  • 基于Nexus搭建docker镜像源仓库
  • Estimating High-Dimensional Directed Acyclic Graphs with the PC-Algorithm
  • Linux文件查找find
  • Vue--》Vue中实现数据代理
  • 深度学习入门(十) 模型选择、过拟合和欠拟合
  • RK3399驱动开发 | 12 - AP6255 SDIO WiFi 调试(基于linux4.4.194内核)
  • 牛客网-《刷C语言百题》第二期
  • 测试开发需要掌握哪些技能?
  • 巴什博弈——范围拿物品问题
  • 【Mybatisplus】初识Mybatisplus+SpringBoot整合
  • 【编程碎笔】-Java中关于next(),nextInt(),nextLine()的深度解剖
  • 2023年荆州市高新技术企业申报条件以及奖励补贴政策(附申报时间)汇总!
  • macOS Ventura 正式版你确定不更新,好用到爆的功能你不想尝试一下?