当前位置: 首页 > news >正文

济南外贸网站保定网络营销推广

济南外贸网站,保定网络营销推广,关于网站建设项目收取费用,wordpress 短码1.背景 在之前有个项目需要一个或多个按键检测#xff1a;单击、双击、长按等操作 于是写了一份基于状态机的按键检测#xff0c;分享一下思路 2.实现效果 单击翻转绿灯电平 双击翻转红灯电平 长按反转红绿灯电平 实现状态机检测按键单击#xff0c;双击#xff0c;长…1.背景 在之前有个项目需要一个或多个按键检测单击、双击、长按等操作 于是写了一份基于状态机的按键检测分享一下思路 2.实现效果 单击翻转绿灯电平 双击翻转红灯电平 长按反转红绿灯电平 实现状态机检测按键单击双击长按等状态 3.代码实现 本代码是基于正点原子STM32F407ZGT6探索者开发板 HAL库写的 关于按键的代码可以直接移植与芯片和HAL库没有多大联系主要就是引脚定义是使用CubeMX生成的在main.h中如下 #define BUTTON3_Pin GPIO_PIN_2 #define BUTTON3_GPIO_Port GPIOE #define BUTTON2_Pin GPIO_PIN_3 #define BUTTON2_GPIO_Port GPIOE #define BUTTON1_Pin GPIO_PIN_4 #define BUTTON1_GPIO_Port GPIOE #define LED0_Pin GPIO_PIN_9 #define LED0_GPIO_Port GPIOF #define LED1_Pin GPIO_PIN_10 #define LED1_GPIO_Port GPIOF 3.1 driver_button.c文件 #include main.h #include driver_boutton.h#define NUM_BUTTONS 3 #define DOUBLE_CLICK_TIME 200 // 双击最大间隔时间ms #define LONG_PRESS_TIME 300 // 长按最小持续时间msvoid button_scan(void); void button_init(void); ButtonNum button_get_number(void);// GPIO端口和PIN引脚数组 const GPIO_TypeDef* button_GPIO_Ports[NUM_BUTTONS] { BUTTON1_GPIO_Port,BUTTON2_GPIO_Port, BUTTON3_GPIO_Port, }; const uint16_t button_GPIO_Pins[NUM_BUTTONS] { BUTTON1_Pin,BUTTON2_Pin, BUTTON3_Pin, };// 按键状态定义 typedef enum { BUTTON_RELEASED, //松开BUTTON_PRESSED, //按下BUTTON_SINGLE_CLICK, //单击BUTTON_DOUBLE_CLICK, //双击BUTTON_LONG_PRESS //长按 } Button_State; // 按键结构体定义 typedef struct { GPIO_TypeDef *GPIOx;uint16_t GPIO_PIN; // 按键连接的GPIO引脚 Button_State state; // 按键状态 uint32_t press_time; // 按下时间 uint32_t release_time; // 释放时间 uint8_t click_count; // 连续点击次数 uint32_t num; // 按键键值 } Button_TypeDef; //按键函数指针 const Button_Handler *button (const Button_Handler) {.get_tick HAL_GetTick, //获取系统时间滴答.init button_init, //按键初始化.callback button_scan, //按键扫描回调函数.get_number button_get_number, //获取键值 };static Button_TypeDef buttons[NUM_BUTTONS]; static ButtonNum button_num {0,0,0};/*** 简要 初始化按键配置* 说明 该函数对每个按键的GPIO端口和引脚进行初始化并将按键状态设置为未按下* 参数 无* 返回值 无*/ void button_init(void) { for (int i 0; i NUM_BUTTONS; i) { buttons[i].GPIOx (GPIO_TypeDef*)button_GPIO_Ports[i]; buttons[i].GPIO_PIN button_GPIO_Pins[i]; buttons[i].state BUTTON_RELEASED; buttons[i].click_count 0; buttons[i].num 0x01 i;} } /*** 简要 定时器扫描按键* 说明 定时器消抖扫描并检测按键状态* 参数 无* 返回值 无*/ void button_scan(void) { uint32_t current_time button-get_tick(); // 获取当前时间 for (int i 0; i NUM_BUTTONS; i) //遍历所有按键{ Button_TypeDef *button buttons[i]; uint8_t current_state HAL_GPIO_ReadPin(button-GPIOx, button-GPIO_PIN); // 读取按键状态 if (current_state 0) // 按键按下{ if (button-state BUTTON_RELEASED) // 如果之前是松开状态{ button-press_time current_time; // 记录按下时间button-state BUTTON_PRESSED; //更新按键状态为按下} } else // 按键释放 { if (button-state BUTTON_PRESSED) // 如果之前是按下状态{ button-release_time current_time; // 记录释放时间uint32_t press_duration button-release_time - button-press_time; // 计算按下持续时间if (press_duration LONG_PRESS_TIME) // 如果按下时间超过长按阈值{ button-state BUTTON_LONG_PRESS; // 更新状态为长按button_num.more | buttons[i].num; // 标记长按事件} else //如果按下时间在长按阈值范围内{ button-click_count; // 增加点击计数} // 复位按键状态 button-state BUTTON_RELEASED; } }if (button-click_count) // 如果有点击计数{// 距离下一次按下时间大于 DOUBLE_CLICK_TIME 可认为是单击if (button-click_count 1 current_time - button-release_time DOUBLE_CLICK_TIME) {button-click_count 0; // 重置点击计数button_num.once | buttons[i].num; // 标记单击事件}// 否则 在 DOUBLE_CLICK_TIME 时间段内按几下算几连击else if (button-click_count 2 current_time - button-release_time DOUBLE_CLICK_TIME){button-click_count 0; // 重置点击计数button_num.twice | buttons[i].num; // 标记双击事件} }} } /*** 简要 获取按键状态* 说明 返回当前各类按键的键值* 参数 无* 返回值 按键的键值*/ ButtonNum button_get_number(void) {ButtonNum temp button_num;button_num.once 0;button_num.twice 0;button_num.more 0;return temp; } 3.2 driver_button.h文件 #ifndef __driver_button__ #define __driver_button__#include stdint.h#define BUTTON1_ONCE (0x01 0) #define BUTTON2_ONCE (0x01 1) #define BUTTON3_ONCE (0x01 2)#define BUTTON1_TWICE (0x01 0) #define BUTTON2_TWICE (0x01 1) #define BUTTON3_TWICE (0x01 2)#define BUTTON1_MORE (0x01 0) #define BUTTON2_MORE (0x01 1) #define BUTTON3_MORE (0x01 2)typedef struct{uint32_t once; //单击uint32_t twice; //双击uint32_t more; //长按 }ButtonNum;extern ButtonNum button_num; // 按键处理函数结构体定义 typedef struct {uint32_t (*get_tick)(void); // 获取系统时间的函数指针void (*init)(void); // 初始化函数指针void (*callback)(void); // 回调函数指针ButtonNum (*get_number)(void); } Button_Handler;extern const Button_Handler *button;#endif 3.3 在定时器中断中 检测按键 这里我使用的是TIM6每10ms扫描一次  void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {static uint32_t timerCount_key 0;if(htim-Instance TIM6){timerCount_key;if(timerCount_key 10){timerCount_key 0;button-callback();}} } 3.4 主函数中使用方法 这里使用按键控制led灯演示 /* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(htim6);button-init();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */ButtonNum num button-get_number(); if(num.twice BUTTON1_TWICE) HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.twice BUTTON2_TWICE) HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.twice BUTTON3_TWICE) HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.more BUTTON1_MORE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin),HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.more BUTTON2_MORE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin),HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.more BUTTON3_MORE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin),HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);if(num.once BUTTON1_ONCE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);if(num.once BUTTON2_ONCE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);if(num.once BUTTON3_ONCE) HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);}/* USER CODE END 3 */ 4.按键状态机思路 void button_scan(void)  主要思路是这样 我每次定时器执行这个按键扫描的回调函数都会轮询判断一下所有的按键状态。 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {static uint32_t timerCount_key 0;if(htim-Instance TIM6){timerCount_key;if(timerCount_key 10){timerCount_key 0;button-callback();}} } 例如在此之前我从来没按下过按键当我的按键1按下的时刻 uint8_t current_state HAL_GPIO_ReadPin(button-GPIOx, button-GPIO_PIN); // 读取按键状态 current_state被返回了低电平取决于你的电路设计我这里按键按下接地 然后就会进入到 if (current_state 0) // 按键按下{ if (button-state BUTTON_RELEASED) // 如果之前是松开状态{ button-press_time current_time; // 记录按下时间button-state BUTTON_PRESSED; // 更新按键状态为按下} } 在这里由于我们是第一次按下会被标记为状态为按下然后将你的结构体中的按下时间记录为这一次扫描按键时的HAL_GetTick(); 然后你按下按键是需要松手的吧 现在你松手了接上面的if语句 else // 按键释放 { if (button-state BUTTON_PRESSED) // 如果之前是按下状态{ button-release_time current_time; // 记录释放时间uint32_t press_duration button-release_time - button-press_time; // 计算按下持续时间if (press_duration LONG_PRESS_TIME) // 如果按下时间超过长按阈值{ button-state BUTTON_LONG_PRESS; // 更新状态为长按button_num.more | buttons[i].num; // 标记长按事件} else // 如果按下时间在长按阈值范围内{ button-click_count; // 增加点击计数} // 复位按键状态 button-state BUTTON_RELEASED; } }松手之后按键释放那么按键又被上拉到高电平了这里先判断一下你之前的状态必须要判断一下这个按键之前是不是被按下了要不然就会一直进入这个if语句。 由于每次进入这个按键扫描函数都会记录一下HAL_GetTick(); uint32_t press_duration button-release_time - button-press_time; // 计算按下持续时间所以记下了你上次按下按键与这次松开按键的时间间隔那么这就可以得出你的按下时间如果超过了长按阈值那么肯定就是长按状态了就执行对应的长按操作。 如果你的时间间隔少于长按的时间阈值那么就会给你增加一次点击计数。 之后你松开了按键那么可能要把按键的状态恢复到初始化的情况。 这时这个函数还没有结束接下来会进入到这个if语句 if (button-click_count) // 如果有点击计数{// 距离下一次按下时间大于 DOUBLE_CLICK_TIME 可认为是单击if (button-click_count 1 current_time - button-release_time DOUBLE_CLICK_TIME) {button-click_count 0; // 重置点击计数button_num.once | buttons[i].num; // 标记单击事件}// 否则 在 DOUBLE_CLICK_TIME 时间段内按几下算几连击else if (button-click_count 2 current_time - button-release_time DOUBLE_CLICK_TIME){button-click_count 0; // 重置点击计数button_num.twice | buttons[i].num; // 标记双击事件} }如果你按下按键的时间低于长按的时间阈值的话那么就会进入这个函数否则直接跳过这个if语句。 例如这个时候从头到尾你只按了一次低于长按时间阈值的操作暂停时间分析 再进入这个if语句 if (button-click_count 1 current_time - button-release_time DOUBLE_CLICK_TIME) {button-click_count 0; // 重置点击计数button_num.once | buttons[i].num; // 标记单击事件} 这里判断你的点击次数为1但是当前你按下到松手后时间还没有超过双击的时间阈值那么 current_time - button-release_time DOUBLE_CLICK_TIME 就是falseif语句就进不去但是如果时间再过去一点 current_time - button-release_time DOUBLE_CLICK_TIME 就是true时间超过了双击的阈值所以直接判断为单击。 再回到例如这个时候从头到尾你只按了一次低于长按时间阈值的操作时间暂停分析 接着上面的if判断 if (button-click_count 1 current_time - button-release_time DOUBLE_CLICK_TIME) {button-click_count 0; // 重置点击计数button_num.once | buttons[i].num; // 标记单击事件}目前你还没有超过双击的时间阈值 紧接着你又按下了一次按键并且这一次按下时间同样低于双击的阈值那么就会继续增加的点击计数 直到本次按键的时间间隔大于双击的阈值则判断结束可以返回按键的点击次数了 5.结束 目前代码能够正常检测单击双击长按等操作如果读者使用此代码发现有什么bug或者值得优化的地方欢迎评论区留言
http://www.hkea.cn/news/14536339/

相关文章:

  • 哪里有手机网站建设联系方式网站未经授权推广别人的产品
  • 广州知名网站建设性价比高网站名称怎么变更
  • 网站 建设后台WordPress知更鸟主题怎样安装
  • 27寸显示器网站建设seo营销型网站推广
  • 象山县建设局网站企业网站开发创意
  • 网站域名被注册网站开发历史
  • 制作网站专业app推广团队
  • 如何查看一个网站做的外链简洁wordpress 杂志
  • 体育器材网站建设方案用jsp做的网站需要什么工具
  • 做网站用域名不备案怎么弄做网站有自己的服务器
  • 滨州 网站开发科技公司网站欣赏
  • 合肥网站开发需要多网站服务器技术
  • 怎么在网站里做宣传做的最好的门户网站
  • 网站导航栏固定mysql做网站怎么查看数据库
  • 绮思网站建设qswoo注册一个空壳公司养着
  • 药品和医疗器械 网站备案discuz与wordpress
  • 推进网站集约化建设制度软件定制报价单
  • 网站建设与制作实验报告广告设计服务
  • 保亭交通工程建设局网站wordpress添加视频
  • 商业网站推广外贸seo网站搭建
  • 英文外贸网站建设推广国外有什么优秀的网站推荐
  • 仿站是什么在线做数据图的网站
  • 外贸soho怎么做网站公司页面图片
  • 厦门网站推广用凡客建站做的网站有哪些
  • 电子商务网站的整个建设流程如何设置wordpress会员注册页
  • 住房和城乡建设部的网站周年庆网站要怎么做
  • wordpress 多语言网站网页制作过程怎么写
  • 网站建设服务上海微信公众号怎么创建步骤
  • 建筑模型设计网站建设jsp网站开发好书
  • 手机搭建网站软件运营公司有哪些