Arduino RGB循环立即停止问题求助:按下Button2无法中断当前循环
Arduino RGB灯循环立即停止问题解决方案
你的问题根源在于使用了阻塞式的delay()函数——一旦程序进入delay(500),就会完全暂停执行,直到500ms延时结束,期间即使中断触发设置了stopCycle = true,也没法立刻响应,必须等当前延时跑完才会回到loop里检查状态。
要实现按下按钮立即停止的效果,必须用非阻塞式定时替代delay(),核心思路是用millis()记录每个颜色状态的起始时间,在loop循环中不断检查时间差是否达到切换条件,同时每次循环都检查stopCycle状态,这样就能做到实时响应中断。
修改后的完整代码
// 引脚定义 const int redLed = 9; const int greenLed = 8; const int blueLed = 7; const int button1 = 3; const int button2 = 2; // 状态变量 volatile boolean stopCycle = false; // 中断修改的变量必须加volatile unsigned long previousMillis = 0; const long interval = 500; // 每个颜色的亮灯时长 const long offInterval = 10; // 熄灭间隔时长 int currentColor = 0; // 0:蓝, 1:红, 2:绿, 3:熄灭间隔 void setup() { pinMode(redLed, OUTPUT); pinMode(blueLed, OUTPUT); pinMode(greenLed, OUTPUT); pinMode(button1, INPUT); pinMode(button2, INPUT); attachInterrupt(digitalPinToInterrupt(button1), restartCycle, CHANGE); attachInterrupt(digitalPinToInterrupt(button2), stopCycleImmediately, CHANGE); // 初始关灯 turnOffAllLeds(); } void loop() { // 先检查是否需要停止,优先级最高 if (stopCycle) { turnOffAllLeds(); return; } unsigned long currentMillis = millis(); // 根据当前状态处理定时逻辑 switch(currentColor) { case 0: // 亮蓝色 if (currentMillis - previousMillis >= interval) { digitalWrite(blueLed, LOW); previousMillis = currentMillis; currentColor = 3; // 切换到熄灭间隔 } break; case 1: // 亮红色 if (currentMillis - previousMillis >= interval) { digitalWrite(redLed, LOW); previousMillis = currentMillis; currentColor = 3; } break; case 2: // 亮绿色 if (currentMillis - previousMillis >= interval) { digitalWrite(greenLed, LOW); previousMillis = currentMillis; currentColor = 3; } break; case 3: // 熄灭间隔 if (currentMillis - previousMillis >= offInterval) { previousMillis = currentMillis; // 切换到下一个颜色,循环回到蓝色 currentColor = (currentColor + 1) % 3; // 点亮对应颜色 switch(currentColor) { case 0: digitalWrite(blueLed, HIGH); break; case 1: digitalWrite(redLed, HIGH); break; case 2: digitalWrite(greenLed, HIGH); break; } } break; } } // 重启循环的中断函数 void restartCycle() { stopCycle = false; // 重置状态,从蓝色开始 currentColor = 0; previousMillis = millis(); turnOffAllLeds(); digitalWrite(blueLed, HIGH); } // 立即停止的中断函数 void stopCycleImmediately() { stopCycle = true; turnOffAllLeds(); } // 辅助函数:关闭所有LED void turnOffAllLeds() { digitalWrite(redLed, LOW); digitalWrite(blueLed, LOW); digitalWrite(greenLed, LOW); }
关键修改点说明
volatile修饰符:stopCycle是被中断函数修改的变量,必须加volatile,防止编译器优化导致主程序读取到旧值。- 非阻塞定时:用
millis()记录时间,替代delay(),让程序在每个loop周期都能检查stopCycle状态,一旦触发立即停止。 - 状态机设计:用
currentColor变量跟踪当前的灯效状态,每个状态只处理自己的定时逻辑,逻辑清晰且响应及时。 - 中断函数优化:在重启循环时直接重置状态,确保重新开始时从蓝色亮灯起步,避免状态混乱。
这样修改后,按下Button2时,中断会立即设置stopCycle = true,下一次loop循环就会执行关灯操作,完全不会等到当前颜色的延时结束,实现真正的“立即停止”。
内容的提问来源于stack exchange,提问作者Anthony Pastran
相关产品推荐
相关产品推荐

