基于计数器与定时需求的LED切换功能开发求助
按键控制LED定时切换解决方案
需求说明
- 两个按键分别控制计数器递增/递减,计数器范围为1-5,对应5个LED
- 计数器值为N时,点亮第N个LED(对应
ledOnTime数组索引N-1的时长),其余LED立即熄灭 - 若LED点亮时长未结束时切换计数器,立即关闭当前LED,启动新LED的定时
- LED达到指定时长后自动熄灭
修改后完整代码
//Buttons// const uint8_t MIN_COUNT = 1; const uint8_t MAX_COUNT = 5; //Button1: count up const uint8_t btnUpPin = 2; //Button2: count down const uint8_t btnDownPin = 3; uint8_t currentCount = MIN_COUNT; // 统一计数器,初始为1 unsigned long lastBtnUpTime = 0; unsigned long lastBtnDownTime = 0; const uint8_t DEBOUNCE_DELAY = 35; const uint8_t SHORT_PRESS_THRESHOLD = 500; ////Leds///// const int ledPins[] = {4,5,6,7,8}; // LED引脚数组 const int numOfLeds = sizeof(ledPins) / sizeof(ledPins[0]); // LED点亮时长(毫秒) const unsigned long ledOnTime[] = {19*1000, 44*1000, 9*1000, 7*1000, 33*1000}; // LED控制变量 int currentActiveLed = -1; // 当前激活的LED索引,-1表示无LED点亮 unsigned long ledStartMillis = 0; // LED点亮的起始时间 void setup() { Serial.begin(115200); pinMode(btnUpPin, INPUT_PULLUP); pinMode(btnDownPin, INPUT_PULLUP); // 初始化LED引脚为输出 for (int j = 0; j < numOfLeds; j++) { pinMode(ledPins[j], OUTPUT); digitalWrite(ledPins[j], LOW); // 初始全灭 } } void loop() { handleBtnUp(); handleBtnDown(); handleLedControl(); } // 处理递增按键 void handleBtnUp() { unsigned long currentMillis = millis(); uint8_t btnState = digitalRead(btnUpPin); if (btnState == LOW) { if (currentMillis - lastBtnUpTime > DEBOUNCE_DELAY) { lastBtnUpTime = currentMillis; static unsigned long pressStart = 0; pressStart = currentMillis; // 等待按键释放 while (digitalRead(btnUpPin) == LOW) { // 空循环等待释放,避免重复触发 } unsigned long pressDuration = currentMillis - pressStart; if (pressDuration < SHORT_PRESS_THRESHOLD) { currentCount++; if (currentCount > MAX_COUNT) { currentCount = MIN_COUNT; } Serial.print("当前计数: "); Serial.println(currentCount); } } } } // 处理递减按键 void handleBtnDown() { unsigned long currentMillis = millis(); uint8_t btnState = digitalRead(btnDownPin); if (btnState == LOW) { if (currentMillis - lastBtnDownTime > DEBOUNCE_DELAY) { lastBtnDownTime = currentMillis; static unsigned long pressStart = 0; pressStart = currentMillis; // 等待按键释放 while (digitalRead(btnDownPin) == LOW) { // 空循环等待释放 } unsigned long pressDuration = currentMillis - pressStart; if (pressDuration < SHORT_PRESS_THRESHOLD) { currentCount--; if (currentCount < MIN_COUNT) { currentCount = MAX_COUNT; } Serial.print("当前计数: "); Serial.println(currentCount); } } } } // 处理LED控制逻辑 void handleLedControl() { unsigned long currentMillis = millis(); int targetLedIndex = currentCount - 1; // 计数转LED索引(1→0,2→1...) // 情况1:计数器变化,需要切换LED if (targetLedIndex != currentActiveLed) { // 关闭之前的LED if (currentActiveLed != -1) { digitalWrite(ledPins[currentActiveLed], LOW); } // 启动新LED currentActiveLed = targetLedIndex; ledStartMillis = currentMillis; digitalWrite(ledPins[currentActiveLed], HIGH); Serial.print("点亮LED"); Serial.println(currentCount); } // 情况2:当前LED已达到点亮时长,自动熄灭 if (currentActiveLed != -1) { if (currentMillis - ledStartMillis >= ledOnTime[currentActiveLed]) { digitalWrite(ledPins[currentActiveLed], LOW); currentActiveLed = -1; Serial.print("LED"); Serial.print(currentCount); Serial.println("已自动熄灭"); } } }
关键修改说明
- 统一计数器变量:将原来分散的计数变量合并为
currentCount,简化逻辑避免变量混乱 - 优化按键防抖:基于
millis实现非阻塞防抖,等待按键释放后判断按压时长,避免误触发 - LED状态跟踪:用
currentActiveLed记录当前点亮的LED索引,ledStartMillis记录点亮起始时间,精准控制定时 - 核心控制逻辑:
- 计数器变化时,立即关闭旧LED并启动新LED,重置定时
- 持续检查当前LED的点亮时长,达到设定值后自动熄灭
- 移除风险宏定义:去掉原有的
sec/min宏(易引发运算错误),直接用*1000转换秒为毫秒
内容的提问来源于stack exchange,提问作者lon_ly
相关产品推荐
相关产品推荐

