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

按键检测函数

 一、如何进行按键检测           

检测按键有中断方式和GPIO查询方式两种。

1.从裸机的角度分析      

中断方式:中断方式可以快速地检测到按键按下,并执行相应的按键程序,但实际情况是由于按键的机械抖动特性,在程序进入中断后必须进行滤波处理才能判定是否有效的按键事件。如果每个按键都是独立的接一个 IO 引脚,需要我们给每个 IO 都设置一个中断,程序中过多的中断会影响系统的稳定性。中断方式跨平台移植困难。   

查询方式:查询方式有一个最大的缺点就是需要程序定期的去执行查询,耗费一定的系统资源。实际上耗费不了多大的系统资源,因为这种查询方式也只是查询按键是否按下,按键事件的执行还是在主程序里面实现。

2.从OS的角度分析

  • 中断方式:在 OS 中要尽可能少用中断方式,因为在RTOS中过多的使用中断会影响系统的稳定性和可预见性。只有比较重要的事件处理需要用中断的方式。

  • 查询方式:对于用户按键推荐使用这种查询方式来实现,现在的OS基本都带有CPU利用率的功能,这个按键FIFO占用的还是很小的,基本都在1%以下。

二、按键检测程序

#define KEY0_PRES 1  //KEY0  
#define KEY1_PRES 2  //KEY1 
#define WKUP_PRES 3  //WK_UP u8 KEY_Scan(u8 mode)
{  static u8 key_up=1;//按键按松开标志if(mode)key_up=1;  //支持连按    if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)){delay_ms(10);//去抖动 key_up=0;if(KEY0==0)return KEY0_PRES;else if(KEY1==0)return KEY1_PRES;else if(WK_UP==1)return WKUP_PRES; }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;       return 0;// 无按键按下
}int main(void)
{ u8 t=0;   delay_init();       //延时函数初始化   LED_Init();       //初始化与LED连接的硬件接口KEY_Init();           //初始化与按键连接的硬件接口LED=0;     //点亮LEDwhile(1){t=KEY_Scan(0);  //得到键值switch(t){     case KEY0_PRES:  //如果KEY0按下LED=!LED;break;default:delay_ms(10); } }
}

三、FIFO

先要回答为什么要使用FIFO。只有搞清楚使用FIFO的好处,你才会有意无意的使用FIFO。学习FIFO机制和状态机机制一样,都是在裸机编程中非常重要的编程思想。编程思想很重要。初级coder总是在关注代码具体是怎么写,高级coder关注的是程序的框架逻辑。

FIFO是先入先出的意思,即谁先进入队列,谁先出去。比如我们需要串口打印数据,当使用缓存将该数据保存的时候,在输出数据时必然是先进入的数据先出去,那么该如何实现这种机制呢?首先就是建立一个缓存空间,这里假设为10个字节空间进行说明。  

 

从这张图就知道如果要使用FIFO,就要定义一个结构体,而这个结构体至少应该有三个成员。数组buf、读指针read、写指针write

typedef struct
{uint8_t Buf[10];  /* 缓冲区 */uint8_t Read;   /* 缓冲区读指针*/uint8_t Write;   /* 缓冲区写指针 */
}KEY_FIFO_T;

缓存一开始没有数据,并且用一个变量write指示下一个写入缓存的索引地址,这里下一个存放的位置就是0,用另一个变量read 指示下一个读出缓存的索引地址,并且下一个读出数据的索引地址也是0。目前队列中是没有数据的,也就是不能读出数据,队列为空的判断条件在这里就是两个索引值相同。

现在开始存放数据:

在这里可以看到队列中加入了9个数据,并且每加入一个数据后队尾索引加 1,队头不变,这就是数据加入队列的过程。但是缓存空间只有10个,如何判断队列已满呢?如果只是先一次性加数据到队列中,然后再读出数据,那这里的判断条件显然是队尾索引为9。

好了这就是FIFO的基本原理,下面来看一下按键FIFO是怎么操作的

我们这里以5个字节的FIFO空间进行说明。Write变量表示写位置,Read 变量表示读位置。初始状态时,Read = Write = 0。

我们依次按下按键 K1,K2,那么FIFO中的数据变为:

如果 Write!= Read,则我们认为有新的按键事件。我们通过函数KEY_FIFO_Get()读取一个按键值进行处理后,Read 变量变为 1。Write 变量不变。

继续通过函数KEY_FIFO_Get()读取 3 个按键值进行处理后,Read 变量变为 4。此时Read = Write= 4。两个变量已经相等,表示已经没有新的按键事件需要处理。

有一点要特别的注意,如果 FIFO 空间写满了,Write 会被重新赋值为 0,也就是重新从第一个字节空间填数据进去,如果这个地址空间的数据还没有被及时读取出来,那么会被后来的数据覆盖掉,这点要引起大家的注意。我们的驱动程序开辟了 10 个字节的 FIFO 缓冲区,对于一般的应用足够了。

五、按键FIFO的优点

  • 可靠地记录每一个按键事件,避免遗漏按键事件。特别是需要实现按键的按下、长按、自动连发、弹起等事件时。

  • 读取按键的函数可以设计为非阻塞的,不需要等待按键抖动滤波处理完毕。

  • 按键 FIFO 程序在嘀嗒定时器中定期的执行检测,不需要在主程序中一直做检测,这样可以有效地降低系统资源消耗。

  • 六、按键 FIFO 的实现

1.定义结构体

在我们的key.h文件中定义一个结构体类型为KEY_FIFO_T的结构体。就是前面说的那个结构体。这只是类型声明,并没有分配变量空间。

typedef struct
{uint8_t Buf[10];  /* 缓冲区 */uint8_t Read;   /* 缓冲区读指针*/uint8_t Write;   /* 缓冲区写指针 */
}KEY_FIFO_T;

接着在key.c 中定义 s_tKey 结构变量, 此时编译器会分配一组变量空间。

static KEY_FIFO_T s_tKey;/* 按键FIFO变量,结构体 */

好了按键FIFO的结构体数据类型就定义完了,很简单吧!

2.将键值写入FIFO

既然结构体都定义好了,接着就是往这个FIFO的数组中写入数据,也就是按键的键值,用来模拟按键的动作了。

**********************************************************
* 函 数 名: KEY_FIFO_Put
* 功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
* 形    参:  _KeyCode : 按键代码
* 返 回 值: 无
**********************************************************
*/
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;}
}

函数的主要功能就是将按键代码_KeyCode写入到FIFO中,而这个FIFO就是我们定义结构体的这个数组成员,每写一次,就是每调用一次KEY_FIFO_Put()函数,写指针write就++一次,也就是向后移动一个空间,如果FIFO空间写满了,也就是s_tKey.Write >= KEY_FIFO_SIZE,Write会被重新赋值为 0。

3.从FIFO读出键值

有写入键值当然就有读出键值。

/*
***********************************************************
* 函 数 名: KEY_FIFO_Get
* 功能说明: 从按键FIFO缓冲区读取一个键值。
* 形    参: 无
* 返 回 值: 按键代码
************************************************************
*/
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;}
}

如果写指针和读出的指针相等,那么返回值就为0,表示按键缓冲区为空,所有的按键时间已经处理完毕。如果不相等就说明FIFO的缓冲区不为空,将Buf中的数读出给ret变量。同样,如果FIFO空间读完了,没有缓存了,也就是s_tKey.Read >= KEY_FIFO_SIZE,Read也会被重新赋值为 0。按键的键值定义在key.h 文件,下面是具体内容:

typedef enum
{KEY_NONE = 0,   /* 0 表示按键事件 */KEY_1_DOWN,    /* 1键按下 */KEY_1_UP,    /* 1键弹起 */KEY_1_LONG,    /* 1键长按 */KEY_2_DOWN,    /* 2键按下 */KEY_2_UP,    /* 2键弹起 */KEY_2_LONG,    /* 2键长按 */KEY_3_DOWN,    /* 3键按下 */KEY_3_UP,    /* 3键弹起 */KEY_3_LONG,    /* 3键长按 */
}KEY_ENUM;

必须按次序定义每个键的按下、弹起和长按事件,即每个按键对象占用 3 个数值。推荐使用枚举enum, 不用#define的原因是便于新增键值,方便调整顺序。使用{ } 将一组相关的定义封装起来便于理解。编译器也可帮我们避免键值重复。

上面说了如何将按键的键值存入和读出FIFO,但是既然是按键操作,就肯定涉及到按键消抖处理,还有按键的状态是按下还是弹起,是长按还是短按。所以为了以示区分,我们用还需要给每一个按键设置很多参数,就需要再定义一个结构体KEY_T,让每个按键对应1个全局的结构体变量。

typedef struct
{/* 下面是一个函数指针,指向判断按键手否按下的函数 */uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */uint8_t  Count;   /* 滤波器计数器 */uint16_t LongCount;  /* 长按计数器 */uint16_t LongTime;  /* 按键按下持续时间, 0表示不检测长按 */uint8_t  State;   /* 按键当前状态(按下还是弹起) */uint8_t  RepeatSpeed; /* 连续按键周期 */uint8_t  RepeatCount; /* 连续按键计数器 */
}KEY_T;

在key.c 中定义s_tBtn结构体数组变量。

static KEY_T   s_tBtn[3] = {0};

每个按键对象都分配一个结构体变量,这些结构体变量以数组的形式存在将便于我们简化程序代码行数。因为我的硬件有3个按键,所以这里的数组元素为3。使用函数指针IsKeyDownFunc可以将每个按键的检测以及组合键的检测代码进行统一管理。

因为函数指针必须先赋值,才能被作为函数执行。因此在定时扫描按键之前,必须先执行一段初始化函数来设置每个按键的函数指针和参数。这个函数是void KEY_Init(void)

void KEY_Init(void)
{KEY_FIFO_Init();  /* 初始化按键变量 */KEY_GPIO_Config();  /* 初始化按键硬件 */
}

下面是KEY_FIFO_Init函数的定义:

static void KEY_FIFO_Init(void)
{uint8_t i;/* 对按键FIFO读写指针清零 */s_tKey.Read = 0;s_tKey.Write = 0;/* 给每个按键结构体成员变量赋一组缺省值 */for (i = 0; i < HARD_KEY_NUM; i++){s_tBtn[i].LongTime = 100;/* 长按时间 0 表示不检测长按键事件 */s_tBtn[i].Count = 5/ 2; /* 计数器设置为滤波时间的一半 */s_tBtn[i].State = 0;/* 按键缺省状态,0为未按下 */s_tBtn[i].RepeatSpeed = 0;/* 按键连发的速度,0表示不支持连发 */s_tBtn[i].RepeatCount = 0;/* 连发计数器 */}/* 判断按键按下的函数 */s_tBtn[0].IsKeyDownFunc = IsKey1Down;s_tBtn[1].IsKeyDownFunc = IsKey2Down;s_tBtn[2].IsKeyDownFunc = IsKey3Down;
}

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

http://www.dtcms.com/a/392125.html

相关文章:

  • CTFshow系列——PHP特性Web109-112
  • 字符函数与字符串函数
  • 酷9 1.7.3 | 支持自定义添加频道列表,适配VLC播放器内核,首次打开无内置内容,用户可完全自主配置
  • Slurm sbatch 全面指南:所有选项详解
  • 使用SCP命令在CentOS 7上向目标服务器传输文件
  • Kindle Oasis 刷安卓系统CrackDroid
  • 最新超强系统垃圾清理优化工具--Wise Care 365 PRO
  • JeecgBoot权限控制系统解析:以具体模块为例
  • 2025年职场人AI认证与学习路径深度解析
  • 硬件开发_基于STM32单片机的智能垃圾桶系统2
  • CSS Display Grid布局 grid-template-columns grid-template-rows
  • 在 Spring Boot 中,针对表单提交和请求体提交(如 JSON) 两种数据格式,服务器端有不同的接收和处理方式,
  • NL2SQL简单使用
  • 数据结构:二叉树OJ
  • 【Linux手册】生产消费者模型的多模式实践:阻塞队列、信号量与环形队列的并发设计
  • Python + Flask + API Gateway + Lambda + EKS 实战
  • 【OpenGL】openGL常见矩阵
  • DeepSeek大模型混合专家模型,DeepSeekMoE 重构 MoE 训练逻辑
  • 450. 删除二叉搜索树中的节点
  • 实用工具:基于Python的图片定位导出小程序
  • 滚珠螺杆在工业机器人关节与线性模组的智能控制
  • 【AI】coze的简单入门构建智能体
  • Python数据分析:函数定义时的装饰器,好甜的语法糖。
  • Java数据结构——包装类和泛型
  • 【C++进阶】C++11的新特性 | 列表初始化 | 可变模板参数 | 新的类功能
  • 广东省省考备考(第一百零三天9.20)——言语(强化训练)
  • 面试编程题(四)
  • OpenHarmony之充电振动定制
  • 前端单元测试入门:使用 Vitest + Vue 测试组件逻辑与交互
  • 泛英国生物样本库全基因组关联分析