停止某个功能并在同一位置重新启动时出现问题

问题描述 投票:0回答:1

我的 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”方法,目前没有成功。

c++ c arduino
1个回答
0
投票

我通常期望按钮事件触发中断,以便执行 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 在绿色和红色之间切换。

© www.soinside.com 2019 - 2024. All rights reserved.