裸机框架:按键模组
一、按键硬件设计的几种方式
1、采用外部上来
外部上拉按键电路设计
2、采用外部上拉加电容滤波消抖
电容滤波按键电路设计
机械按键在接触和断开时产生信号抖动,主要原因有以下几点:
机械弹性作用 按键内部金属弹片在接触瞬间会发生弹性形变与反弹,导致触点多次快速接触/断开。
触点表面粗糙与氧化 金属触点表面并非完全光滑,且可能有氧化层,首次接触时电流导通不稳定,表现为抖动。
机械震动 手按下或弹起按键时,会引发轻微机械震动,使触点在短时间内反复开合。
电气特性 导通瞬间可能伴随电荷积累、放电或电容耦合效应,进一步加剧信号毛刺。
这就是为什么需要硬件(RC电路)或软件(延时/滤波/状态机)消抖来保证单片机正确识别一次按键动作。
对于单片机输入引脚处的信号如下图所示
一次按键动作波形
3、采用单片机内部上拉
采用内部上拉按键电路设计
单片机内部上拉设计
采用这种方式可以外部节省一个电阻,对于物料成本很敏感的设备,还是可以直接采用这种方案的
二、软件设计部分
组件文件
组件文件: P4_CPN/framework/key.h
组件文件: P4_CPN/framework/key.c
Key组件功能总结
1、核心功能
按键事件检测:支持短按、长按、长按释放三种按键事件类型
按键去抖处理:内置20ms的去抖时间,避免按键抖动干扰
长按识别:可识别1500ms的长按操作
多按键管理:支持链表形式管理多个按键实例
2、主要特性
事件类型:
KEY_PRESS
(0):短按事件KEY_LONG_DOWN
(1):长按事件KEY_LONG_UP
(2):长按释放事件
时间配置:
长按确认时间:1500ms
按键去抖时间:20ms
#define LONG_PRESS_TIME 1500 /*长按确认时间 ------------*/
#define KEY_DEBOUNCE_TIME 20 /*按键消抖时间 ------------*/
3、接口函数
key_create()
:创建并注册一个按键实例key_busy()
:判断按键是否处于忙状态key_scan_process()
:按键扫描处理主函数
4、架构设计
采用链表结构管理多个按键
- 每个按键实例包含:
按键读取函数指针
事件处理函数指针
时间戳记录
链表指针
5、key_scan_process
函数处理逻辑详解
key_scan_process
函数是按键扫描处理的核心函数,它通过遍历按键链表来检测和处理所有按键的状态变化。
6、整体流程
函数遍历所有已注册的按键实例(通过链表结构),对每个按键进行状态检测和事件处理。
7、按键状态检测逻辑
7.1. 按键按下检测 (if (k->readkey())
)
首次按下:如果
k->tick == 0
(按键之前未被按下)记录按下时间:
k->tick = get_tick()
持续按下:如果
k->tick != 0
(按键之前已被按下)检查是否达到长按时间:
is_timeout(k->tick, LONG_PRESS_TIME)
如果达到长按时间(1500ms),触发长按事件:
KEY_LONG_DOWN
7.2. 按键释放检测 (else if (k->tick)
)
当按键释放时(k->readkey()
返回 false 且之前有按下记录):
长按释放处理:
检查是否达到长按时间
如果达到,触发长按释放事件:
KEY_LONG_UP
短按释放处理:
条件:超过去抖时间(20ms)但未达到长按时间(1500ms)
触发短按事件:
KEY_PRESS
状态重置:
k->tick = 0
,表示按键回到空闲状态
8、时间控制机制
#define LONG_PRESS_TIME 1500 // 长按确认时间:1.5秒
#define KEY_DEBOUNCE_TIME 20 // 按键去抖时间:20ms
去抖保护:防止按键抖动导致的误触发
长按识别:区分短按和长按操作
事件分类:根据按键持续时间触发不同的事件类型
9、事件触发时机
事件类型 | 触发条件 | 说明 |
---|---|---|
KEY_PRESS | 按键按下后20ms-1500ms内释放 | 短按操作 |
KEY_LONG_DOWN | 按键持续按下1500ms | 长按确认 |
KEY_LONG_UP | 长按后释放按键 | 长按释放 |
10、设计特点
非阻塞扫描:通过定时调用实现按键状态轮询
防抖处理:内置去抖机制,提高按键检测可靠性
多按键支持:链表结构支持管理多个按键实例
事件驱动:通过回调函数处理按键事件,实现解耦
11、应用层调用
这个函数通常需要在主循环或定时器中定期调用(如每10-20ms调用一次),以实现实时的按键检测和响应。
static key_t key; /*按键定义*//* * @brief 读取按键电平状态* @return 0 | 1*/
static int readkey(void)
{return GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_4) == 0;
}/* * @brief 按键事件处理* @return type - */
static void key_event(int type, unsigned int duration)
{if (type == KEY_PRESS)led_ctrl(LED_TYPE_GREEN, LED_MODE_FAST, 3); /*短按,绿灯闪3下*/else if (type == KEY_LONG_DOWN)led_ctrl(LED_TYPE_GREEN, LED_MODE_ON, 0); /*长按,绿灯常亮*/else if (type == KEY_LONG_UP)led_ctrl(LED_TYPE_GREEN, LED_MODE_OFF, 0); /*长按后释放,绿灯关闭*/
}/* * @brief 按键 io初始化* PC4 -> key;* @return none*/
static void key_io_init(void)
{gpio_conf(GPIOC, GPIO_Mode_IN, GPIO_PuPd_UP, GPIO_Pin_4);key_create(&key, readkey, key_event); /*创建按键*/
}driver_init("key", key_io_init); /*按键初始化*/
task_register("key", key_scan_process, 20); /*按键扫描任务, 20ms轮询1次*/
这个组件设计简洁高效,通过回调函数机制实现了按键检测与事件处理的解耦,便于在不同项目中复用和扩展。
欢迎关注交流,需要源码可留言!!!