求助:七段数码管倒计时功能异常,仅显示当前时间
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
相关产品推荐
相关产品推荐

