STM32F4 按键FIFO设计
来源:互联网 发布:ios wkwebview 传值js 编辑:程序博客网 时间:2024/04/30 10:06
设计按键 FIFO 主要有三个方面的好处:
1. 可以有效的记录按键事件的发生,特别是需要实现按键的按下,长按,弹起等事件,使用 FIFO的方式来实现是一种非常好的思路。
2. 系统是非阻塞的,这样系统在检测到按键按下的情况下,由于机械按键抖动的原因不需要在这里等待一段时间,然后再确定按键是否按下。
3. 按键 FIFO 程序在嘀嗒定时器中定期的执行检测,不需要在主程序中一直做检测,这样可以有效的降低系统资源消耗。
实现代码如下:
1. 可以有效的记录按键事件的发生,特别是需要实现按键的按下,长按,弹起等事件,使用 FIFO的方式来实现是一种非常好的思路。
2. 系统是非阻塞的,这样系统在检测到按键按下的情况下,由于机械按键抖动的原因不需要在这里等待一段时间,然后再确定按键是否按下。
3. 按键 FIFO 程序在嘀嗒定时器中定期的执行检测,不需要在主程序中一直做检测,这样可以有效的降低系统资源消耗。
关于按键是否该使用中断方式去实现的问题,很多初学者都比较模糊,我这里从两方面简单说一下,纯属个人见解,如果那位有更好的意见,欢迎提出来。
从裸机的角度分析
中断方式:中断方式可以有效的检测到按键按下的消息,并执行相应的程序,但是用中断方式实现按键 FIFO 相对就有点麻烦,如果每个按键都是独立的接一个 IO 引脚,需要我们给每个 IO都设置一个中断,程序中过多的中断会影响系统的稳定性。
查询方式:查询方式有一个最大的缺点就是需要程序定期的去执行查询,耗费一定的系统资源,实际上耗费不了多大的系统资源,因为这种查询方式也只是查询按键是否按下,按键事件的执行还是在主程序里面实现。
从 OS 的角度分析
中断方式:在 OS 中要尽可能少用中断方式,因为在 RTOS 中过多的使用中断会影响系统的稳定性和可预见性(抢占式调度的 OS 基本没有可预见性,基于时间触发调度的可预见性要好很多)。比较重要的事件处理需要用中断的方式。
查询方式:对于用户按键推荐使用这种查询方式来实现,现在的 OS 基本都带有 CPU 利用率的功能,这个按键 FIFO 占用的还是很小的,基本都在%1 以下。
这个按键 FIFO 程序主要用于扫描扫描独立按键,具有软件滤波机制,具有按键 FIFO。可以检测如下事件:
1. 按键按下
2. 按键弹起
3. 长按键
4. 长按时自动连发
声明代码如下:
/** ****************************************************************************** * @file: bsp_key.h * @author: xiaofeng * @version: V1.0 * @date : 2015.05.21 * @brief : STM32F4 KEY FIFO ****************************************************************************** * @attention: * ****************************************************************************** *//* Define to prevent recursive inclusion -------------------------------------*/#ifndef __BSP_KEY_H__#define __BSP_KEY_H__#ifdef __cplusplus extern "C" {#endif/* Includes ------------------------------------------------------------------*/#include "stm32f4xx.h"/* Exported types ------------------------------------------------------------*/// 按键IDtypedef enum{KID_K1 = 0,KID_K2,KID_K3, KID_K4}KEY_ID_E;/*定义键值代码, 必须按如下次序定时每个键的按下、弹起和长按事件推荐使用enum, 不用#define,原因:(1) 便于新增键值,方便调整顺序,使代码看起来舒服点(2) 编译器可帮我们避免键值重复。*/typedef enum{KEY_NONE = 0,/* 0 表示按键事件 */KEY1_DOWN,/* 1键按下 */KEY1_UP,/* 1键弹起 */KEY1_LONG,/* 1键长按 */KEY2_DOWN,/* 2键按下 */KEY2_UP,/* 2键弹起 */KEY2_LONG,/* 2键长按 */}KEY_ENUM;/* Exported constants --------------------------------------------------------*//* Exported macro ------------------------------------------------------------*/#define KEY_COUNT 2 // 按键个数#define KEY_FIFO_SIZE 10 // 按键FIFO大小#define KEY_FILTER_TIME 5 // 按键滤波时间50ms, 只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件#define KEY_LONG_TIME 0 // 长按时间. 0,表示不检测长按键; 其他,检测长按键的时间#define KEY_REPEAT_SPEED 0 // 长按键连发速度. 0,表示不支持连发,上报长按事件;其他,连发按下// 按键口对应的RCC时钟及引脚#define RCC_ALL_KEY (RCC_AHB1Periph_GPIOA )#define GPIO_PORT_K1 GPIOA#define GPIO_PIN_K1 GPIO_Pin_0#define GPIO_PORT_K2 GPIOD#define GPIO_PIN_K2 GPIO_Pin_1/* Exported functions --------------------------------------------------------*/ void KEY_Init(void);void KEY_Scan(void);void KEY_FIFO_Clear(void);uint8_t KEY_FIFO_Get(void);uint8_t KEY_GetState(KEY_ID_E ucKeyID);void KEY_SetParam(uint8_t ucKeyID, uint16_t LongTime, uint8_t RepeatSpeed);#ifdef __cplusplus}#endif#endif /*****END OF FILE****/
实现代码如下:
/** ****************************************************************************** * @file: bsp_key.h * @author: xiaofeng * @version: V1.0 * @date : 2015.05.21 * @brief : STM32F4 KEY FIFO ****************************************************************************** * @attention: * ****************************************************************************** *//* Includes ------------------------------------------------------------------*/#include "bsp_key.h"/* Private typedef -----------------------------------------------------------*/// 每个按键对应1个全局的结构体变量。typedef struct{/* 下面是一个函数指针,指向判断按键手否按下的函数 */uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */uint8_t Count;/* 滤波器计数器 */ uint8_t State;/* 按键当前状态(按下还是弹起) */uint16_t LongCount;/* 长按计数器 */uint16_t LongTime;/* 按键按下持续时间, 0表示不检测长按 */uint8_t RepeatSpeed;/* 连续按键周期 */uint8_t RepeatCount;/* 连续按键计数器 */}KEY_T;// 按键FIFO用到变量 typedef struct{uint8_t Buf[KEY_FIFO_SIZE];/* 键值缓冲区 */uint8_t Read;/* 缓冲区读指针 */uint8_t Write;/* 缓冲区写指针 */}KEY_FIFO_T;/* Private define ------------------------------------------------------------*//* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/static KEY_T s_tBtn[KEY_COUNT];static KEY_FIFO_T s_tKey;/* 按键FIFO变量,结构体 *//* Private function prototypes -----------------------------------------------*/static void KEY_FIFO_Init(void);static void KEY_GPIO_Config(void);static void KEY_FIFO_Put(uint8_t _KeyCode);static void KEY_Detect(uint8_t i);/* Private functions ---------------------------------------------------------*//** * @brief:KEY初始化 * @note: * @param : * @retval: */void KEY_Init(void){ KEY_GPIO_Config(); KEY_FIFO_Init();}/** * @brief: 清空按键FIFO缓冲区 * @note: 无 * @param : 无 * @retval: 无 */void KEY_FIFO_Clear(void){s_tKey.Read = s_tKey.Write;}/** * @brief: 从按键FIFO缓冲区读取一个键值 * @note: 无 * @param : * @retval: 按键代码 */uint8_t KEY_FIFO_Get(void){uint8_t ret;if (s_tKey.Read == s_tKey.Write){return KEY_NONE;}else{ret = s_tKey.Buf[s_tKey.Read];if (++s_tKey.Read >= KEY_FIFO_SIZE){s_tKey.Read = 0;}return ret;}}/** * @brief: 读取按键的状态 * @note: 无 * @param : ucKeyID : 按键ID,从0开始 * @retval: 1 表示按下, 0 表示未按下 */uint8_t KEY_GetState(KEY_ID_E ucKeyID){return s_tBtn[ucKeyID].State;}/** * @brief: 设置按键参数 * @note: 无 * @param : ucKeyID : 按键ID,从0开始 * LongTime : 长按事件时间 * RepeatSpeed : 连发速度 * @retval: 无 */void KEY_SetParam(uint8_t ucKeyID, uint16_t LongTime, uint8_t RepeatSpeed){s_tBtn[ucKeyID].LongTime = LongTime;/* 长按时间 0 表示不检测长按键事件 */s_tBtn[ucKeyID].RepeatSpeed = RepeatSpeed;/* 长按键连发的速度,0表示不支持连发 */s_tBtn[ucKeyID].RepeatCount = 0;/* 连发计数器 */}/** * @brief: 扫描所有按键。非阻塞,被周期性的调用(如systick中断) * @note: 无 * @param : 无 * @retval: 无 */void KEY_Scan(void){uint8_t i;for (i = 0; i < KEY_COUNT; i++){KEY_Detect(i);}}/***************************************************************************//** * @brief: 配置按键对应的GPIO * @note: 无 * @param : 无 * @retval: 无 */static void KEY_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;/* 第1步:打开GPIO时钟 */RCC_AHB1PeriphClockCmd(RCC_ALL_KEY, ENABLE);/* 第2步:配置所有的按键GPIO为浮动输入模式(实际上CPU复位后就是输入状态) */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;/* 设为输入口 */GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;/* 设为推挽模式 */GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;/* 无需上下拉电阻 */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/* IO口最大速度 */GPIO_InitStructure.GPIO_Pin = GPIO_PIN_K1;GPIO_Init(GPIO_PORT_K1, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_PIN_K2;GPIO_Init(GPIO_PORT_K2, &GPIO_InitStructure);}/** * @brief: 判断按键是否按下 * @note: 无 * @param : 无 * @retval: 1 表示按下,0表示未按下 */static uint8_t IsKey1Down(void) {if (GPIO_ReadInputDataBit(GPIO_PORT_K1, GPIO_PIN_K1) == 0) return 1;else return 0;}static uint8_t IsKey2Down(void) {if (GPIO_ReadInputDataBit(GPIO_PORT_K2, GPIO_PIN_K2) == 0) return 1;else return 0;}/** * @brief: 初始化按键变量 * @note: 无 * @param : 无 * @retval: 无 */static void KEY_FIFO_Init(void){uint8_t i;/* 对按键FIFO读写指针清零 */s_tKey.Read = 0;s_tKey.Write = 0;/* 给每个按键结构体成员变量赋一组缺省值 */for (i = 0; i < KEY_COUNT; i++){s_tBtn[i].LongTime = KEY_LONG_TIME;/* 长按时间 0 表示不检测长按键事件 */s_tBtn[i].Count = KEY_FILTER_TIME / 2;/* 计数器设置为滤波时间的一半 */s_tBtn[i].State = 0;/* 按键缺省状态,0为未按下 */s_tBtn[i].RepeatSpeed = KEY_REPEAT_SPEED; /* 按键连发的速度,0表示不支持连发 */s_tBtn[i].RepeatCount = 0;/* 连发计数器 */}/* 判断按键按下的函数 */s_tBtn[0].IsKeyDownFunc = IsKey1Down;s_tBtn[1].IsKeyDownFunc = IsKey2Down;}/** * @brief: 将1个键值压入按键FIFO缓冲区 * @note: 无 * @param : KeyCode : 按键代码 * @retval: 无 */static void KEY_FIFO_Put(uint8_t _KeyCode){s_tKey.Buf[s_tKey.Write] = _KeyCode;if (++s_tKey.Write >= KEY_FIFO_SIZE){s_tKey.Write = 0;}}/** * @brief: 检测一个按键。非阻塞状态,必须被周期性的调用 * @note: 无 * @param : 按键数 * @retval: 无 */static void KEY_Detect(uint8_t i){KEY_T *pBtn;pBtn = &s_tBtn[i];if (pBtn->IsKeyDownFunc()){// 按键按下if (pBtn->Count < KEY_FILTER_TIME){pBtn->Count = KEY_FILTER_TIME;}else if(pBtn->Count < 2 * KEY_FILTER_TIME){pBtn->Count++;}else{if (pBtn->State == 0){pBtn->State = 1;/* 发送按钮按下的消息 */KEY_FIFO_Put((uint8_t)(3 * i + 1));}if (pBtn->LongTime > 0){ if (pBtn->LongCount < pBtn->LongTime) { /* 发送按钮持续按下的消息 */ if (++pBtn->LongCount == pBtn->LongTime) { if (pBtn->RepeatSpeed > 0) { pBtn->LongCount = 0; if (++pBtn->RepeatCount >= pBtn->RepeatSpeed) { pBtn->RepeatCount = 0; /* 常按键后,每隔10ms发送1个按键 */ KEY_FIFO_Put((uint8_t)(3 * i + 1)); } } else { /* 键值放入按键FIFO */ KEY_FIFO_Put((uint8_t)(3 * i + 3)); } } }}}}else{// 按键抬起if(pBtn->Count > KEY_FILTER_TIME){pBtn->Count = KEY_FILTER_TIME;}else if(pBtn->Count != 0){pBtn->Count--;}else{if (pBtn->State == 1){pBtn->State = 0;/* 发送按钮弹起的消息 */KEY_FIFO_Put((uint8_t)(3 * i + 2));}}pBtn->LongCount = 0;pBtn->RepeatCount = 0;}}/*****END OF FILE****/
0 0
- STM32F4 按键FIFO设计
- 【STM32F4探索套件】序列之3:按键FIFO机制
- (转)stm32F4-----DMA的FIFO作用和用法
- 异步FIFO设计
- 异步FIFO设计方法
- 同步FIFO设计
- 同步fifo设计
- 同步FIFO设计
- 异步FIFO设计
- STM32F4
- 异步FIFO及FPGA设计
- FIFO设计中的深度计算
- 异步FIFO的设计方法
- FIFO设计中的深度计算
- 八、FPGA设计之FIFO
- 异步FIFO设计与实现
- 异步fifo设计(四)
- 异步FIFO同步化设计
- 索引
- UIPickerView选择省市
- Android仿虾米音乐播放器之专辑图片模糊处理
- 【SSO】--单点登录之过滤器(filter)
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- STM32F4 按键FIFO设计
- USACO Prime Palindromes(dfs)
- MySql基本查询、连接查询、子查询、正则表达查询讲解
- 递归调用
- 并查集
- 微信开发几个坑
- C#基础加强第二天总结--面向对象2及字符串
- pat 1092. To Buy or Not to Buy (20)
- 解决Eclipse中C++代码显示Symbol 'std' could not be resolved的问题