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

多定时事件优化:行人红绿灯倒计时程序bug排查与代码优化

行人红绿灯倒计时功能Bug修复与代码优化

功能需求

进入倒计时阶段后需持续执行以下逻辑10秒,之后切换至其他任务:

  • 红灯以亮0.8秒、灭0.8秒的频率闪烁;
  • 蜂鸣器每1.6秒触发一次;
  • 数码管从9开始每秒倒计时至0。

现有代码

unsigned long time_start = millis();
unsigned long time_over = millis() + 10001;
unsigned long countdown_1sec = millis();
unsigned long countdown = millis();
unsigned long countdown_last = millis();
unsigned long countdown_last_1sec = millis();
int countdownNum = 9;
bool atZeroRan = false;
bool at800Ran = false;
bool at1600Ran = false;

while(countdown < time_over) {
  if (countdown - countdown_last == 0 && atZeroRan == false) {
    digitalWrite(pedR, HIGH);
    tone(buzzer, 973, 15);
    at1600Ran = false;
    atZeroRan = true;
  }
  if (countdown - countdown_last == 800 && at800Ran == false) {
    digitalWrite(pedR, LOW);
    atZeroRan = false;
    at800Ran = true;
  }
  if (countdown_1sec - countdown_last_1sec == 1000) {
    countdown_last_1sec = millis();
    displayNumber(countdownNum);
    countdownNum = countdownNum - 1;
  }
  if (countdown - countdown_last == 1600 && at1600Ran == false) {
    countdown_last = millis();
    at800Ran = false;
    at1600Ran = true;
  }
  countdown_1sec = millis();
  countdown = millis();
}

digitalWrite(pedR, HIGH);

问题现象

程序多数时候正常,但偶尔出现异常:数码管不更新倒计时、红灯不切换状态,或倒计时在5-8秒左右随机停止更新,已排除电路问题。


修复与优化方案

核心问题分析

现有代码的致命问题是精确判断时间差等于固定值,但millis()的更新是离散的,一旦程序执行有微小延迟,就会错过这个精确时间点,导致事件无法触发;同时多变量重复获取millis(),逻辑耦合度高,容易出现状态混乱。

具体优化措施

  1. 改用「时间差≥阈值」的判断逻辑:放弃精确匹配时间点,只要时间差达到设定值就触发事件,避免漏触发。
  2. 统一时间基准:循环内只获取一次当前millis()值,避免多次调用导致的时间不一致。
  3. 简化状态管理:用单个布尔变量替代多个标记变量,减少逻辑冲突。
  4. 修正倒计时边界:确保数码管从9到0完整显示10次,对应10秒时长。

改进后的代码

unsigned long currentMillis = millis();
unsigned long phaseEndTime = currentMillis + 10000; // 10秒倒计时阶段
unsigned long lastBlinkTime = currentMillis;        // 红灯闪烁/蜂鸣器基准时间
unsigned long lastCountdownTime = currentMillis;    // 数码管倒计时基准时间
int countdownNum = 9;
bool isRedLightOn = true;

// 初始化状态
digitalWrite(pedR, HIGH);
displayNumber(countdownNum);
tone(buzzer, 973, 15);

while (millis() < phaseEndTime) {
  currentMillis = millis();

  // 处理红灯闪烁(0.8秒切换一次)和蜂鸣器(每1.6秒触发一次)
  if (currentMillis - lastBlinkTime >= 800) {
    isRedLightOn = !isRedLightOn;
    digitalWrite(pedR, isRedLightOn ? HIGH : LOW);
    
    // 红灯重新亮起时触发蜂鸣器(刚好每1.6秒一次)
    if (isRedLightOn) {
      tone(buzzer, 973, 15);
    }
    lastBlinkTime = currentMillis;
  }

  // 处理数码管每秒倒计时
  if (currentMillis - lastCountdownTime >= 1000) {
    countdownNum--;
    if (countdownNum >= 0) {
      displayNumber(countdownNum);
    }
    lastCountdownTime = currentMillis;
  }
}

// 阶段结束后红灯保持常亮
digitalWrite(pedR, HIGH);

代码说明

  • 容错性时间判断:用>=替代==,确保即使程序有延迟,事件也能被触发,彻底解决漏触发问题。
  • 统一时间变量:每次循环只获取一次currentMillis,避免多次调用millis()产生的时间误差。
  • 简化状态逻辑:用isRedLightOn直接控制红灯状态,替代原有的多个标记变量,逻辑清晰不易出错。
  • 蜂鸣器触发优化:利用红灯亮的时机(每1.6秒一次)触发蜂鸣器,无需额外计时,降低逻辑复杂度。
  • 完整倒计时保证:确保countdownNum从9递减到0,完整显示10个数字,严格对应10秒时长。

内容的提问来源于stack exchange,提问作者P. Z.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:22:50