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

news2024/11/15 1:27:08

  说起按键程序,只要会单片机的肯定都很熟悉。一般开始学习单片机的时候,入门程序基本都是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灯如如何控制呢?要知按键如何判断?且听下回分解。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1904.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信早安消息推送(大升级版-企业微信)

微信早安消息推送(企业微信) 在微信公众号推送的基础上的一个升级 新增图文、疫情状况等 可以修改头像 、 昵称 效果展示 更多资讯 源代码获取 → 薇信公粽号“Cloud技术栈”,回复“企业微信推送” ———————————————————…

【贪心算法-LeetCode3:无重复字符的最长子串(Java实现)】

无重复字符的最长子串一、题目描述1.题目内容2.样例二、解决方案1.算法流程1)分析2)算法流程2.Java代码1)核心代码2)完整测试代码个人社区:https://bbs.csdn.net/forums/smile 个人主页:https://blog.csdn.…

STM32G070RBT6基于STM32CubeMX创建定时器中断控制LED闪烁

STM32G070RBT6基于STM32CubeMX创建定时器中断控制LED闪烁📍相关篇《【硬件开源电路】STM32G070RBT6开发板》🌺配置内容演示: 📚功能介绍 📑通过STM32CubeMX配置定时器1和定时器3分别作为两个led的定时闹钟。这里作为…

单片机原理及应用实验一交通信号系统(基于Proteus仿真)

1.实验内容与要求 交通信号系统是保障交通安全高效的重要设施。51单片机价格低廉、体积小、低功耗、抗干扰性好等优点,适用于交通信号系统中,本实验利用51单片机IO口的开关量的输入输出功能及内部CPU运算功能,设计一个简易的交通信号灯系统&…

生成.keystore 安卓签名

需要有openssl.exe和keytool.exe支持 signapk.jar手动签名命令 java -jar signapk.jar pl.x509.pem pl.pk8 smartrecord_3.5.8.apk smartrecord_3.5.8-signed.apk除了直接使用signapk.jar签名外,还可以将签名文件生成keystore文件,然后配置编译器给apk进…

数据分析 | Pandas 200道练习题,每日10道题,学完必成大神(5)

文章目录前期准备1. 将create Time列设置为索引2. 生成一个和df长度相同的随机数DataFrame3. 将上一题生成的DataFrame与df合并4. 生成的新的一列new值为salary列减去之前生成的随机数列5. 检查数据中是否含有空值6. 将salary类型转换成浮点数7. 计算salary 大于10000的次数8. …

多线程之线程池

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、什么是线程池二.为什么要有线程池引入:为什么从池子里取,比创建线程速度要快什么是用户态,什么是内核态最终结论&#xf…

aws 负载均衡clb/nlb/alb

目录 概述 传统负载均衡器(Classic Load Balancer) DNS解析 健康检查(Health Check) 监听器(Listeners) 连接耗尽(Connection Draining) 粘性会话/会话关联(Sticky Sessions/…

(四)手写简单版MyBatis框架

文章目录环境搭建第一步:资源⼯具类第二步:定义SqlSessionFactoryBuilder类第三步:定义SqlSessionFactory类第四步:定义JDBC事务管理器第五步:定义数据源类第六步:定义MyMappedStatement类第七步&#xff1…

基于遗传算法卡车无人机旅行推销员问题(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

Leetcode刷题111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:2 示例 2: 输入…

Python_机器学习_算法_第7章_7.拓展知识

Python_机器学习_算法_第7章_7.拓展知识 文章目录Python_机器学习_算法_第7章_7.拓展知识7.拓展知识7.1. 其他距离公式1 标准化欧氏距离2 余弦距离3 汉明距离【了解】4 杰卡德距离【了解】5 马氏距离【了解】7.2.再议数据分割1 留出法2 交叉验证法2.1 交叉验证法基本介绍2.2 KF…

ARM发布Cortex-X3和Cortex-A715

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】: 【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 ARM公司发布了第二代 AR…

x86 smbus 下挂eeprom不能写问题

目录 背景 分析 驱动影响 SPD register 接口 只读 修改验证 总结 背景 x86 smbus上下挂一个eeprom,只能读取,不能写入。 写入命令采用: i2cset -y -f 0 0x50 0 0x33 即向总线0 下的0x50 地址的eeprom偏移量0 写入数据0x33, 命令…

哈夫曼树原理及Java编码实现

文章目录前言一、哈夫曼树原理二、哈夫曼编码(Java题解)参考资料前言 所有博客文件目录索引:博客目录索引(持续更新) 源代码:Gitee—Huffman.java、Github—Huffman.java 一、哈夫曼树原理 对于哈夫曼树的构造以及权值计算原理…

Java语言高级-10MySQL-第2节MySQL安装与使用

2、MySQL数据库软件 1、安装 详细见视频 2、卸载 1、去mysql的安装目录找到my.ini文件 “复制datadir “C:/programData/MySQL/MySQL Server 5.5/Data” 2、卸载MySQL 控制面板->程序卸载,但是此时并没有卸载干净 3、删除C:/ProgramData目录下得MySQL文件夹 注意…

java 内部类

小镇做题家 前段时间很火的一个话题“小镇做题家”,我没有具体了解,我以为是在鼓励一些努力拼搏的人。 某一天,禁不住好奇,我打开了百度百科,看了看小镇做题家的解释 就是指一些村里或者小镇的人,通过学习…

模板和泛型编程(上)

目录函数模板泛型编程函数模板概念及原理函数模板的实例化函数模板的匹配原则类模板类模板实例化函数模板 泛型编程 泛型编程(Generic Programming)最初提出时的动机很简单直接:发明一种语言机制,能够帮助实现一个通用的标准容器…

猿创征文|Python迭代器、生成器、装饰器、函数闭包

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 Python迭代器、生成器、装饰器、函数闭包1. 迭代器 iterator☞迭代器协议☞Python中的for循环2. 生成器…

C语言qsort()函数针对:整型、单个字符、字符串、结构体,超详细讲解(多维度分析举例,小白一看就懂!!!!!)

目录 一、前言 二、qsort()函数 🍑qsort()函数简介 🍉qsort()函数中整型、double型、字符型的应用 💦整型 💦 double型 💦字符排序 🍎qsort()函数在字符串中的应用 💦在字符串中按首字母…