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

求助:七段数码管倒计时功能异常,仅显示当前时间

Arduino SevSeg库4位数码管逐位倒计时问题修复

问题根源分析

原代码存在以下核心逻辑错误:

  • 倒计时逻辑嵌套在分钟进位分支中,仅当分钟变化时才会执行,且每次都会重置starting_val为9999,无法持续推进倒计时
  • 四个位的倒计时判断是顺序执行的,同一时间会全部触发,previousDigitMillis被连续更新,导致逐位效果完全丢失
  • 循环末尾无条件调用sevseg.setNumber(time),直接覆盖了倒计时的显示内容,这是"仅显示当前时间"的核心原因
  • 未区分「倒计时阶段」和「正常显示阶段」,状态逻辑混乱

修正后的代码

#include "SevSeg.h"

SevSeg sevseg;

// 数码管硬件配置
byte numDigits = 4;
byte digitPins[] = {10, 11, 12, 13};
byte segmentPins[] = {9, 2, 3, 5, 6, 8, 7, 4};
bool resistorsOnSegments = true;
byte hardwareConfig = COMMON_CATHODE;

// 时间变量
int seconds = 50;
int minutes = 44;
int hours = 10;
unsigned long previousTimeMillis = 0;
const unsigned long timeInterval = 1000;

// Colleen闪烁控制
const int colleenPin = A0;
bool colleenState = false;

// 倒计时控制变量
unsigned long previousCountdownMillis = 0;
const unsigned long countdownStepInterval = 1000; // 每步倒计时间隔1秒
int currentCount = 9999; // 倒计时当前值
int targetTime; // 目标时间(格式:HHMM)
bool isCountdownFinished = false; // 倒计时完成标志
int currentDigit = 3; // 当前正在倒计时的位:3=千位,2=百位,1=十位,0=个位

void setup() {
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
  sevseg.setBrightness(90);
  pinMode(colleenPin, OUTPUT);
  
  // 初始化目标时间
  targetTime = hours * 100 + minutes;
}

void loop() {
  unsigned long currentMillis = millis();

  // 时间更新逻辑(每秒走时)
  if (currentMillis - previousTimeMillis >= timeInterval) {
    previousTimeMillis = currentMillis;
    
    // Colleen闪烁切换
    colleenState = !colleenState;
    digitalWrite(colleenPin, colleenState ? HIGH : LOW);

    seconds++;
    if (seconds >= 60) {
      seconds = 0;
      minutes++;
      if (minutes >= 60) {
        minutes = 0;
        hours++;
        if (hours >= 24) {
          hours = 0;
        }
      }
      // 更新目标时间(仅在分钟变化时)
      targetTime = hours * 100 + minutes;
    }
  }

  // 倒计时逻辑
  if (!isCountdownFinished) {
    if (currentMillis - previousCountdownMillis >= countdownStepInterval) {
      previousCountdownMillis = currentMillis;
      
      // 根据当前位调整数值
      switch(currentDigit) {
        case 3: // 千位:每次减1000,直到千位等于目标值的千位
          if (currentCount / 1000 == targetTime / 1000) {
            currentDigit = 2; // 切换到百位
          } else {
            currentCount -= 1000;
          }
          break;
        case 2: // 百位:每次减100,直到百位等于目标值的百位
          if ((currentCount / 100) % 10 == (targetTime / 100) % 10) {
            currentDigit = 1; // 切换到十位
          } else {
            currentCount -= 100;
          }
          break;
        case 1: // 十位:每次减10,直到十位等于目标值的十位
          if ((currentCount / 10) % 10 == (targetTime / 10) % 10) {
            currentDigit = 0; // 切换到个位
          } else {
            currentCount -= 10;
          }
          break;
        case 0: // 个位:每次减1,直到等于目标值的个位
          if (currentCount % 10 == targetTime % 10) {
            isCountdownFinished = true; // 倒计时完成
          } else {
            currentCount -= 1;
          }
          break;
      }
    }
    // 显示当前倒计时数值
    sevseg.setNumber(currentCount);
  } else {
    // 倒计时完成,显示当前时间
    sevseg.setNumber(targetTime);
  }

  // 必须保持刷新显示
  sevseg.refreshDisplay();
}

关键修复点说明

  • 状态区分:新增isCountdownFinished标志,明确区分倒计时阶段和正常显示阶段,避免显示内容被覆盖
  • 逐位倒计时逻辑:用currentDigit记录当前正在倒计时的位,通过switch分支实现逐位递减,直到该位达到目标值后切换到下一位
  • 时间逻辑分离:把时间更新和倒计时逻辑分开,倒计时不再依赖分钟进位,而是独立按1秒间隔推进
  • 避免显示覆盖:仅在对应阶段调用setNumber,倒计时阶段显示currentCount,完成后显示目标时间,不会被无条件覆盖

内容的提问来源于stack exchange,提问作者Kevin Derylo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:17:32