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

ESP32超声波传感器系统按键控制问题求助:双击关机/单击开机

ESP32传感器系统问题修复

原代码核心问题

  • 赋值/比较运算符混淆:所有if (变量 = 值)的写法都是错误的,这是赋值操作而非逻辑判断,应该用==。这是导致系统状态无法正确切换的根本原因。
  • 按键逻辑混乱:没有正确实现“开机状态下1-2秒内按两次关机”的逻辑,计时变量未正确初始化,脉冲计数逻辑错误,且使用delay阻塞程序导致按键响应不及时。
  • 引脚模式重复设置:在loop中反复调用pinMode,属于冗余操作,应该一次性在setup中完成。
  • LED闪烁阻塞程序:使用delay(5)实现红灯闪烁会阻塞整个系统,导致按键和传感器检测无法正常工作,需改用非阻塞方式。
  • 时间阈值错误:注释标注1秒内按两次,但代码写的是4000毫秒(4秒),与需求不符。
  • 缺少按键消抖:未处理按键机械抖动,容易导致误触发。

修正后的代码

#include <Arduino.h>
#define trigger 27
#define echo 14
#define ledrojo 4
#define ledverde 5
#define BOTON 13

float distancia = 0;
unsigned long ta = 0;
unsigned long lastPressTime = 0; // 记录上次按键时间
int pressCount = 0;              // 按键计数
int sistemaEstado = 0;           // 0=关闭,1=开启
unsigned long lastBlinkTime = 0; // 红灯闪烁计时
const long BLINK_INTERVAL = 500; // 红灯闪烁间隔(毫秒)

void setup() {
  Serial.begin(9600);
  // 初始化所有引脚模式
  pinMode(BOTON, INPUT_PULLUP);
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  pinMode(ledrojo, OUTPUT);
  pinMode(ledverde, OUTPUT);
  
  // 系统初始状态:关闭,LED全灭
  digitalWrite(ledrojo, LOW);
  digitalWrite(ledverde, LOW);
  sistemaEstado = 0;
}

void loop() {
  // 处理按键逻辑
  handleButton();
  
  // 根据系统状态执行对应操作
  if (sistemaEstado == 1) {
    // 传感器检测
    measureDistance();
    // 控制LED
    controlLEDs();
  } else {
    // 系统关闭时,关闭所有输出
    digitalWrite(ledrojo, LOW);
    digitalWrite(ledverde, LOW);
    digitalWrite(trigger, LOW);
  }
}

// 处理按键逻辑:开机按一次,关机1-2秒内按两次
void handleButton() {
  static unsigned long lastDebounceTime = 0;
  const unsigned long DEBOUNCE_DELAY = 50; // 消抖延时
  int buttonState = digitalRead(BOTON);

  // 按键消抖:检测到按键按下(INPUT_PULLUP,低电平为按下)
  if (buttonState == LOW && (millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
    lastDebounceTime = millis();
    
    if (sistemaEstado == 0) {
      // 系统关闭,按一次开机
      sistemaEstado = 1;
      Serial.println("系统已开启");
      pressCount = 0;
    } else {
      // 系统开启,计数按键次数
      pressCount++;
      if (pressCount == 1) {
        // 记录第一次按键时间
        lastPressTime = millis();
      } else if (pressCount == 2) {
        // 检测两次按键间隔是否在1-2秒内
        if (millis() - lastPressTime >= 1000 && millis() - lastPressTime <= 2000) {
          sistemaEstado = 0;
          Serial.println("系统已关闭");
        }
        // 重置计数,避免多次触发
        pressCount = 0;
      }
    }
  }

  // 如果超过2秒未按第二次,重置计数
  if (sistemaEstado == 1 && pressCount == 1 && (millis() - lastPressTime) > 2000) {
    pressCount = 0;
  }
}

// 超声波传感器测距
void measureDistance() {
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);

  ta = pulseIn(echo, HIGH);
  if (ta == 0) {
    // 超时处理,默认设为远距
    distancia = 100;
    return;
  }
  ta = ta / 2;
  distancia = ta / 29.1; // 修正系数,提高测距准确性
}

// 控制LED状态
void controlLEDs() {
  if (distancia <= 30) {
    // 红灯闪烁(非阻塞)
    if (millis() - lastBlinkTime >= BLINK_INTERVAL) {
      lastBlinkTime = millis();
      digitalWrite(ledrojo, !digitalRead(ledrojo));
    }
    digitalWrite(ledverde, LOW);
    Serial.println("¡PELIGRO, RETROCEDA!");
  } else {
    // 绿灯常亮,红灯熄灭
    digitalWrite(ledverde, HIGH);
    digitalWrite(ledrojo, LOW);
  }
}

关键修改说明

  • 修复运算符错误:将所有赋值=替换为比较==,确保逻辑判断正确。
  • 重构按键逻辑:用millis()实现非阻塞计时,加入消抖处理,准确实现“开机按一次,关机1-2秒内按两次”的需求,避免阻塞程序。
  • 引脚初始化移至setup:所有pinMode调用放在setup中,避免loop中重复执行的冗余操作。
  • 非阻塞LED闪烁:用millis()替代delay实现红灯闪烁,确保系统其他功能(按键、传感器)能正常响应。
  • 传感器优化:加入pulseIn超时判断,避免传感器无信号时程序阻塞,修正距离计算系数提高准确性。
  • 状态变量命名优化:将estadosistema改为sistemaEstado,变量名更清晰易读。

内容的提问来源于stack exchange,提问作者28nodbot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 05:50:27