初学者思路-实现独立按键检测(以STM32为例)

这篇具有很好参考价值的文章主要介绍了初学者思路-实现独立按键检测(以STM32为例)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

        本文以初学者角度切入,详细剖析按键检测原理,实现按键短按、短按抬起、首次长按、持续长按次数、长按抬起功能;


目录

前言

波形图分析

抖动原因

为什么要消抖

如何消抖

原理图分析

程序设计思路

代码实践

按键配置

按键检测

实验结果

留下反思


波形图分析

        如图为按键按下→释放过程的波形图

stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机

可以从图中看到,实际波形在按下与释放时都有一段杂乱的波形,期间存在着多次高电平与低电平,这就是抖动

抖动原因

        机械原因:由于按键内部构造常为弹簧、金属弹片等接触器件,当按键按下或释放时,这些器件的反弹、震动等原因导致瞬时的接触和断开,从而产生抖动;

        电气原因:电路噪声、环境干扰、电容充放电等因素;

为什么要消抖

        为了确保按键信号的稳定性和可靠性。由于上述机械原因与电气原因,软件在读取到一个有效电平时,是无法百分百分辨出是真实的按键按下/释放还是由于抖动、干扰等造成的。如果不进行消抖会导致在一次按键按下释放过程中出现判断为多次的按键短按与释放,这是对系统功能有破坏性与不可靠性的。

如何消抖

        硬件层面:添加合适电容消除机械原因(注意电容过大会影响按键响应时间,过小则作用不佳)。添加上拉电阻抵抗电气原因;

        软件层面:在一段时间内,对引脚电平进行多次判断,如果每次都满足了触发条件则认为是有效的;


原理图分析

stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机

图一为最简单的按键原理图

        优点:简单,降低了成本和电路设计的复杂性;

        缺点:没有硬件消抖,且抗干扰能力差;

图二为加了上拉电阻的按键原理图

        优点:与图一方式比较,提高了抗干扰能力;

        缺点:没有硬件消抖;

图三为加了上拉电阻与电容的按键原理图

        优点:与图一二方式比较,有了抗干扰能力与硬件消抖;

        缺点:提高了成本和电路设计的复杂性;


程序设计思路

        当检测电平有按键按下时,等待一段时间(即抖动时间)之后,再次检测电平是否按下,如果仍然检测为有按键按下则认为有效。检测释放也同理,下图为大致流程图,省略了释放的消抖以便阅读。

stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机


代码实践

详细代码工程链接

按键配置

#include "stm32f10x.h"



#define KEY_GPIO_PORT			GPIOA				/* 按键引脚端口号 */
#define KEY_GPIO_PIN			GPIO_Pin_0			/* 按键引脚编号 */
#define KEY_GPIO_CLK_ENABLE()	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)	/* GPIO时钟使能 */



/*按键初始化*/
void Key_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/*GPIO时钟使能*/
	KEY_GPIO_CLK_ENABLE();
	
	/*GPIO配置*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;            /* 上拉输入 */
	
	GPIO_InitStructure.GPIO_Pin = KEY_GPIO_PIN;
	GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStructure);
}

详细代码工程链接 

按键检测

#include "stdio.h"



/* 按键检测 */
void KeyCheck(void)
{
	unsigned char tempDownCount = 0;	/* 按下计数 */
	unsigned char tempUpCount = 0;		/* 释放计数 */
	unsigned char tempLongFlag = 0;		/* 长按标志 */
	unsigned int tempContinueCount = 0;	/* 持续长按次数 */
	
	if(0 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN))				/* 读取按键电平有效 */
	{
		Delay_ms(20);														/* 按下阶段消抖(合理范围10~50ms) */
		if(0 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN))			/* 再次读取按键电平仍然有效 */
		{
			printf("按键按下\n");
            //按键短按需要干嘛。。。
			
			/*检测长按*/
			while(1)
			{
				if(0 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN))
				{
					tempUpCount = 0;										/* 复位释放计数 */
					
					if(++tempDownCount >= 10)
					{
						tempDownCount = 0;									/* 复位按下计数 */
						if(0 == tempLongFlag)
						{
							tempLongFlag = 1;
							tempContinueCount = 1;
							printf("按键首次长按\n");
                            //按键首次长按需要干嘛。。。
						}
						else
						{
							++tempContinueCount;
							printf("按键持续长按次数【%d】\n", tempContinueCount);
                            //按键多次持续长按需要干嘛。。。
						}
					}
				}
				/*检测释放*/
				if(1 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN))
				{
					if(++tempUpCount >= 2)									/* 释放阶段消抖 */
					{
						if(0 == tempLongFlag)
						{
							printf("按键短按抬起\n\n");
                            //按键短按抬起需要干嘛。。。
						}
						else
						{
							printf("按键长按抬起\n\n");
                            //按键长按抬起需要干嘛。。。
						}
						return;
					}
				}
					
				Delay_ms(20);												/* 时间间隔 */
			}
		}
	}
}



int main(void)
{
	Delay_Init();				/* 滴答延时初始化 */
	Usart1_Init(9600);			/* 串口初始化 */
	Key_Init();					/* 按键初始化 */
	
	printf("按键检测测试\n");
	
	while(1)
	{
		KeyCheck();				/* 按键检测 */
	}
}

详细代码工程链接


实验结果

短按测试

stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机

长按测试

stm 32 检测按键按下和松开,我的按键驱动编年史,stm32,嵌入式硬件,单片机


留下反思

        细心的同学应该能发现,虽然按键检测的功能是实现了,但是当后续其他功能的加入时,如果按键一直按住不松是不是就一直在KeyCheck()里的while(1)里不出来了?这时其他功能是不是就跑不了了?那么该怎么办呢?

        敬请关注“我的按键驱动编年史”专栏,里面有你想要的答案。


        分享先到这里,希望能给大家带来启发与帮助。如果对内容存在疑问或想法,欢迎在评论区留言,我会积极回复大家的问题。在我的“我的按键驱动编年史”专栏中,还有一些关于按键驱动不同写法的教程,欢迎一起探讨、一起学习。

        终版驱动gitee仓库:

XxxSwitchScan_Driver: XxxSwitchScan_Driver可以简单的看作为一个C语言的按键驱动,使用简单、灵活且解耦,以面向对象思想结合状态机编写,同时适用于裸机与操作系统。最终实现响应事件有:短按/短按抬起/长按/持续长按/长按抬起/连击/单边沿触发。一开始仅为了实现按键驱动。后面把按键结合如高低电平的传感器、开关量的限位等进一步抽象为开关量的输入设备。由此我常会把项目中的开关量的输入设备通过该驱动统一管理。https://gitee.com/wx_372d4eb42f/xxx-switch-scan_-driver文章来源地址https://www.toymoban.com/news/detail-794471.html

到了这里,关于初学者思路-实现独立按键检测(以STM32为例)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32初学者入门FreeRTOS操作系统,多任务实时系统

            FreeRTOS(Free Real-Time Operating System)是一个开源的嵌入式实时操作系统,它专门设计用于在资源有限的嵌入式系统中运行。FreeRTOS提供了一些用于任务管理、调度、同步和通信的功能,使开发者能够轻松地创建可靠的嵌入式系统。 以下是FreeRTOS的一些特点和功能: 轻量

    2024年02月11日
    浏览(32)
  • 不怕没项目做!github上的STM32 优秀开源项目和初学者项目

    TinyGo - Go语言编译器,适用于微控制器、WebAssembly、命令行工具,基于LLVM。 语言:Go 星标数:14,267+ 描述:TinyGo带来了Go语言在嵌入式系统的实现,使得STM32等微控制器编程更加多样化。 Flipper Zero Firmware - Flipper Zero的固件源码。 语言:C 星标数:10,699+ 描述:为Flipper Zero多功能

    2024年03月20日
    浏览(85)
  • Java初学者也可以实现的图书系统小练习

           大家好呀,我是小戴🙌🙌🙌        最近大家不是快期末了嘛,有没有泡图书馆呀?今天的学习内容跟图书馆有关,没错,就是图书管理系统,但是目前所学知识水平有限,这是一个很简单的图书系统小练习。不要急,我们的 目的是在于如何使用已知学过的知识进

    2023年04月09日
    浏览(36)
  • AIGC:初学者使用“C知道”实现AI人脸识别

    从前,我们依靠各种搜索引擎来获取内容,但随着各类数据在互联网世界的爆炸式增长,加上深度学习模型的广泛发展,我们现在不仅可以实现“遇事不决问AI”,还可以利用AI进行创作,关于人工智能生成内容(AIGC)的讨论和应用也是随处可见。 本文记录一下人工智能初学

    2024年02月11日
    浏览(37)
  • 【C语言】代码实现 扫雷 游戏及进阶功能(初学者详解)

    扫雷游戏的起源可以追溯到20世纪60年代,当时这款游戏是由IBM开发出来的。在80年代初,微软公司将其收归旗下,并将其作为Windows操作系统自带的一款游戏。自此以后,扫雷成为了Windows用户最喜欢的休闲游戏之一,也受到了全球范围内的玩家喜爱。 现在,我们使用C语言,来

    2024年01月20日
    浏览(34)
  • RSA 加密算法在C++中的实现 面向初学者(附代码)

    博文的 一,二部分 为 基础知识 的铺垫。分别从 密码学,数论 两个方面为理解RSA算法做好了准备。 第三部分 是对RSA加密过程的具体介绍,主要涉及其 密钥对(key-pair)的获取 。前三个部分与编程实践无关,可以当作独立的关于RSA加密算法的介绍。 第四部分 开始介绍在 编

    2024年01月21日
    浏览(36)
  • SpringBoot整合阿里云短信服务详细过程(保证初学者也能实现)

    网上关于实操性的文章普遍大部分都记录不全,要么只记录重点部分,对于刚学习的小伙伴来说看起来是比较困难的 所以,基于这一点。 该文章会详细介绍使用SpringBoot整合阿里云短信服务的每一步过程,同时会将验证码存放到Redis中并设置过期时间 , 尽量保证实战的同时也

    2023年04月15日
    浏览(30)
  • 守护进程(初学者必备)

    目录 一.进程组和会话 二.守护进程的概念 三.守护线程的特点 四.守护进程创建的基本步骤 1.进程组的相关概念: 进程除了有进程的PID之外还有一个进程组,进程组是由一个进程或者多个进程组成。通常他们与同一作业相关联可以收到同一终端的信号 每个进程组有唯一的进程

    2024年02月08日
    浏览(47)
  • 爬虫,初学者指南

    1.想目标地址发起请求,携带heards和不携带heards的区别 request模块用于测速发送数据的连通性,通过回复可以看出418,Connection:close表示未获取到服务器的返回值,需要添加heards信息,此服务器拒绝非浏览器发送的请求。 上图可以看出添加了头信息headers之后成功获取了返回值

    2024年02月07日
    浏览(45)
  • Groovy初学者指南

    本文已收录至Github,推荐阅读 👉 Java随想录 微信公众号:Java随想录 目录 摘要 Groovy与Java的联系和区别 Groovy的语法 动态类型 元编程 处理集合的便捷方法 闭包 运算符重载 控制流 条件语句 循环语句 字符串处理 字符串插值 多行字符串 集合与迭代 列表(List) 映射(Map) 迭代器

    2024年02月05日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包