这个代码片段是基于STM32G4系列微控制器设计的,适用于处理嵌入式系统的按键事件检测(如蓝桥杯嵌入式比赛项目中可能会用到)。在蓝桥杯这类嵌入式编程竞赛中,通常会要求选手通过编程实现对硬件资源的有效利用,包括但不限于GPIO引脚控制、中断服务程序以及定时器的应用。
在这个示例中,通过KEY_scan()
函数实现了对按键状态的扫描与处理。首先,进行按键消抖以确保准确读取按键动作;接着,根据按键按下和释放的时间间隔判断短按、长按和双击事件,并将结果存储在keyvalue
变量中。
同时,配合使用定时器TIM4的周期溢出中断回调函数HAL_TIM_PeriodElapsedCallback()
,在按键被持续按下的过程中累计key_sum
值,用于辅助识别长按事件。
这段代码展示了在嵌入式系统开发中如何结合中断和主循环来精确识别和处理不同类型的按键事件,对于参加蓝桥杯等嵌入式编程竞赛具有参考价值。
#include "KEY.h"
// 定义变量,key_sum 用于累计按键状态,key_count 未使用(可考虑移除或赋予其他用途)
// keyvalue 用于存储最终的按键事件类型(短按、长按、双击),count 记录连续按键次数
// flag 未使用(可考虑移除或赋予其他用途),k_flag 标记按键是否被按下
// last_press_time 记录上次按键发生的时间
uint8_t key_sum = 0,keyvalue = 0, count=0;
volatile bool k_flag=0;
uint32_t last_press_time = 0; // 存储上次按键时间戳
// 按键扫描函数
void KEY_scan()
{
uint32_t current_time = HAL_GetTick(); // 获取当前系统时间
// 检查按键1是否被按下
if(key1 == 0) {
HAL_Delay(5); // 实施消抖操作,延时5ms
if(key1 == 0) { // 再次确认按键状态以确保不是误触发
k_flag = 1; // 设置按键标志位为已按下
count = 1; // 初始化连续按键计数器
last_press_time = current_time; // 更新最后一次有效按键时间
}
} else {
k_flag = 0; // 若按键未被按下,重置按键标志位
// 判断是否满足双击条件
if(count == 1 && (current_time - last_press_time <= 65)) {
keyvalue = 3; // 双击事件
count = 0;
}
// 判断是否为长按或短按
if(key_sum > 80) {
keyvalue = 2; // 长按事件
} else if((key_sum < 50) && (key_sum > 10)) {
keyvalue = 1; // 短按事件
}
// 清零累计按键状态值,准备下一轮检测
key_sum = 0;
}
}
// 定时器中断服务程序回调函数
// 当定时器TIM4周期溢出时,此函数将被调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// 判断是否为定时器TIM4的中断
if(htim->Instance==TIM4)
{
// 如果按键已被按下(k_flag==1),则增加key_sum的值
if(k_flag==1) {
key_sum++;
}
}
}
以上代码通过定时器中断实时累计按键状态,并结合按键释放后的检测逻辑,实现了对按键短按、长按及双击的精准识别。在具体应用中,可以根据项目的实际需求调整按键事件判定的时间阈值等参数。
-
中断与主循环耦合度高:按键事件的判断主要依赖于定时器中断与主循环之间的配合,这种设计使得两者耦合度较高。如果能将按键状态机独立出来,并通过中断触发状态转移,那么代码的可读性和维护性会更好。