STM32框架之按键扫描新思路

STM32框架之按键扫描新思路

  • 引入
  • 代码展示
  • 思路分析

我们学习了定时器实现毫秒级/秒级任务框架,这期我们基于任务框架学习按键扫描新思路。

引入

在按键扫描的过程中,最重要的一步就是按键消抖,解决的方法最简单粗暴的就是先扫描一次按键状态,判断按键按下后,延时,再次判断按键状态。就像这样:

if(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin))				//判断按键0是否按下{HAL_Delay(20);											//延时消抖			if(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin))			 //再次判断按键0是否按下	{while(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin))	//等待按键0松开{}Key_Num = 1;		//赋值按键值}}

这是最笨的方法,当然还可以

多次调用按键扫描函数,当按键按下的时候开始计数/计时。当数字/时间到达一定值时,判断按键按下,当有一次扫描到按键为按下时,计数/计时清零,代码如下:

int Key_Scan(void)
{int Key_Num = 0;        //定义按键值int temp = 0;           //定义临时变量static int Key0_Count=0,Key1_Count=0,Key2_Count=0,WKUP_Count=0 ;    //定义不同按键的按键值if(1-HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)) temp = 1;           //当某一个按键按下是,临时变量值为对应的按键值加一if(1-HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)) temp = 2;           //加一是因为temp为0时无法进入switch中,所以案件之都加一if(1-HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)) temp = 3;           //if(HAL_GPIO_ReadPin(WKUP_GPIO_Port,WKUP_Pin))   temp = 4;switch(temp){case 1: Key0_Count++; Key1_Count=0;Key2_Count=0;WKUP_Count=0 ;  //通过temp变量的值,将对应按键计数值加一break;                                                      //同时将其他按键计数值清零,case 2: Key1_Count++; Key0_Count=0;Key2_Count=0;WKUP_Count=0 ;  break;case 3: Key2_Count++; Key0_Count=0;Key1_Count=0;WKUP_Count=0 ;break;case 4: WKUP_Count++; Key0_Count=0;Key1_Count=0;Key2_Count=0 ;break;default: Key0_Count=0; Key1_Count=0;Key2_Count=0;WKUP_Count=0 ;break;}if(Key0_Count >= 500)           //当temp到达一定值时,则可判断按键按下{Key_Num = 1;                //按键按下,将所有的按键计数值清零Key0_Count=0; Key1_Count=0;Key2_Count=0;WKUP_Count=0 ;}if(Key1_Count >= 500){Key_Num = 2;Key0_Count=0; Key1_Count=0;Key2_Count=0;WKUP_Count=0 ;}if(Key2_Count >= 500){Key_Num = 3;Key0_Count=0; Key1_Count=0;Key2_Count=0;WKUP_Count=0 ;}if(WKUP_Count >= 500){Key_Num = 4;Key0_Count=0; Key1_Count=0;Key2_Count=0;WKUP_Count=0 ;}return Key_Num;	//返回按键值,当没有按键按下,或者存在抖动时,返回值为0

这种方法相对于第一种,逻辑上更严谨,但是不好控制计数值。并且多次进入函数,占用大量CPU资源,所以我们引入第三种方法,规定时间间隔,进行扫描,通过数组判断结果。代码如下:

代码展示

  • main.c
/* USER CODE BEGIN PFP */
void Proc2msTask(void)        //2ms任务
{static uint8_t i=0;if(Get_2ms_Flag() == 1)     //获取2ms标志位{Clear_2ms_Flag();      //清除2ms标志位//2mstask codei++;if(i==4)                //1s扫描一处按键状态{i=0;Key_One_Scan(Key_Name_Key0,Key0_Up_Task,Key0_Down_Task);         //扫描Key0状态Key_One_Scan(Key_Name_Key1,Key1_Up_Task,Key1_Down_Task);         //扫描Key1状态Key_One_Scan(Key_Name_Key2,Key2_Up_Task,Key2_Down_Task);         //扫描Key2状态Key_One_Scan(Key_Name_WKUP,WWKUP_Up_Task,WKUP_Down_Task);        //扫描WKUP状态}}
}void Proc1sTask(void)       //1s任务
{if(Get_1s_Flag() == 1)     //获取1s标志位{Clear_1s_Flag();         //清除1s标志位//1stask code
//      HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);}      
}
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM10_Init();/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim10);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){Proc2msTask();       //调用2ms任务Proc1sTask();        //调用1s任务/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
  • Key.c
/* USER CODE BEGIN 2 */
void Key0_Down_Task(void)
{HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET); //按下亮灯 
}
void Key0_Up_Task(void)
{HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET);  //松开关闭 
}
void Key1_Down_Task(void)
{HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); //按下亮灯  
}
void Key1_Up_Task(void)
{HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);  //松开关闭  
}
void Key2_Down_Task(void)
{HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET); //按下亮灯 
}
void Key2_Up_Task(void)
{HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET);  //松开关闭 
}
void WKUP_Down_Task(void)
{HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_RESET); //按下亮灯  
}
void WWKUP_Up_Task(void)
{HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_SET);  //松开关闭  
}void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void))
{static uint8_t Key_Val[Key_Name_Max];    //按键值的存放位置static uint8_t Key_Flag[Key_Name_Max];   //KEY0~2为0时表示按下,为1表示松开,WKUP反之Key_Val[KeyName] = Key_Val[KeyName] <<1;  //每次扫描完,将上一次扫描的结果左移保存switch(KeyName){case Key_Name_Key0:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin));    //读取Key0按键值break;case Key_Name_Key1:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin));   //读取Key1按键值break;case Key_Name_Key2:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin));   //读取Key2按键值break;case Key_Name_WKUP:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin));   //读取WKUP按键值break; default:break;}if(KeyName == Key_Name_WKUP)     //WKUP的电路图与其他按键不同,所以需要特殊处理{//WKUP特殊情况//当按键标志为1(松开)是,判断是否按下,WKUP按下时为0xffif(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 1){(*OnKeyOneDown)();Key_Flag[KeyName] = 0;}//当按键标志位为0(按下),判断按键是否松开,WKUP松开时为0x00if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 0){(*OnKeyOneUp)();Key_Flag[KeyName] = 1;} }else                               //Key0~2按键逻辑判断{//Key0~2常规判断//当按键标志为1(松开)是,判断是否按下if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 1){(*OnKeyOneDown)();Key_Flag[KeyName] = 0;}//当按键标志位为0(按下),判断按键是否松开if(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 0){(*OnKeyOneUp)();Key_Flag[KeyName] = 1;}  }}
/* USER CODE END 2 */
  • Key.h
/* Includes ------------------------------------------------------------------*/
#include "main.h"/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* USER CODE BEGIN Private defines */
typedef enum{Key_Name_Key0 = 0,Key_Name_Key1,Key_Name_Key2,Key_Name_WKUP,Key_Name_Max}EnumKeyOneName;/* USER CODE END Private defines */void MX_GPIO_Init(void);/* USER CODE BEGIN Prototypes */
void Key0_Down_Task(void);void Key0_Up_Task(void);void Key1_Down_Task(void);void Key1_Up_Task(void);void Key2_Down_Task(void);void Key2_Up_Task(void);void WKUP_Down_Task(void);void WWKUP_Up_Task(void);void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void)); 
/* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */

思路分析

按键按下的过程中,难免会有抖动,但是抖动的时间通常在10~20ms之间,而按键按下的过程往往会持续100ms以上,所以我们可以每10ms扫描一次按键状态,如果连续八次都是按下,则认为按键已经按下,想要的执行认为即可。反之,如果八次都是松开,则认为按键松开了,也可以执行按键松开的相关任务。

具体细节,大家看代码吧,这个只是大体思路,代码还有很多精彩的地方。

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

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

相关文章

纵行科技亮相2023汽车物流行业年会,与菜鸟共推ZETag资产管理方案

近日&#xff0c;由中物联汽车物流分会主办的“汽车物流行业年会”在十堰召开。纵行科技受邀亮相&#xff0c;并与菜鸟共推ZETag资产管理方案&#xff0c;助力汽车物流数字化发展。 当前&#xff0c;我国物流业处于恢复性增长和结构性调整的关键期&#xff0c;国务院印发的《…

大模型的交互能力

摘要&#xff1a; 基础大模型显示出明显的潜力&#xff0c;可以改变AI系统的开发人员和用户体验&#xff1a;基础模型降低了原型设计和构建AI应用程序的难度阈值&#xff0c;因为它们在适应方面的样本效率&#xff0c;并提高了新用户交互的上限&#xff0c;因为它们的多模式和生…

中间件安全:Apache 目录穿透.(CVE-2021-41773)

中间件安全&#xff1a;Apache 目录穿透.&#xff08;CVE-2021-41773&#xff09; Apache 的 2.4.49、2.4.50 版本 对路径规范化所做的更改中存在一个路径穿越漏洞&#xff0c;攻击者可利用该漏洞读取到Web目录外的其他文件&#xff0c;如系统配置文件、网站源码等&#xff0c…

list用stream流转map报key重复

我们在利用java8 Lambda 表达式将集合中对象的属性转成Map时就会出现 Duplicate key xxxx , 说白了也就是key 重复了&#xff01;案例如下&#xff1a; GetterSetterAllArgsConstructorpublic class Student{private String className;private String studentName;public st…

K-Means聚类

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 K-means聚类算法实现 技术细节 选取的数据集是sklearn.datasets里面的鸢尾花数据集&#xff0c;方便最后的算法评价。 根据手肘法&#xff08;即根据SSE代价函数&#xff09;得出最合适的k值。 此处思路是先根据E …

【实用技巧】更改ArduinoIDE默认库文件位置,解放系统盘,将Arduino15中的库文件移动到其他磁盘

本文主要介绍更改Arduino IDE &#xff08;含2.0以上版本&#xff09;默认库文件位置的方法。 原创文章&#xff0c;转载请注明出处&#xff1a; 【实用技巧】更改ArduinoIDE默认库文件位置&#xff0c;解放C盘&#xff0c;将Arduino15中的库文件移动到其他磁盘-CSDN博客文章浏…

Kubernetes Dashboard部署ImagePullBackOff问题处理

通常&#xff0c;出现ImagePullBackOff问题是由于Kubernetes集群无法拉取所需的镜像导致的。解决这个问题的方法通常包括以下步骤&#xff1a; 1. 检查Pod的描述信息&#xff1a; kubectl describe pod/[pod名称] --namespacekubernetes-dashboard 查看Events部分是否有关于…

GOTS认证资讯-7.0版关于环境准则的要求

4.3. 环境准则 4.3.1. 环境管理政策 4.3.1.1. 除GOTS准则外&#xff0c;被认证实体应必须确保其加工或制造阶段&#xff08;包括气体排放、废水排放和废弃物及污泥的处置&#xff09;符合相应国家和当地环境法规的相关要求。 4.3.1.2. 被认证实体应拥有与其业务性质相适应的书面…

【Python百宝箱】图解未来:数据可视化引领智慧决策时代

图表和数据可视化在数据分析中的关键作用 引言&#xff1a; 在现代数据科学中&#xff0c;数据可视化扮演着至关重要的角色。通过图表和可视化工具&#xff0c;我们能够更直观、更有效地理解数据的分布、趋势和关联性。本文将深入讨论三个主要的数据可视化工具&#xff1a;mat…

Windows安装Java环境(OracleJDK)

在下载之前&#xff0c;我们先了解一下java的前世今生 1991年&#xff1a;Java 的前身 Oak 由 James Gosling 和他的团队在 Sun Microsystems 公司开发。1995年&#xff1a;Oak 更名为 Java&#xff0c;并在同年发布。Java 1.0 版本正式推出。1996年&#xff1a;Sun Microsyst…

Vue 2.0中引入的类型检查Flow

1. 认识 Flow Flow 是 facebook 出品的 JavaScript 静态类型检查工具。Vue.js 的源码利用了 Flow 做了静态类型检查&#xff0c;所以了解 Flow 有助于我们阅读源码。 2. 为什么用 Flow JavaScript 是动态类型语言&#xff0c;它的灵活性有目共睹&#xff0c;但是过于灵活的副…

XLua热更新框架原理和代码实战

安装插件 下载Xlua插件&#xff1a;https://github.com/Tencent/xLua 下载完成后&#xff0c;把Asset文件夹下的文件拖入自己的工程Asset中&#xff0c;看到Unity编辑器上多了个Xlua菜单&#xff0c;说明插件导入成功 Lua启动代码 新建一个空场景&#xff0c;场景中什么都不…

Threejs_06 多材质的实现

Threejs 同一个几何体如何实现多材质呢&#xff1f; 多材质的实现 1.使用索引绘制一个几何体 //创建几何体(三角形) const geometry new THREE.BufferGeometry();//使用索引绘制 (两个共用的) const vertices new Float32Array([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1…

谈谈系统性能调优中都需要考虑哪些因素

一、 什么是性能调优&#xff1f; 这个系统好慢、网站又打不开了&#xff0c;太卡了&#xff0c;又没响应了&#xff0c;相信大家都遇到过用户的这种抱怨&#xff0c;此时&#xff0c;说明我们的应用系统出现了性能问题&#xff0c;那么怎么办呢&#xff0c;首先想到的应该是优…

npm私有云

安装node时npm会自动安装&#xff0c;npm也可以单独安装。 package.json 在使用npm时&#xff0c;package.json文件是非常重要的&#xff0c;因为它包含了关于项目的必要信息&#xff0c;比如名称、版本、依赖项等。在初始化新项目时&#xff0c;通常会使用npm init命令生成一…

HP惠普暗影精灵9笔记本电脑OMEN by HP Transcend 16英寸游戏本16-u0000原厂Windows11系统

惠普暗影9恢复出厂开箱状态&#xff0c;原装出厂Win11-22H2系统ISO镜像 下载链接&#xff1a;https://pan.baidu.com/s/17ftbBHEMFSEOw22tnYvPog?pwd91p1 提取码&#xff1a;91p1 适用型号&#xff1a;16-u0006TX、16-u0007TX、16-u0008TX、16-u0009TX、16-u0017TX 原厂系…

每天一道算法题(五)——判断一组数字是否连续,出现连续数字的时候以‘-’输出

文章目录 1、问题2、示例3、解决方法&#xff08;0&#xff09;错误示范——两个for循环遍历&#xff08;1&#xff09;方法1(递归)&#xff08;2&#xff09;方法2&#xff08;推荐&#xff09; 1、问题 实现一个函数&#xff0c;判断一组数字是否连续。当出现连续数字的时候以…

数据结构与算法编程题2

逆置线性表&#xff0c;使空间复杂度为 O(1) #include <iostream> using namespace std;typedef int ElemType; #define Maxsize 100 #define OK 1 #define ERROR 0 typedef struct SqList {ElemType data[Maxsize];int length; }SqList;void Init_SqList(SqList& …

YOLOV8部署Android Studio安卓平台NCNN

下载Android Studio&#xff0c;配置安卓开发环境&#xff0c;这个过程比较漫长。 安装cmake&#xff0c;注意安装的是cmake3.10版本。 根据手机安卓版本选择相应的安卓版本&#xff0c;我的是红米K30Pro&#xff0c;安卓12。 使用腾讯开源的ncnn&#xff0c;这是一个为手机端极…

驶入产业发展快车道,汉鑫科技人工智能研发中心正式启用!

11月18日&#xff0c;汉鑫科技人工智能研发中心正式启用。中心立足烟台&#xff0c;服务全国&#xff0c;聚焦工业智能、智能网联、智慧城市三大业务板块&#xff0c;以人工智能技术赋能政企实现“数智化”转型升级。该中心的启用标志着汉鑫科技在人工智能研发应用领域迈上了新…