实现红外触感按键扫描函数

函数目标

检测 GPIOC第8号引脚 的电平状态(假设低电平触发),实现按键消抖和状态锁定,返回键值 5 表示按键被按下,未按下时返回 0xff


代码逐行解析

1. 变量定义

u8 ir_value = 0xff;          // 默认返回未按下状态(0xff)
static u8 ir_flag = 1;        // 状态锁存标志,初始为1(允许检测)
  • ir_value:存储按键返回值,初始化 0xff 表示未按下。

  • ir_flag:静态变量(保持状态跨函数调用),初始为 1,用于锁定按键状态,防止重复触发。


2. 首次条件检测(按下检测)

if(~(GPIOC->IDR & (1<<8)) | ir_flag) {
    delay_ms(50);
    // ...
}
  • 条件逻辑

    • GPIOC->IDR & (1<<8):读取 GPIOC 第8号引脚的输入电平。

    • ~(...):取反操作,假设低电平有效(如 0 表示按下)。

    • 按位或 | ir_flag:若 ir_flag=1,条件恒成立(可能需改为 逻辑或 ||,此处可能存在代码错误,后文分析)。

  • 作用

    • 当检测到 引脚低电平 或 ir_flag=1 时,进入消抖流程。


3. 消抖与状态确认

delay_ms(50);                     // 延时50ms消抖
if(~(GPIOC->IDR & (1<<8))) {      // 再次检测引脚电平
    ir_value = 5;                 // 确认按下,返回键值5
    ir_flag = 0;                  // 锁定状态,防止重复触发
}
  • 消抖逻辑

    • 延时 50ms 跳过按键抖动期。

    • 二次检测引脚电平,若仍为低电平,确认有效按下。

  • 状态锁定

    • 设置 ir_flag=0,后续条件 ~(GPIOC->IDR & (1<<8)) | ir_flag 不再成立,避免重复触发。


4. 按键释放检测

if(GPIOC->IDR & (1<<8)) {     // 检测引脚是否为高电平(释放)
    ir_flag = 1;              // 恢复标志,允许下次检测
}
  • 逻辑

    • 当引脚恢复高电平时,重置 ir_flag=1,解除状态锁定。

    • 确保下次按键按下时可重新触发。


关键机制:ir_flag 的状态锁定

  1. 初始状态

    • ir_flag=1,允许检测按键按下。

  2. 按下锁定

    • 首次检测到低电平后,消抖确认,设置 ir_flag=0

    • 后续函数调用中,由于 ir_flag=0,条件 ~(GPIOC->IDR & (1<<8)) | ir_flag 不再成立,避免重复返回键值。

  3. 释放解锁

    • 引脚恢复高电平时,重置 ir_flag=1,恢复检测能力。


潜在问题与改进建议

1. 按位或 (|) 误用
  • 问题:原代码使用 按位或 |,可能导致条件判断错误。

    c

    复制

    if(~(GPIOC->IDR & (1<<8)) | ir_flag)  // 错误写法
  • 修复:应改为 逻辑或 ||

    if((~(GPIOC->IDR & (1<<8)) != 0) || (ir_flag != 0))  // 正确逻辑
2. 消抖时间优化
  • 问题50ms 消抖时间较长,可能导致响应延迟。

  • 建议:根据实际按键抖动特性调整(通常 10-20ms)。

3. 返回值设计
  • 问题:未按下时返回 0xff,按下返回 5,但未处理多按键或错误状态。

  • 建议:使用枚举或宏定义键值,提高可读性。


优化后的代码

#define KEY_PRESSED  5
#define KEY_RELEASED 0xff

u8 ir_key_() {
    u8 ir_value = KEY_RELEASED;  // 默认未按下
    static u8 ir_flag = 1;       // 状态锁存标志

    // 检测按下条件(逻辑或修复)
    if((~(GPIOC->IDR & (1<<8)) != 0) || (ir_flag != 0)) {
        delay_ms(20);  // 优化消抖时间
        // 确认按下
        if((~(GPIOC->IDR & (1<<8)) != 0) {
            ir_value = KEY_PRESSED;
            ir_flag = 0;  // 锁定
        }
    }

    // 检测释放
    if((GPIOC->IDR & (1<<8)) != 0) {
        ir_flag = 1;  // 解锁
    }

    return ir_value;
}

总结

  • 核心逻辑:通过 ir_flag 实现按键状态锁定与释放,结合消抖确保稳定检测。

  • 关键点

    • 静态变量 ir_flag 跨函数调用保持状态。

    • 消抖延时过滤抖动信号。

    • 引脚释放后重置标志,恢复检测能力。

  • 改进方向:修复逻辑运算符、优化消抖时间、增强代码可读性。

你可能感兴趣的:(stm32项目实现,stm32)