C黄豆酱 2026-01-12 20:36 采纳率: 0%
浏览 12

关于#51单片机#的疑惑求解答

请求广大工程师,51单片机简单的 GPIO读取 + 静态变量 的函数
函数功能 是
1、根据当前拨码的位置(即两个IO口的高低电平)切换模式
2、添加了静态变量last_mode只有当拨码有变化才会更新频率
问题出现在
1、只有初始化的第一次才能进入FREQ_MODEL0(模式0)
2、后面无论怎么切换都无法更新FREQ_MODEL0,但是对应的 静态变量last_mode 和局部变量updatemode 都是正常赋值
我处理的方法
1、原本 uint32_t updatemode = 0; 我改成 uint32_t updatemode = 0xFF; (改完后函数就能正常运行了)
2、另一个方法,在整个函数中添加Delay_ms(500);
疑惑求解答:
这是51单片机的什么机制吗,还是说51keil也有什么优化等级
整个函数的逻辑也没没检查出啥问题,ai也没给出一个准确的解答。

// #define FREQ_MODEL0 0
// #define FREQ_MODEL1 1
// #define FREQ_MODEL2 2
// #define FREQ_MODEL3 3
void Read_Dial_State(void)
{
    static uint32_t last_mode = 0;     // 上一次模式
    uint32_t updatemode = 0;       // 
    
    /* 模式0:1KHz */
    if(P03 && P04){
        Delay_ms(20);
        if(P03 && P04){
            updatemode = g_FreqMode = FREQ_MODEL0;
        }
    }
    
    /* 模式1:500Hz */
    else if((!P03) && P04){
        Delay_ms(20);
        if((!P03) && P04){
            updatemode = g_FreqMode = FREQ_MODEL1;            
        }
    }
    
    /* 模式2:250Hz */    
    else if(P03 && (!P04)){
        Delay_ms(20);    
        if(P03 && (!P04)){
            updatemode = g_FreqMode = FREQ_MODEL2;        
        }            
    }
    
    /* 模式3:125Hz */
    else if((!P03) && (!P04)){
        Delay_ms(20);
        if((!P03) && (!P04)){
            updatemode = g_FreqMode = FREQ_MODEL3;            
        }
    }

    if(updatemode != last_mode){  //模式有变化才更新PWM
        last_mode = updatemode;
        PWM_FreqDuty_Update(g_FreqMode_Buffer[g_FreqMode], g_DutyVal);        
    }

}

img

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2026-01-12 20:48
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    你的问题非常典型,尤其是在嵌入式开发中,特别是使用 51单片机 这类对时序要求较高的平台。你提到的“一个简单的GPIO读取函数,只有添加了延时才能正常运行,不加延时就无法切换回FREQ_MODEL0”,这说明你遇到了 按键抖动(Bounce) 的问题。


    一、为什么需要延时?

    1. 按键抖动(Switch Bounce)

    当机械按键被按下或释放时,由于金属触点的弹性变形和接触不良,会产生短时间的不稳定信号,这种现象称为 按键抖动

    • 抖动时间:通常在 5ms ~ 20ms 之间。
    • 如果不处理,可能会导致:
      • 多次误触发(比如一次按键被识别为多次按下)
      • 状态切换错误(如你遇到的无法切换回 FREQ_MODEL0)

    2. 延时的作用

    添加延时是为了等待抖动稳定后再读取按键状态。这样可以确保读取的是稳定的电平,而不是抖动造成的虚假信号。


    二、正确的按键读取逻辑

    ✅ 正确做法(推荐):

    // 定义按键引脚
    #define KEY_PIN P3_2
    
    // 按键检测函数
    bit ReadKey(void) {
        // 初始读取
        if (KEY_PIN == 0) {  // 按键被按下
            delay_ms(20);    // 延时去抖
            if (KEY_PIN == 0) {  // 再次确认
                return 1;      // 按键有效
            }
        }
        return 0;          // 按键无效
    }
    

    三、为什么没有延时就无法切换回 FREQ_MODEL0?

    原因分析:

    • 没有延时,直接读取按键状态,会受到抖动影响,导致状态判断不准确。
    • 即使变量被正确修改,但由于硬件不稳定,可能造成:
      • 按键状态未被正确识别
      • 状态机(state machine)未能正确进入目标状态(如 FREQ_MODEL0)

    四、解决方案总结(有序列表)

    1. 添加延时消除按键抖动

      • 在读取按键前加入 20ms 左右的延时
      • 确保读取的是稳定的电平
    2. 采用双重检测机制

      • 第一次读取按键是否被按下
      • 延时后再读取一次,若状态一致则认为按键有效
    3. 优化状态机逻辑

      • 避免频繁切换状态
      • 添加防抖逻辑,防止误操作
    4. 调试建议

      • 使用示波器观察按键引脚的波形,确认是否有抖动
      • 打印中间变量(如 key_state),验证是否被正确赋值

    五、代码示例(修改后的版本)

    #include <reg52.h>
    
    #define KEY_PIN P3_2
    
    void delay_ms(unsigned int ms) {
        unsigned int i, j;
        for (i = ms; i > 0; i--)
            for (j = 110; j > 0; j--);
    }
    
    bit ReadKey(void) {
        if (KEY_PIN == 0) {  // 按键被按下
            delay_ms(20);    // 去抖
            if (KEY_PIN == 0) {
                return 1;    // 有效按键
            }
        }
        return 0;
    }
    
    void main() {
        while (1) {
            if (ReadKey()) {
                // 按键被按下,切换模式
                // 示例:切换到 FREQ_MODEL0
                // ...
            }
        }
    }
    

    六、其他建议(可选)

    • 如果系统中有多个按键,可以考虑使用中断方式读取,提高响应速度。
    • 对于更复杂的场景,可以使用 软件消抖算法硬件消抖电路(如 RC 滤波)。

    七、总结

    关键点:

    • 按键抖动是根本原因
    • 延时是消除抖动的有效手段
    • 必须结合两次读取来判断按键是否有效

    如果你还有更多关于状态机或 GPIO 控制的问题,欢迎继续提问!

    评论

报告相同问题?

问题事件

  • 修改了问题 1月14日
  • 修改了问题 1月13日
  • 修改了问题 1月13日
  • 修改了问题 1月13日
  • 展开全部