我的 Arduino 代码有问题。我正在构建一个小型交通灯系统,我的基础项目需要它。
现在我有一个问题,我无法让程序在单击按钮两次时停止,并在再次单击按钮时在同一个地方继续运行。
#define one_Red 3
#define one_Yellow 4
#define one_Green 5
#define two_Red 6
#define two_Yellow 7
#define two_Green 8
#define redLed 10
#define greenLed 9
#define button 2
int programRunning = false;
int brightness = 0;
int fadeAmount = 5;
unsigned long previousMillis = 0;
const long interval = 30;
unsigned long taskStartTime = 0;
const unsigned long firstTaskDuration[] = {1000, 2000, 3000, 2000, 2000};
const unsigned long resetTaskDuration[] = {1000, 2000, 3000, 2000, 2000};
int currentStep = 0;
unsigned long lastButtonPress = 0;
int buttonPressCount = 0;
void setup()
{
pinMode(one_Red, OUTPUT);
pinMode(one_Yellow, OUTPUT);
pinMode(one_Green, OUTPUT);
pinMode(two_Red, OUTPUT);
pinMode(two_Yellow, OUTPUT);
pinMode(two_Green, OUTPUT);
pinMode(redLed, OUTPUT);
pinMode(button, INPUT_PULLUP);
digitalWrite(one_Red, HIGH);
digitalWrite(one_Yellow, HIGH);
digitalWrite(one_Green, LOW);
digitalWrite(two_Red, LOW);
digitalWrite(two_Yellow, HIGH);
digitalWrite(two_Green, HIGH);
digitalWrite(redLed, HIGH);
}
void loop()
{
pulseRedLed();
handleButtonPress();
if (programRunning)
{
runResetTask();
}
else
{
runFirstTask();
}
}
void handleButtonPress()
{
if (digitalRead(button) == LOW)
{
unsigned long currentMillis = millis();
if (currentMillis - lastButtonPress > 800)
{
lastButtonPress = currentMillis;
buttonPressCount++;
if (buttonPressCount == 2)
{
programRunning = !programRunning;
buttonPressCount = 0;
}
}
}
else
{
buttonPressCount = 0;
}
}
void runFirstTask()
{
if (digitalRead(button) == LOW && currentStep == 0)
{
taskStartTime = millis();
currentStep = 1;
}
if (currentStep > 0)
{
unsigned long currentMillis = millis();
if (currentMillis - taskStartTime >= firstTaskDuration[currentStep - 1])
{
taskStartTime = currentMillis;
switch (currentStep)
{
case 1:
digitalWrite(one_Green, HIGH);
digitalWrite(one_Yellow, LOW);
break;
case 2:
digitalWrite(one_Yellow, HIGH);
digitalWrite(one_Red, LOW);
break;
case 3:
digitalWrite(two_Red, HIGH);
digitalWrite(two_Yellow, LOW);
break;
case 4:
digitalWrite(two_Yellow, HIGH);
digitalWrite(two_Green, LOW);
programRunning = true;
currentStep = 0;
return;
}
currentStep++;
}
}
}
void runResetTask()
{
if (digitalRead(button) == LOW && currentStep == 0)
{
taskStartTime = millis();
currentStep = 1;
}
if (currentStep > 0)
{
unsigned long currentMillis = millis();
if (currentMillis - taskStartTime >= resetTaskDuration[currentStep - 1])
{
taskStartTime = currentMillis;
switch (currentStep)
{
case 1:
digitalWrite(two_Green, HIGH);
digitalWrite(two_Yellow, LOW);
break;
case 2:
digitalWrite(two_Yellow, HIGH);
digitalWrite(two_Red, LOW);
break;
case 3:
digitalWrite(one_Red, HIGH);
digitalWrite(one_Yellow, LOW);
break;
case 4:
digitalWrite(one_Yellow, HIGH);
digitalWrite(one_Green, LOW);
programRunning = false;
currentStep = 0;
return;
}
currentStep++;
}
}
}
void pulseRedLed()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
analogWrite(redLed, brightness);
brightness += fadeAmount;
if (brightness <= 0 || brightness >= 255)
{
fadeAmount = -fadeAmount;
}
}
}
我尝试修改“handleButtonPress”方法,目前没有成功。
我通常期望按钮事件触发中断,以便执行 ISR(中断服务例程)。然后,ISR 将检测按钮按下和按钮松开等事件。它可能包括一些基于时间的过滤来处理接触反弹。
但是,您的代码似乎轮询按钮。这似乎是——至少是问题的一部分。
让我们从
handleButtonPress
开始,暂时忘记其他功能。你的想法似乎是你想看两次digitalRead(button) == LOW
。并且您可以使用 buttonPressCount
来确定何时发生。
好的,点击按钮两次看起来像:
HHHHHHHHLHHHHLHHHHHHHH (L means LOW, H means HIGH)
^ ^
1st 2nd
click
当您看到第一个
LOW
时,您会增加 buttonPressCount
,即它将变为 1。到目前为止一切都很好。
然后您会看到一个
H
(HIGH
),因此您的代码采用 else
路径并执行以下操作:
buttonPressCount = 0;
Ups...您刚刚清除了第一次点击!所以你无法检测到按钮被点击两次!
只有在连续两次执行都读取低值时,您当前的函数才能执行此操作。
但是你也有 800 毫秒的限制...因为我假设该函数会在 800 毫秒内运行很多很多次,这意味着很多很多连续执行必须读取低值以避免进入
else
路径并清除计数器。
因此,要触发“单击两次”的代码,您需要长时间按住按钮,即超过 2x800ms。
所以需要重新设计功能。
我建议您在没有其他功能的情况下开始测试它,以便您有一个更简单的设置。例如:
void loop()
{
/////////////// pulseRedLed();
handleButtonPress();
if (programRunning)
{
///////////// runResetTask();
turn_on_green_and_turn_off_red();
}
else
{
///////////// runFirstTask();
turn_off_green_and_turn_on_red();
}
}
一旦“单击两次”检测起作用,单击两次时,您应该会看到 LED 在绿色和红色之间切换。