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

微网站免费制作企业微信网站开发公司

微网站免费制作,企业微信网站开发公司,98建筑人才网,企业建网站的案例常见的按键判定程序,如正点原子按键例程,只能判定单击事件,对于双击、长按等的判定逻辑较复杂,且使用main函数循环扫描的方式,容易被阻塞,或按键扫描函数会阻塞其他程序的执行。使用定时器设计状态机可以规…

常见的按键判定程序,如正点原子按键例程,只能判定单击事件,对于双击、长按等的判定逻辑较复杂,且使用main函数循环扫描的方式,容易被阻塞,或按键扫描函数会阻塞其他程序的执行。使用定时器设计状态机可以规避这一问题。

本文在博主 老子姓李! 程序的基础上添加连按功能,整合双击功能并补充双击二次按下消抖,添加可调消抖时间,扩展为多按键,修改在定时器运行状态机,在主函数判断,并尽可能多的添加注释方便阅读。。
参考博主文章【源码详解-按键状态机-简洁易懂】1.单个按键实现短按长按的功能(基于STM32)

功能介绍

本程序功能:
使用定时器状态机实现按键单击、双击、长按、连按功能。消抖时间可调,长按时间可调,双击判定时间可调,连按单击间隔可调。无延时不阻塞,稳定触发。移植只需修改读IO函数,结构体初始化和宏定义时间参数即可。

注:

  1. 在定时器状态机判定产生事件标志,在主函数处理并清除事件标志。
  2. 单击、长按、双击事件为抬起时触发。
  3. 使能双击会稍微滞后单击事件的判定,可以选择是否使能双击判定。
  4. 可选择是否使能长按判定。
  5. 连按功能是指长按一定时间不松后,间隔较短时间多次触发快速单击事件,松开后结束。“快速单击”为单独事件,不与单击、长按事件冲突。

代码

头文件 my_key.h

#ifndef ___MY_KEY_H__
#define ___MY_KEY_H__#define KEY_DEBOUNCE_TIME 10      //消抖时间
#define KEY_LONG_PRESS_TIME 500   //长按判定时间
#define KEY_QUICK_CLICK_TIME 100  //连按时间间隔
#define KEY_DOUBLE_CLICK_TIME 200 //双击判定时间#define KEY_PRESSED_LEVEL 0 //按键被按下时的电平
#define TOTAL_KEYS 5        //物理按键数量//按键事件
typedef enum
{KEY_Event_Null,        //空事件KEY_Event_SingleClick, //单击KEY_Event_LongPress,   //长按KEY_Event_QuickClick,  //连击KEY_Event_DoubleClick, //双击
} KEY_EventList_TypeDef;//按键动作
typedef enum
{KEY_Action_Press,   //按住KEY_Action_Release, //松开
} KEY_Action_TypeDef;//按键状态
typedef enum
{KEY_Status_Idle,             //空闲KEY_Status_Debounce,         //消抖KEY_Status_ConfirmPress,     //确认按下KEY_Status_ConfirmPressLong, //确认长按KEY_Status_WaitSecondPress,  //等待再次按下KEY_Status_SecondDebounce,   //再次消抖KEY_Status_SecondPress,      //再次按下
} KEY_StatusList_TypeDef;// 按键引脚的电平
typedef enum
{KKEY_PinLevel_Low,KEY_PinLevel_High,KEY_PinLevel_Unknow,
} KEY_PinLevel_TypeDef;//按键配置
typedef struct
{uint8_t KEY_Label;                 //按键标号uint16_t KEY_Count;                //按键按下计时KEY_Action_TypeDef KEY_Action;     //按键动作,按下或释放KEY_StatusList_TypeDef KEY_Status; //按键状态KEY_EventList_TypeDef KEY_Event;   //按键事件
} KEY_Configure_TypeDef;extern KEY_Configure_TypeDef KeyConfig[TOTAL_KEYS];
extern KEY_EventList_TypeDef key_event[TOTAL_KEYS];
extern uint8_t double_click_mode;
extern uint8_t long_press_mode;void KEY_ReadStateMachine(KEY_Configure_TypeDef *KeyCfg);#endif

源文件 my_key.c

#include "my_key.h"//单独封装函数方便移植
static KEY_PinLevel_TypeDef KEY_ReadPin(uint8_t key_label)
{switch (key_label){case 1:return (KEY_PinLevel_TypeDef)HAL_GPIO_ReadPin(K1_GPIO_Port, K1_Pin);case 2:return (KEY_PinLevel_TypeDef)HAL_GPIO_ReadPin(K2_GPIO_Port, K2_Pin);case 3:return (KEY_PinLevel_TypeDef)HAL_GPIO_ReadPin(K3_GPIO_Port, K3_Pin);case 4:return (KEY_PinLevel_TypeDef)HAL_GPIO_ReadPin(K4_GPIO_Port, K4_Pin);case 5:return (KEY_PinLevel_TypeDef)HAL_GPIO_ReadPin(K5_GPIO_Port, K5_Pin);// case X://   return (KEY_PinLevel_TypeDef)HAL_GPIO_ReadPin(KX_GPIO_Port, KX_Pin);}return KEY_PinLevel_Unknow;
}KEY_Configure_TypeDef KeyConfig[TOTAL_KEYS] = {{1, 0, KEY_Action_Release, KEY_Status_Idle, KEY_Event_Null},{2, 0, KEY_Action_Release, KEY_Status_Idle, KEY_Event_Null},{3, 0, KEY_Action_Release, KEY_Status_Idle, KEY_Event_Null},{4, 0, KEY_Action_Release, KEY_Status_Idle, KEY_Event_Null},{5, 0, KEY_Action_Release, KEY_Status_Idle, KEY_Event_Null},// {X, 0, KEY_Action_Release, KEY_Status_Idle, KEY_Event_Null},
};KEY_EventList_TypeDef key_event[TOTAL_KEYS] = {KEY_Event_Null};
uint8_t double_click_mode = 0; //双击模式
uint8_t long_press_mode = 1;   //长按模式
//按键状态处理
void KEY_ReadStateMachine(KEY_Configure_TypeDef *KeyCfg)
{//按键动作读取if (KEY_ReadPin(KeyCfg->KEY_Label) == KEY_PRESSED_LEVEL){KeyCfg->KEY_Action = KEY_Action_Press;}else{KeyCfg->KEY_Action = KEY_Action_Release;}//状态机switch (KeyCfg->KEY_Status){//状态:空闲case KEY_Status_Idle:if (KeyCfg->KEY_Action == KEY_Action_Press) //动作:按下{KeyCfg->KEY_Status = KEY_Status_Debounce; //状态->消抖KeyCfg->KEY_Event = KEY_Event_Null;       //事件->无}else //动作:默认动作,释放{KeyCfg->KEY_Status = KEY_Status_Idle; //状态->空闲KeyCfg->KEY_Event = KEY_Event_Null;   //事件->无}break;//状态:消抖case KEY_Status_Debounce:if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count >= KEY_DEBOUNCE_TIME)) //动作:消抖时间已到,保持按下{KeyCfg->KEY_Count = 0;                        //计数清零KeyCfg->KEY_Status = KEY_Status_ConfirmPress; //状态->确认按下KeyCfg->KEY_Event = KEY_Event_Null;           //事件->无}else if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count < KEY_DEBOUNCE_TIME)) //动作:时间未到,保持按下{KeyCfg->KEY_Count++;                      //消抖计数KeyCfg->KEY_Status = KEY_Status_Debounce; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;       //事件->无}else //动作:消抖时间未到,释放,判定为抖动{KeyCfg->KEY_Count = 0;                //计数清零KeyCfg->KEY_Status = KEY_Status_Idle; //状态->空闲KeyCfg->KEY_Event = KEY_Event_Null;   //事件->无}break;//状态:确认按下case KEY_Status_ConfirmPress:if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count >= KEY_LONG_PRESS_TIME)) //动作:长按时间已到,保持按下{KeyCfg->KEY_Count = KEY_QUICK_CLICK_TIME;         //计数置数,生成第一次连按事件KeyCfg->KEY_Status = KEY_Status_ConfirmPressLong; //状态->确认长按KeyCfg->KEY_Event = KEY_Event_Null;               //事件->无}else if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count < KEY_LONG_PRESS_TIME)) //动作:时间未到,保持按下{KeyCfg->KEY_Count++;                          //长按计数KeyCfg->KEY_Status = KEY_Status_ConfirmPress; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;           //事件->无}else //动作:长按时间未到,释放{if (double_click_mode) //双击模式{KeyCfg->KEY_Count = 0;                           //计数清零KeyCfg->KEY_Status = KEY_Status_WaitSecondPress; //状态->等待再按KeyCfg->KEY_Event = KEY_Event_Null;              //事件->无}else{KeyCfg->KEY_Count = 0;                     //计数清零KeyCfg->KEY_Status = KEY_Status_Idle;      //状态->空闲KeyCfg->KEY_Event = KEY_Event_SingleClick; //事件->单击****}}break;//状态:确认长按case KEY_Status_ConfirmPressLong:if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count >= KEY_QUICK_CLICK_TIME)) //动作:连按时间已到,保持按下{KeyCfg->KEY_Count = 0;                            //计数清零KeyCfg->KEY_Status = KEY_Status_ConfirmPressLong; //状态->维持KeyCfg->KEY_Event = KEY_Event_QuickClick;         //事件->连按****}else if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count < KEY_QUICK_CLICK_TIME)) //动作:时间未到,保持按下{KeyCfg->KEY_Count++;                              //连按计数KeyCfg->KEY_Status = KEY_Status_ConfirmPressLong; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;               //事件->无}else //动作:长按下后释放{if (long_press_mode) //长按模式{KeyCfg->KEY_Count = 0;                   //计数清零KeyCfg->KEY_Status = KEY_Status_Idle;    //状态->空闲KeyCfg->KEY_Event = KEY_Event_LongPress; //事件->长按****}else //非长按模式{KeyCfg->KEY_Count = 0;                     //计数清零KeyCfg->KEY_Status = KEY_Status_Idle;      //状态->空闲KeyCfg->KEY_Event = KEY_Event_SingleClick; //事件->单击****}}break;//状态:等待是否再次按下case KEY_Status_WaitSecondPress:if ((KeyCfg->KEY_Action != KEY_Action_Press) && (KeyCfg->KEY_Count >= KEY_DOUBLE_CLICK_TIME)) //动作:双击等待时间已到,保持释放{KeyCfg->KEY_Count = 0;                     //计数清零KeyCfg->KEY_Status = KEY_Status_Idle;      //状态->空闲KeyCfg->KEY_Event = KEY_Event_SingleClick; //事件->单击****}else if ((KeyCfg->KEY_Action != KEY_Action_Press) && (KeyCfg->KEY_Count < KEY_DOUBLE_CLICK_TIME)) //动作:时间未到,保持释放{KeyCfg->KEY_Count++;                             //双击等待计数KeyCfg->KEY_Status = KEY_Status_WaitSecondPress; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;              //事件->无}else //动作:双击等待时间内,再次按下{KeyCfg->KEY_Count = 0;                          //计数清零KeyCfg->KEY_Status = KEY_Status_SecondDebounce; //状态->再次消抖KeyCfg->KEY_Event = KEY_Event_Null;             //事件->无}break;//状态:再次消抖case KEY_Status_SecondDebounce:if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count >= KEY_DEBOUNCE_TIME)) //动作:消抖时间已到,保持按下{KeyCfg->KEY_Count = 0;                       //计数清零KeyCfg->KEY_Status = KEY_Status_SecondPress; //状态->确认再次按下KeyCfg->KEY_Event = KEY_Event_Null;          //事件->无}else if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count < KEY_DEBOUNCE_TIME)) //动作:时间未到,保持按下{KeyCfg->KEY_Count++;                            //消抖计数KeyCfg->KEY_Status = KEY_Status_SecondDebounce; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;             //事件->无}else //动作:消抖时间未到,释放,判定为抖动{KeyCfg->KEY_Count = 0;                //计数清零KeyCfg->KEY_Status = KEY_Status_Idle; //状态->空闲KeyCfg->KEY_Event = KEY_Event_Null;   //事件->无}break;//状态:再次按下case KEY_Status_SecondPress:if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count >= KEY_LONG_PRESS_TIME)) //动作:长按时间已到,保持按下{if (long_press_mode) //长按模式{KeyCfg->KEY_Count = 0;                            //计数清零KeyCfg->KEY_Status = KEY_Status_ConfirmPressLong; //状态->确认长按KeyCfg->KEY_Event = KEY_Event_SingleClick;        //事件->先响应单击}else //非长按模式{KeyCfg->KEY_Count = 0;                       //计数清零KeyCfg->KEY_Status = KEY_Status_SecondPress; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;          //事件->无}}else if ((KeyCfg->KEY_Action == KEY_Action_Press) && (KeyCfg->KEY_Count < KEY_LONG_PRESS_TIME)) //动作:长按时间未到,保持按下{KeyCfg->KEY_Count++;                         //计数KeyCfg->KEY_Status = KEY_Status_SecondPress; //状态->维持KeyCfg->KEY_Event = KEY_Event_Null;          //事件->无}else //动作:按下后释放{KeyCfg->KEY_Count = 0;                     //计数清零KeyCfg->KEY_Status = KEY_Status_Idle;      //状态->空闲KeyCfg->KEY_Event = KEY_Event_DoubleClick; //事件->双击}break;}if (KeyCfg->KEY_Event != KEY_Event_Null) //事件记录key_event[KeyCfg->KEY_Label] = KeyCfg->KEY_Event;
}

定时器中断和主函数调用
中断周期为1ms

uint32_t tim_cnt = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == htim1.Instance){tim_cnt++;if (tim_cnt % 1 == 0) // 1ms{KEY_ReadStateMachine(&KeyConfig[KEY_1]);KEY_ReadStateMachine(&KeyConfig[KEY_2]);KEY_ReadStateMachine(&KeyConfig[KEY_3]);KEY_ReadStateMachine(&KeyConfig[KEY_4]);KEY_ReadStateMachine(&KeyConfig[KEY_5]);}}
}//调用
int main(void)
{long_press_mode = 1;	 //使能长按模式double_click_mode = 1; //使能双击模式while (1){if (key_event[KEY_1] == KEY_Event_SingleClick) //单击{something1();}if (key_event[KEY_2] == KEY_Event_LongPress) //长按{something2();}if ((key_event[KEY_3] == KEY_Event_QuickClick) || (key_event[KEY_3] == KEY_Event_SingleClick)) //连按{something3();}if (key_event[KEY_4] == KEY_Event_DoubleClick) //双击{something4();}memset(key_event, KEY_Event_Null, sizeof(key_event)); //清除事件}
}
http://www.yayakq.cn/news/991005/

相关文章:

  • 网站域名费用多少钱一年权威的网页设计公司
  • 产品网站开发服务邢台做网站哪里便宜
  • 做什麽网站有前景大连市自然资源局
  • 德米萨erp深圳网站建设优化推广公司
  • 建立网站站点的基本过程网站开发技术支持与保障
  • 好的网页网站设计网站编程 外包类型
  • 做网站一般按什么报价网站黏度
  • c2c代表性企业网站wordpress异次元主题
  • 佛山网站设计制作公司js做网站登录界面
  • 如何自己建设简单的手机网站首页营销推广的渠道
  • 兰州专业做网站电商网站建设内容规划
  • 佛山网站建设玲念建站建站公司兴田德润在哪里
  • 服务器上做网站公司网站建设需要资质
  • 怎么做网站截图网站没有icp备案
  • 优化网站排名软件linux 搭建wordpress
  • 做网站拉广告宏宇网站建设
  • 外贸平台排名seo怎么优化方法
  • 营销型网站建设纪念册设计制作公司
  • 做电商引流软文网站WordPress用户名怎么泄露的
  • 注册网站域名用什么好处扬州建站公司
  • 手机与pc的网站开发东莞志豪建设公司网站
  • 广州网站建设乐云seo张槎建网站
  • 电子商务网站建设课设心得体会个人网站制作教程视频
  • 搞个网站要多少钱中建五局华东建设公司网站
  • 网页版微信二维码不能直接识别seo研究协会网是干什么的
  • 任务平台网站建设建筑网挂兼职
  • 职友集一家做公司点评的网站常德网站设计
  • 那些网站做的非常好看的免费奖励代码网站
  • 网站建设公司不能备案吗网站建设协调会
  • 河南外贸网站制作淘宝网站边上的导航栏怎么做