You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATmega328P控制LED异常求助:HC-SR04与按键失效问题

ATmega328P HC-SR04与按键控制LED异常问题分析及修复

故障原因

  • 传感器测量函数的阻塞式死循环:measure_distance中等待ECHO引脚拉高的while (!(PIND & (1 << ECHO_PIN)))无超时处理。若HC-SR04未返回ECHO信号(如检测范围内无物体、接线故障),程序会永久卡在该循环,导致按键及后续逻辑完全停止响应,这是按下按键后功能失效的核心原因。
  • 逻辑优先级冲突:按键切换LED状态后,传感器检测到10cm内物体时会强制调用turn_on_led点亮LED,违背按键手动控制的意图。
  • 按键无消抖处理:机械按键按下/释放时的抖动可能导致toggle_led多次触发,影响功能稳定性。

修改方案

  1. 给传感器测量添加超时机制:在等待ECHO信号的循环中加入计数限制,避免无限阻塞。
  2. 增加模式控制变量:区分「传感器自动控制」和「按键手动控制」模式,解决逻辑冲突。
  3. 添加按键消抖:通过延时和状态判断过滤按键抖动。

修改后的代码

#include <avr/io.h>
#include <util/delay.h>

#define LED_PIN PD2
#define BUTTON_PIN PD3
#define TRIGGER_PIN PD5
#define ECHO_PIN PD6

#define MEASURE_TIMEOUT 10000  // 超时阈值,避免无限等待

void toggle_led() {
    PORTD ^= (1 << LED_PIN);
}

void turn_on_led() {
    if (!(PORTD & (1 << LED_PIN))) {
        PORTD |= (1 << LED_PIN);
    }
}

void turn_off_led() {
    if (PORTD & (1 << LED_PIN)) {
        PORTD &= ~(1 << LED_PIN);
    }
}

uint16_t measure_distance() {
    uint16_t duration = 0;
    uint16_t timeout = MEASURE_TIMEOUT;

    // 发送触发信号
    PORTD |= (1 << TRIGGER_PIN);
    _delay_us(10);
    PORTD &= ~(1 << TRIGGER_PIN);

    // 等待ECHO拉高,带超时
    while (!(PIND & (1 << ECHO_PIN)) && timeout--) {
        _delay_us(1);
    }
    if (timeout == 0) {
        return 0;  // 返回0表示超时,无有效测量
    }

    // 测量ECHO高电平持续时间,带超时
    timeout = MEASURE_TIMEOUT;
    while ((PIND & (1 << ECHO_PIN)) && timeout--) {
        duration++;
        _delay_us(1);
    }

    // 计算距离(cm),58是声波往返时间转距离的系数
    uint16_t distance = (duration / 58);
    return distance;
}

int main(void) {
    // 配置引脚方向
    DDRD |= (1 << LED_PIN) | (1 << TRIGGER_PIN);
    DDRD &= ~((1 << BUTTON_PIN) | (1 << ECHO_PIN));

    // 启用按键引脚内部上拉电阻
    PORTD |= (1 << BUTTON_PIN);

    uint8_t button_state = 1;  // 初始为释放状态(上拉高电平)
    uint8_t last_button_state = 1;
    uint8_t manual_mode = 0;   // 0:传感器自动控制,1:手动控制

    while (1) {
        // 按键处理:消抖+切换模式
        button_state = (PIND & (1 << BUTTON_PIN)) ? 1 : 0;
        if (button_state != last_button_state) {
            _delay_ms(20);  // 消抖延时
            button_state = (PIND & (1 << BUTTON_PIN)) ? 1 : 0;
            if (button_state != last_button_state) {
                if (!button_state) {  // 按键按下(低电平)
                    manual_mode ^= 1;
                    if (manual_mode) {
                        toggle_led();  // 进入手动模式时切换当前LED状态
                    }
                }
                last_button_state = button_state;
            }
        }

        // 传感器控制逻辑(仅自动模式下生效)
        if (!manual_mode) {
            uint16_t distance = measure_distance();
            if (distance <= 10 && distance != 0) {
                turn_on_led();
            } else {
                turn_off_led();
            }
        }

        _delay_ms(50);  // 主循环延时,降低CPU占用
    }

    return 0;
}

关键修改说明

  • 超时机制:在等待ECHO信号的两个循环中加入timeout计数,超时后返回0,避免程序卡死。
  • 模式切换:新增manual_mode变量,按键切换模式而非直接控制LED。自动模式下传感器正常控制LED;手动模式下传感器逻辑失效,进入时切换一次LED状态。
  • 按键消抖:通过两次读取按键状态并加入20ms延时,过滤机械抖动。
  • 内部上拉电阻:启用按键引脚的内部上拉,无需额外外接上拉电阻,简化电路。

内容的提问来源于stack exchange,提问作者Igor Abrunhosa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:40:15