蓝桥杯嵌入式学习日记(三)——按键的长按、短按与双击(三行按键法)【STM32】【HAL库】

目录

  • 一、查阅相关资料
  • 二、程序的编写
    • 1、创建工程
    • 2、三行按键法
    • 3、短按与长按
    • 4、双击

一、查阅相关资料

  想要进行一块板子的开发,需要先查阅资料了解器件连接。
在这里插入图片描述
  从CT117E-M4产品手册中不难发现,按键分别有PB0、PB1、PB2、PA0分别对应B1、B2、B3、B4四个按键。

按键抖动
在这里插入图片描述
在这里插入图片描述
  我们所使用这类按键时,当按键按下,内部的机械触点因为弹性,并不会立马导通,同样松开时也不是立马分离,而是会产生一连串的抖动,这段时间大概在5~10ms,为了防止紊乱我们要进行消抖。这里我选择利用uwTick进行软件延时,实际情况中也可以使用定时器,但不建议使用HAL_Delay函数进行延时。

	if( uwTick - KeyTick < 10) return ;//建议至少大于等于10ms,但不要过大,例如超过100ms
	KeyTick = uwTick ;

了解了这些,我们可以进行STM32cubemx工程创建。依旧是上一篇的工程进行延展。

二、程序的编写

1、创建工程

在这里插入图片描述
如图设置完以后便可以生成工程进行编写,不会利用STM32cubemx生成工程的可以参考上一篇利用STM32cubemx创建工程并以STM32G4点灯【HAL库】。
依旧是照例创建key.c和key.h方便管理。

2、三行按键法

#define B1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) 
#define B2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) 
#define B3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) 
#define B4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) 
#define Key_Flag  B1 | (B2<<1) | (B3<<2) | (B4<<3) | 0xf0      //初始端口状态

u8 Trg ;//Triger
u8 Cont ;//Continue

void Key_Scan()
{
	u8 ReadDate = Key_Flag ^ 0xff ;
	Trg = ReadDate & (ReadDate ^ Cont) ;
	Cont = ReadDate ;
}

想要理解这三行代码需要了解下最基本的与或知识,对于学过数电的同学可能已经掌握,可以直接跳过。

1为真值
0 为假值

与(and)(&)
逻辑表达式:F=AB
运算规则为:全1为1 ,有0为0 。真值表为

操作数1操作数2结果值
111
100
010
000

或(or)(|)
逻辑表达式:F=A+B
运算规则为:全0为0,有1为1 。真值表为

操作数1操作数2结果值
111
101
011
000

异或(XOR)(^)
运算规则为:相异为1,相同为0 。真值表为

操作数1操作数2结果值
110
101
011
000

了解了基础知识再来进行推理就很简单了。

1、当没有按键按下的初始状态

Key_Flag = 0xff ;
ReadDate = 0xff^0xff = 0000 0000 ;
Trg = 0000 0000 ;
Cont = 0000 0000 ;

2、当B1被按下

Key_Flag = 0xfe ;
ReadDate = 0xfe ^ 0xff = 0x01 ; 
Trg = 0x01 & (0x01 ^ 0x00) = 0x01 ;
Cont = 0x01 ;

3、当B1被长按

Key_Flag = 0xfe ;
ReadDate = 0xfe ^ 0xff = 0x01 ;
Trg = 0x01 & (0x01 ^ 0x01) = 0x00 ;
Cont = 0x01 ;
一步步来理解就是当初始状态没有按键被按下时,Key_Flag 为0xff

ReadDate = Key_Flag ^ 0xff = 0xff ^ 0xff // 对于0xff取反则为0000 0000 ;
Cont默认为0x00 
Trg = ReadDate & (ReadDate ^ Cont) = 0x00 & ( 0x00 ^ 0x00) = 0x00


-------------------------------------------------------------------
当有按键被按下例如B1,则有 Key_Flag 为 0xfe

ReadDate = Key_Flag ^ 0xff = 0xfe ^ 0xff = 0x01 // 0000 0001
Trg = ReadDate & (ReadDate ^ Cont) = 0x01 & (0x01 ^ 0x00) = 0x01 & 0x01 = 0x01 
Cont = 0x01 


-------------------------------------------------------------------
当有按键被持续按下例如B1,则有 Key_Flag 为 0xfe

此事件发生前Cont = 0x01

ReadDate = Key_Flag ^ 0xff = 0xfe ^ 0xff = 0x01 // 0000 0001
Trg = ReadDate & (ReadDate ^ Cont) = 0x01 & (0x01 ^ 0x01) =  0x01 & 0x00 = 0x00 
Cont = 0x01 

在结束按按键之后即所有回复0x00的状态。
如有不懂的同学,可以自己动手推到一两次即可理解。

3、短按与长按

  在了解上述内容后,后续只需要进行逻辑判断即可。
  
短按
  判断Trg的值即可进行按键的判断

按键KB1KB2KB3KB4
Trg0x010x020x040x08
void KEY_Judge()
{
	if( uwTick - KeyTick < 10) return ;
	KeyTick = uwTick ;
	
	Key_Scan() ;
//短按
	if(Trg & 0x01)  LED_Control(0x01) ; //B1
	if(Trg & 0x02)  LED_Control(0x02) ; //B2
	if(Trg & 0x04)  LED_Control(0x04) ; //B3
	if(Trg & 0x08)  LED_Control(0x08) ; //B4
}

通过上篇LED进行按键反馈。B1 ~ B4对于LED1 ~ LED4。

长按
  长按相较于短按只需要加入时间来进行判断Cont即可。

//长按
	if(Trg & 0x01)  ContTick = uwTick ; //B1
	if(Trg & 0x02)  ContTick = uwTick ; //B2
	if(Trg & 0x04)  ContTick = uwTick ; //B3
	if(Trg & 0x08)  ContTick = uwTick ; //B4
///B1
	if( Cont & 0x01 ) 
	{
		if(uwTick - ContTick < 1000) return ;
		{
			LED_Control (0x00) ;
		    ContTick = uwTick ;
		}
	}
//省略

这里设置短按B1则LED1亮起,长按一秒关闭。

4、双击

双击

  双击只需要加入标志位来判断,并且人手设置双击时间小于200ms即可(自适应)。这里需要填入一位变量来记录按键输入值。

#define Key_Temp  ((B1 | (B2<<1) | (B3<<2) | (B4<<3) ) ^ 0x0f)    //端口状态

经过上面学习应该对于Key_Temp的值有所了解,可以试着自己算一算。

	Key_Down = Key_Temp & (Key_Old ^ Key_Temp) ;   //按下为按键值
	Key_Up  = ~Key_Temp & (Key_Old ^ Key_Temp) ;  //松手为抬起前的按键值
	Key_Old = Key_Temp ;

这里跟上面三行按键类似不再进行分析,如果有不会的可以在评论区询问。

	if(Key_Up)	DoubleTick = uwTick;		//判断按键上升沿弹起并记录当前时间 

	if(uwTick - DoubleTick >=200 ) //200ms以内执行以下操作
	{
		switch(Key_Down) 
		{
			case 1 : LED_Control(0x01) ; break ;
			case 2 : break ;
			case 3 : break ;
			case 4 : break ;
		}
		if(Cont & 0x01)
		{
			if(uwTick - ContTick < 1000) return ;
			{
				LED_Control (0x00) ;
				ContTick = uwTick ;
		    }
		}
	}
	else //反之
	{
			switch(Key_Down) 
			{
				case 1 : LED_Control(0xff) ; break ;
				case 2 : break ;
				case 3 : break ;
				case 4 : break ;
			}
	}
}

这里只放出了B1的短按、长按和双击,对应的现象分别是,LED1亮起、LED1一秒熄灭和LED1~8全部亮起。如有不懂,可以在评论区留言。这里放上完整工程,如有需要自行下载。

链接:https://pan.baidu.com/s/1KmYiYB84tBnmpjXxt94sFg?pwd=1111
提取码:1111

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络安全 | 漏洞挖掘】通过JWT的IDOR实现账户接管

未经许可,不得转载。 文章目录 正文正文 在审查目标平台“redirect.com”的Web应用时,我发现它使用了JSON Web Token(JWT)进行身份验证,因此决定尝试进行账户接管(ATO)攻击。 首先,我创建了一个新账户并测试了其功能。在此过程中,我尝试在“firstName”字段输入XSS(…

从0到1入门RabbitMQ

一、同步调用 优势&#xff1a;时效性强&#xff0c;等待到结果后才返回 缺点&#xff1a; 拓展性差性能下降级联失败问题 二、异步调用 优势&#xff1a; 耦合度低&#xff0c;拓展性强异步调用&#xff0c;无需等待&#xff0c;性能好故障隔离&#xff0c;下游服务故障不影响…

CST直角反射器 --- 距离多普勒(RD图), 毫米波汽车雷达ADAS

之前几期介绍了雷达是如何从频域换去时域&#xff0c;然后时域计算距离。 这期我们加上一个维度&#xff0c;既看距离&#xff0c;又看速度。速度的计算当然就是多普勒原理&#xff0c;所以距离速度的二维图又叫range-doppler图。 启用雷达ADAS Range-Doppler模板&#xff1a…

手写一个Tomcat

Tomcat 是一个广泛使用的开源 Java Servlet 容器&#xff0c;用于运行 Java Web 应用程序。虽然 Tomcat 本身功能强大且复杂&#xff0c;但通过手写一个简易版的 Tomcat&#xff0c;我们可以更好地理解其核心工作原理。本文将带你一步步实现一个简易版的 Tomcat&#xff0c;并深…

【从零开始学习计算机科学】计算机组成原理(六)异常事件处理

【从零开始学习计算机科学】计算机组成原理&#xff08;六&#xff09;异常事件处理 异常事件处理异常处理的数据通路异常事件入口地址 异常事件处理 异常和中断事件改变处理机正常指令的执行顺序。异常指令执行过程中&#xff0c;由于操作非法和指令非法引起的事件。陷阱指陷…

3.3.2 Proteus第一个仿真图

文章目录 文章介绍0 效果图1 新建“点灯”项目2 添加元器件3 元器件布局接线4 补充 文章介绍 本文介绍&#xff1a;使用Proteus仿真软件画第一个仿真图 0 效果图 1 新建“点灯”项目 修改项目名称和路径&#xff0c;之后一直点“下一步”直到完成 2 添加元器件 点击元…

高效运行 QwQ-32B + 错误修复

文章目录 QwQ-32B 错误修复⚙️ 官方推荐设置&#x1f44d; 推荐的 llama.cpp 设置&#x1f4d6; 教程&#xff1a;运行和修复的 QwQ-32B1、对于 llama.cpp 及使用 llama.cpp 的引擎&#xff1a;2、下载模型 测试3、测试/评估4、尝试不使用我们的修复方案&#xff1a; &#x…

R 语言科研绘图 --- 直方图-汇总

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…

1.5.1 掌握Scala内建控制结构 - 条件表达式

本文介绍了 Scala 中条件表达式的使用及其在实际任务中的应用。条件表达式的语法为 if (条件) 值1 else 值2&#xff0c;其结果类型取决于值1和值2的类型。如果类型相同&#xff0c;结果类型与它们相同&#xff1b;如果不同&#xff0c;则结果类型为 Any。通过两个任务展示了条…

Linux rootfs:如何开机就自动添加某个用户?

前言 项目开发需求&#xff0c;需要开机后就自动创建某个用户密码 厂家提供的sdk&#xff0c;只有adduser命令&#xff0c; 该命令添加用户时&#xff0c;会有终端交互&#xff0c; 需要手动输入2次密码&#xff0c; 所以无法通过简单脚本方式创建。 要实现自动填充密码&…

计算机三级网络技术知识点汇总【7】

第七章 路由器配置及使用 1. 路由器的基础知识 1.1 路由器的基本概念 路由器是工作在网络层的设备&#xff0c;负责将数据分组从源端主机经最佳路径传送到目的端主机&#xff0c;实现在网络层的互联。路由器工作在 TCP/IP 网络模型的网络层&#xff0c;对应于 OSI 网络参考模…

Compounding Geometric Operations for Knowledge Graph Completion(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2023年7月 25年3月10日交 一、简介 使用知识图谱嵌入模型&#xff0c;将三元组&#xff08;h,r,t&#xff09;中关系 r 转化为平移、旋转、缩放矩阵对头节点以及尾节点进行运算&#xff0c;判定三元组的真实性。 二、原理 1.整…

mac系统安装

目录 准备工作 一、安装虚拟机 二、解锁系统 三、安装系统 四、部署系统 五、安装VMware Tools(选做) 为什么要安装VMware Tools,这是啥玩意? 六、配置共享文件夹(选做) 为什么要共享文件夹? 注意事项: 七、安装完成 准备工作 一、安装说明: 本教程分为7个部…

DNASimCLR:一种基于对比学习的基因序列数据分类的深度学习方法

摘要 DNASimCLR利用卷积神经网络和基于对比学习的SimCLR框架&#xff0c;从不同的微生物基因序列中提取复杂的特征。在包含宏基因组和病毒基因序列的两个经典的大规模未标记数据集上进行了预训练。后续的分类任务通过使用先前获得的模型对预训练的模型进行微调来完成。我们的实…

Ae 效果详解:VR 旋转球面

Ae菜单&#xff1a;效果/沉浸式视频/VR 旋转球面 Immersive Video/VR Rotate Sphere VR 旋转球面 VR Rotate Sphere效果用于对 VR 视频进行三轴旋转&#xff0c;以调整视频的视角方向。可用于校正拍摄时的角度偏差&#xff0c;或者根据创意需求模拟摄像机旋转。 本效果适用于所…

南开提出1Prompt1Story,无需训练,可通过单个连接提示实现一致的文本到图像生成。

&#xff08;1Prompt1Story&#xff09;是一种无训练的文本到图像生成方法&#xff0c;通过整合多个提示为一个长句子&#xff0c;并结合奇异值重加权&#xff08;SVR&#xff09;和身份保持交叉注意力&#xff08;IPCA&#xff09;技术&#xff0c;解决了生成图像中身份不一致…

Python----数据可视化(Seaborn二:绘图一)

常见方法 barplot方法 单独绘制条形图 catplot方法 可以条形图、散点图、盒图、小提亲图、等 countplot方法 统计数量 一、柱状图 seaborn.barplot(dataNone, xNone, yNone, hueNone, colorNone, paletteNone) 函数描述data用于绘图的数据集。x用于绘制长格式数据的输入。…

只音 1.2.0 |纯净无广告,畅听全网音乐,支持无损下载和批量下载

只音是一款全网音乐一网打尽的听歌利器&#xff0c;无需登录即可搜索抖音、网易云、QQ音乐等平台资源&#xff0c;无损音质直连播放。内置智能推荐算法&#xff0c;每日更新热门榜单与个性化歌单&#xff0c;轻松发现小众优质音乐。支持批量下载功能&#xff0c;一次性打包30首…

Python从入门到精通1:FastAPI

引言 在现代 Web 开发中&#xff0c;API 是前后端分离架构的核心。FastAPI 凭借其高性能、简洁的语法和自动文档生成功能&#xff0c;成为 Python 开发者的首选框架。本文将从零开始&#xff0c;详细讲解 FastAPI 的核心概念、安装配置、路由设计、请求处理以及实际应用案例&a…

Service与Ingress:如何将你的应用暴露给世界

引言&#xff1a;从“内部通讯”到“对外开放” 想象Kubernetes集群是一座繁忙的办公楼&#xff0c;每个Pod&#xff08;容器&#xff09;是楼内的员工。 Service 就像前台的接待员&#xff0c;负责将外部电话&#xff08;请求&#xff09;转接到正确的员工&#xff08;Pod&am…