3、按键扫描检测处理
说明:本文处理按键的短按、长按检测执行,非矩阵按键
硬件可以类似如下连接即可,无需放置上下拉电阻;

按键动作分长按、短按(弹起时执行)两种
按下不放执行长按,但松开按键时不予执行短按函数
多个按键可以同时操作
按键引脚会自动配置软件上下拉
1、驱动文件
Key_Driver.h
#ifndef _Key_Driver_H_
#define _Key_Driver_H_
#include "Common_Driver.h"extern void Key_Init(void);
extern void Key_Scan(void);#endif
Key_Driver.c
/**********************************************************************
*file:按键扫描处理文件
*author:残梦
*date:2023.2.15
*Version:V1.0
*note: 按键动作分长按、短按(弹起时执行)两种按下不放执行长按,但松开按键时不予执行短按函数多个按键可以同时操作按键引脚会自动配置软件上下拉
使用方法:1、修改宏按键个数值:KEY_NUM2、修改宏按键引脚对应时钟:KEYx_GPIO_CLK_ENABLE()3、修改按键编码枚举:KeyCode_EnumDef4、修改按键端口及引脚号变量数组:Key_gpioPort[]、Key_gpioPin[];端口和引脚需相对应,第一个为按键05、修改按键引脚初始电平状态值:KeyInitStatus[]6、主函数调用按键初始化函数Key_Init()7、1ms调用1次扫描函数Key_Scan()8、修改按键长按、短按执行函数:Key_LongPressAction()、Key_Action()
**********************************************************************/
#include "Key_Driver.h"#define LongPressThr 2000//长按LongPressThr毫秒标为长按按键动作
#define LongPressInc 500//长按LongPressInc毫秒执行一次长按动作函数#define KEY_NUM 4//按键个数
#define KEY0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define KEY1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define KEY2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define KEY3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()typedef enum
{eKeyCode0 = 0,eKeyCode1 = 1,eKeyCode2 = 2,eKeyCode3 = 3
}KeyCode_EnumDef;//按键编码static GPIO_TypeDef* Key_gpioPort[KEY_NUM] = {GPIOE,GPIOE,GPIOE,GPIOA};//按键引脚对应端口key0-key
static uint16_t Key_gpioPin[KEY_NUM] = {GPIO_PIN_4,GPIO_PIN_3,GPIO_PIN_2,GPIO_PIN_0};//按键引脚对应引脚号key0-key
static uint8_t KeyInitStatus[KEY_NUM] = {1,1,1,0};//按键引脚初始电平状态:0--低电平,1--高电平
static uint8_t KeyReset = 1;//无需用户更改static void Key_LongPressAction(KeyCode_EnumDef key,uint32_t DownTime);
static void Key_Action(KeyCode_EnumDef key);/****************************************************
@function:按键初始化(无需用户修改)
@param:void
@return:void
@date:2023.2.15
@note:
****************************************************/
void Key_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};KEY0_GPIO_CLK_ENABLE();KEY1_GPIO_CLK_ENABLE();KEY2_GPIO_CLK_ENABLE();KEY3_GPIO_CLK_ENABLE();//外设引脚初始化GPIO_InitStruct.Mode = GPIO_MODE_INPUT;for(uint8_t i = 0;i < KEY_NUM;i++){GPIO_InitStruct.Pull = KeyInitStatus[i]?GPIO_PULLUP:GPIO_PULLDOWN;GPIO_InitStruct.Pin = Key_gpioPin[i];HAL_GPIO_Init(Key_gpioPort[i], &GPIO_InitStruct);}KeyReset = 1;
}/******************************
@function:按键扫描函数(无需用户修改)
@param:void
@return:void
@date:2023.2.15
@remark:需在定时中断中调用,推荐调用间隔1ms长按和短按分为两种按下不放执行长按,但是弹起时不予执行短按函数
******************************/
void Key_Scan(void)
{static uint8_t keybuf[KEY_NUM] = {0xFF};//按键扫描缓冲区赋值static uint8_t KeySta[KEY_NUM] = {1};//全部矩阵按键的当前状态static uint8_t backup[KEY_NUM] = {1};//按键值备份,保存前一次的值static uint32_t KeyDownTime[KEY_NUM] = {0};//长按累计时间static uint32_t KeyDownThr[KEY_NUM] = {LongPressThr};static uint8_t KeyDownFlag[KEY_NUM] = {0};uint8_t i = 0,pinSta = 0;if(KeyReset){KeyReset = 0;for(i = 0;i < KEY_NUM;i++){keybuf[i] = 0xFF;KeySta[i] = 1;backup[i] = 1;KeyDownTime[i] = 0;KeyDownThr[i] = LongPressThr;KeyDownFlag[i] = 0;}}//将按键值移入缓冲区for(i=0;i < KEY_NUM;i++){pinSta = (uint8_t)HAL_GPIO_ReadPin(Key_gpioPort[i],Key_gpioPin[i]);if(!KeyInitStatus[i]){pinSta = pinSta?0:1;}keybuf[i] = (keybuf[i] << 1) | pinSta;}//消抖后更新按键状态for (i=0; i < KEY_NUM; i++){if((keybuf[i] & 0x0F) == 0x00){KeySta[i] = 0;}//连续4次扫描值为0,即4ms内都是按下状态时,可认为按键已稳定的按下else if((keybuf[i] & 0x0F) == 0x0F){KeySta[i] = 1;}//连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起}for(i=0; i < KEY_NUM; i++)//循环检测按键{if(KeySta[i] == 0)//长按按键{KeyDownTime[i] += 1;if(KeyDownTime[i] >= KeyDownThr[i]){KeyDownFlag[i] = 1; //长按标志KeyDownThr[i] += LongPressInc; //时间阈值增加LongPressInc毫秒,以准备下次执行Key_LongPressAction((KeyCode_EnumDef)i,KeyDownTime[i]); //调用长按执行函数}}//按键弹起 if(backup[i] != KeySta[i])//检测按键动作{if(backup[i] != 1)//按键按下时执行动作{if(KeyDownFlag[i] == 0)//长按弹起避免重复执行 {Key_Action((KeyCode_EnumDef )i); //调用按键动作函数}}backup[i] = KeySta[i]; //刷新前一次的备份值}if(KeySta[i]) {KeyDownFlag[i] = 0; //长按标志KeyDownTime[i] = 0; //累加时间清零KeyDownThr[i] = LongPressThr;//恢复阈值} }
}/******************************
@function:长按按键动作函数
@param:key-按键键码
@return:void
@date:2023.2.15
@remark:void
******************************/
static void Key_LongPressAction(KeyCode_EnumDef key,uint32_t DownTime)
{printf("Key%d:%d\r\n",key,DownTime);switch(key){case eKeyCode0:{}break;case eKeyCode1:{}break;case eKeyCode2:{}break;case eKeyCode3:{}break;}
}/******************************
@function:短按按键动作函数
@param:key-按键键码
@return:void
@date:2023.2.16
@remark:void
******************************/
static void Key_Action(KeyCode_EnumDef key)
{printf("Action Key%d\r\n",key);switch(key){case eKeyCode0:{}break;case eKeyCode1:{}break;case eKeyCode2:{}break;case eKeyCode3:{}break;}}
2、使用方法
1、修改宏按键个数值:KEY_NUM
2、修改宏按键引脚对应时钟:KEYx_GPIO_CLK_ENABLE()
3、修改按键编码枚举:KeyCode_EnumDef
4、修改按键端口及引脚号变量数组:Key_gpioPort[]、Key_gpioPin[];端口和引脚需相对应,第一个为按键0
5、修改按键引脚初始电平状态值:KeyInitStatus[]
6、主函数调用按键初始化函数Key_Init()
7、1ms调用1次扫描函数Key_Scan()
8、修改按键长按、短按执行函数:Key_LongPressAction()、Key_Action()
测试效果:

注意:扫描时间1ms如觉得太长可以更久调用1次,程序中会检测4次引脚的状态值,如都为1或0则算为稳定状态
按键文件下载:
链接:https://pan.baidu.com/s/1sO_kFuJb6wtLiMlFbneFsA
提取码:sun5
相关文章:
3、按键扫描检测处理
说明:本文处理按键的短按、长按检测执行,非矩阵按键 硬件可以类似如下连接即可,无需放置上下拉电阻; 按键动作分长按、短按(弹起时执行)两种 按下不放执行长按,但松开按键时不予执行短按函数 多个按键可以同时操作 按…...
集中式存储和分布式存储
分布式存储是相对于集中式存储来说的,在介绍分布式存储之前,我们先看看什么是集中式存储。不久之前,企业级的存储设备都是集中式存储。所谓集中式存储,从概念上可以看出来是具有集中性的,也就是整个存储是集中在一个系…...
【机器学习数据集】如何获得机器学习的练习数据?
一、scikit-learn自带数据集Scikit-learn内置了很多可以用于机器学习的数据,可以用两行代码就可以使用这些数据。自带的小的数据集为:sklearn.datasets.load_<name>load_bostonBoston房屋价格回归506*13fetch_california_housing加州住房回归20640…...
【编程实践】使用 Kotlin HTTP 框架 Fuel 实现 GET,POST 接口 kittinunf.fuel【极简教程】
目录 Fuel 简介 实现代码 GET网络请求用法(有三种写法...
大数据DataX(一):DataX的框架设计和插件体系
文章目录 DataX的框架设计和插件体系 一、DataX是什么...
软考高级信息系统项目管理师系列之十一:项目进度管理
软考高级信息系统项目管理师系列之十一:项目进度管理 一、进度管理领域输入、输出、工具和技术表二、项目进度管理1.项目进度管理过程2.项目进度管理三、项目进度管理过程1.项目进度管理2.工作包和活动3.活动清单4.活动属性5.项目进度网络图6.资源日历7.活动资源需求8.资源分解…...
vue2版本《后台管理模式》(下)
文章目录前言一、home 页以下都属于home子组件二、header 头部 组件二、Menu 页面三、Bread 面包屑四、Footer五 、分页器: Pageing六、权限管理总结前言 这章…...
软考中级-程序设计语言
(1)解释器解释源程序时不生成独立的目标代码,源程序和解释程序都参与到程序执行中。(2)编译器编译时生成独立的目标代码,运行时是运行与源程序等价的目标程序,源程序不参与执行。阶段补充&#…...
Sphinx : 高性能SQL全文检索引擎
Sphinx是一款基于SQL的高性能全文检索引擎,Sphinx的性能在众多全文检索引擎中也是数一数二的,利用Sphinx,我们可以完成比数据库本身更专业的搜索功能,而且可以有很多针对性的性能优化。 Sphinx的特点 快速创建索引:3分…...
ansible实战应用系列教程6:管理ansible变量
ansbile实战应用系列教程6:管理ansible变量 Ansible VariablesNaming VariablesDefining Variables在playbook中定义变量Defining Variables in Playbooks在playbooks中使用VariablesHost Variables and Group Variables使用group_vars和host_vars目录命令行定义全局变量Varia…...
java8新特性Stream流中anyMatch和allMatch和noneMatch的区别详解
1、anyMatch 判断数据列表中是否存在任意一个元素符合设置的predicate条件,如果是就返回true,否则返回false。 接口定义: boolean anyMatch(Predicate<? super T> predicate); 方法描述: 在anyMatch 接口定义中是接收 Pr…...
双网卡(有线和wifi)同时连接内网和外网
双网卡(有线和wifi)同时连接内网和外网 Win10技巧:如何修改有线/WiFi网络优先级:https://www.ithome.com/html/win10/253612.htm双网卡实现两个网络的自由访问:https://blog.51cto.com/ghostlan/1299090Linux服务器安…...
如何赋能智能运维,迈出数字化黑匣子第一步?
在当下大数据时代,诸多行业专家为企业智能运维绘出美好蓝图。在该蓝图中,互联网、云计算、大数据分析联合发力,企业在能“攻”能“守”中快速、可持续发展。何为“攻”?对支撑企业产品研发、生产、管理、营销等各业务链条的IT基础…...
消息称索尼计划为PS5推出两款蓝牙耳机,Find My蓝牙耳机用途广
根据国外科技媒体 Insider Gaming 报道,索尼计划进一步丰富 PlayStation 5 的配件生态,将会推出两款耳机,一款采用类似于 AirPods 的 TWS 设计,另一款则是无线头戴式耳机。 消息称 TWS 耳机的内部代号为“Project Nomad”&#…...
状态管理VueX
哈喽~大家好,这篇来看看状态管理VueX。 🥇个人主页:个人主页 🥈 系列专栏:【专栏】 🥉与这篇相关的文章: SpringCloud Sentinel 使用SpringClou…...
i.MX8MP平台开发分享(clock篇)- PLL14xx驱动
专栏目录:专栏目录传送门 平台内核i.MX8MP5.15.71文章目录 clk_pll14xx_prepareclk_pll14xx_is_preparedclk_pll1443x_set_rateclk_pll14xx_round_rateclk_pll1443x_recalc_rate在前面的文章i.MX8MP平台开发分享(clock篇)- 各类clock的注册,我们提到VIDEO_PLL1,GPU_PLL等P…...
课程规范性要求
课程制作规范 图片规范 允许范围:CC协议 / 作者授权 / 网站代理授权书 图片大小要求:1600 x 1200 dpi 图片长宽比:4:3 每章节格式要求 Week number 本周目标 1.通过背景学习,了解四足机器狗mini pupper上的微型控…...
华为OD机试 - 优秀学员统计(Python)| 真题+思路+考点+代码+岗位
优秀学员统计 题目 公司某部门软件教导团正在组织新员工每日打卡学习活动,他们开展这项学习活动已经一个月了,所以想统计下这个月优秀的打卡员工。每个员工会对应一个 id,每天的打卡记录记录当天打卡员工的 id 集合,一共 30 天。 请你实现代码帮助统计出打卡次数 top5 的…...
布林线(BOLL)计算公式详解,开口收口代表什么
布林带,英文名称BOLL,是John Bollinger在上世纪八十年代创建的,由中轨、上轨、下轨三条线组成。 一、布林线计算公式详解 布林线中轨是简单移动平均线,一般软件上自带的布林带中轨是20日均线,上轨是中轨加上2个标准差…...
模糊的照片能修复吗?
用照片记录生活,虽然不一定拍得好,但这也是生活应该有的样子。而我们拍得不好,常见就是拍出了模糊的照片,这可能是因为没有对焦或者是手抖了一下,就成了模糊的照片。更多时候未能及时发现,等到想分享一下才…...
SpringBoot+Vue Spring Boot可盈保险合同管理系统管理平台源码【适合毕设/课设/学习】Java+MySQL
系统架构设计### 摘要 随着保险行业的快速发展,传统的手工管理模式已无法满足现代保险业务的高效需求。保险合同管理系统作为保险业务的核心支撑,亟需通过信息化手段提升管理效率,降低人工操作错误率。当前市场上许多保险公司的合同管理仍依赖…...
FakeLocation:你的手机位置自由指南,3个场景让位置掌控更简单
FakeLocation:你的手机位置自由指南,3个场景让位置掌控更简单 【免费下载链接】FakeLocation Xposed module to mock locations per app. 项目地址: https://gitcode.com/gh_mirrors/fak/FakeLocation 还在为社交软件的位置限制烦恼吗?…...
自动驾驶汽车保险七大议题:从技术视角看责任转移与系统设计
1. 自动驾驶汽车保险的七个核心议题:从工程师视角看技术与责任的碰撞作为一名在汽车电子和嵌入式系统领域摸爬滚打了十几年的工程师,我亲眼见证了从ABS到自适应巡航,再到今天各种L2辅助驾驶的演进。每当和圈内朋友聊起全自动驾驶,…...
Java 资源释放与堆外内存管理机制演进分析
在 Java 虚拟机(JVM)的内存管理模型中,垃圾收集器(GC)仅负责回收 JVM 堆内存(Heap Memory)中不可达对象所占用的空间。然而,Java 程序在运行过程中必然会涉及到不受 GC 直接控制的外…...
MySQL性能优化:慢查询分析与索引设计艺术
MySQL性能优化:慢查询分析与索引设计艺术 引言 MySQL是世界上最流行的开源关系型数据库之一,但再强大的数据库在不当使用下也会出现性能问题。慢查询是数据库性能的头号杀手,而正确的索引设计则是解决慢查询的关键。本文将深入探讨MySQL慢查询…...
从淘宝几块钱的2804云台电机开始,手把手教你DIY一个桌面机械臂关节(STM32/GD32 + SimpleFOC)
从零打造低成本机械臂关节:2804云台电机FOC控制实战指南 在创客圈里,机械臂项目总是让人既向往又却步——商用伺服电机动辄上千元的单价,让许多爱好者望而却步。但当我发现淘宝上仅售几元的2804云台电机时,一个大胆的想法诞生了&a…...
触发器如何在主从架构下进行同步_基于Row格式的Binlog规避触发器
不会。MySQL在ROW格式Binlog下,主库触发器产生的变更不生成独立Binlog事件,从库仅回放行记录快照,跳过触发器执行;若启用STATEMENT/MIXED模式或手动关闭从库只读,才可能意外触发。主库触发器写入会不会被同步到从库不会…...
Bun用Claude自己“换心手术“?AI重构软件的新纪元来了
五月中旬的编程界上演了一出荒诞又魔幻的戏码——Bun,这个曾以 Zig 语言为傲的 JavaScript 运行时,在短短六天时间里,由被它拖累的 Claude AI 亲手把自己从 Zig 重写成 Rust 语言。事情得从两年前说起。2024年,Bun 创始人 Jarred …...
FPGA神经形态计算架构与Class 7实现详解
1. FPGA神经形态计算架构概述 神经形态计算是一种模拟生物神经系统信息处理机制的新型计算范式,其核心在于脉冲神经网络(SNiking Neural Network, SNN)的硬件实现。与传统人工神经网络不同,SNN通过精确模拟神经元间的脉冲时序依赖可塑性(STDP)来实现更接…...
毫米波雷达测心率靠谱吗?聊聊TI方案在车载健康监测中的真实挑战与未来
毫米波雷达在车载健康监测中的技术突破与实践挑战 当方向盘成为健康监测的第一道防线,毫米波雷达正在重新定义智能座舱的生物感知能力。不同于医院里笨重的心电监护仪或智能手表上时灵时不灵的光电传感器,藏在汽车顶棚或座椅背后的毫米波芯片,…...
