【问题标题】:How to constantly listen for button input in Arduino?如何在 Arduino 中不断监听按钮输入?
【发布时间】:2020-01-20 14:22:21
【问题描述】:

我正在尝试创建一个交通信号灯十字路口的有效物理模拟。我想在整个程序中连续收听按钮读数(行人按钮将行人灯变为绿色),并希望运行一个不同的功能,如果在程序期间按下按钮,将处理行人灯。 我已经尝试过使用 while 循环和 if 条件,但它不起作用,因为它会在特定时间点读取按钮输入,当我希望它在整个程序中不断读取读数并在条件下中断循环时永远是不真实的(当我希望它检查整个循环的条件时,while 和 do-while 循环只检查循环结束时的条件)。如果可能的话,我还需要知道按下了哪个按钮。然后根据按下的按钮,我想运行一个名为 pedes() 或 pedes2() 的函数。 如果您需要任何说明,请随时询问。

我在下面发布了我想要不断运行的原始代码,直到按下按钮。 谢谢!

// If at any point in time during this code, a button is pushed, I want to run a function called
    pedes() or pedes2() depending on which button is pressed.

// First set of Trafiic Lights
int redT = 13 ;
int yellowT = 12;
int greenT = 11;

// First set of Pedestrian Lights
int redP = 10;
int greenP = 9;

// Second set of Traffic Lights
int redT2 = 8;
int yellowT2 = 7;
int greenT2 = 6;

// Second set of Pedestrian Lights
int redP2 = 5;
int greenP2 = 4;

// Pedestrian Buttons
int buttonT = 3;
int buttonT2 = 2;
int buttonT3 = 1;
int buttonT4 = 0;

int buttonStateT = 0;
int buttonStateT2 = 0;
int buttonStateT3 = 0;
int buttonStateT4 = 0;

// Booleans which will handle which button was pressed

void setup() {
  // First set of Trafiic Lights
  pinMode(redT, OUTPUT);
  pinMode(yellowT, OUTPUT);
  pinMode(greenT, OUTPUT);

  // First set of Pedestrian Lights
  pinMode(redP, OUTPUT);
  pinMode(greenP, OUTPUT);

  // Second set of Traffic Lights
  pinMode(redT2, OUTPUT);
  pinMode(yellowT2, OUTPUT);
  pinMode(greenT2, OUTPUT);

  // Second set of Pedestrian Lights
  pinMode(redP2, OUTPUT);
  pinMode(greenP2, OUTPUT);

  // Pedestrian Buttons
  pinMode(buttonT, INPUT);
  pinMode(buttonT2, INPUT);
  pinMode(buttonT3, INPUT);
  pinMode(buttonP4, INPUT);
}

void loop() {
    // Resetting all the traffic lights
    digitalWrite(redP, HIGH); // Turns on red pedestrian LED from 1st bunch
    digitalWrite(redP2, HIGH); // Turns on red pedestrian LED from 2nd bunch

    digitalWrite(yellowT, LOW); // Turns off yellow traffic LED from 1st bunch
    digitalWrite(yellowT2, LOW); // Turns off yellow traffic LED from 1st bunch

    digitalWrite(redT, HIGH); // Turns on red traffic LED from 1st bunch
    digitalWrite(redT2, HIGH); // Turns on red traffic LED from 2nd bunch

    delay(2000);

    digitalWrite(redT, LOW); // Turns off red traffic LED from 1st bunch
    digitalWrite(redT2, HIGH); // Turns on red traffic LED from 2nd bunch

    digitalWrite(greenT, HIGH); // Turns on green traffic LED from 1st bunch
    digitalWrite(greenT2, LOW); // Turns off green traffic LED from 2nd bunch

    delay(10000); // Pauses program for 8 seconds

    digitalWrite(greenT, LOW); // Turns off green traffic LED from 1st bunch
    digitalWrite(yellowT, HIGH); // Turns on yellow traffic LED from 1st bunch

    delay(3000); // Pauses program for 3 seconds

    digitalWrite(yellowT, LOW); // Turns off yellow traffic LED from 1st bunch
    digitalWrite(redT, HIGH); // Turns on red traffic LED from 1st bunch

    delay(2000); // Pauses program for 3 seconds

    digitalWrite(redT2, LOW); // Turns off red traffic LED from 2nd bunch
    digitalWrite(greenT2, HIGH); // Turns on green traffic LED from 2nd bunch

    delay(6000); // Pauses program for 8 seconds

    digitalWrite(greenT2, LOW); // Turns off green traffic LED from 2nd bunch
    digitalWrite(yellowT2, HIGH); // Turns on yellow traffic LED from 2nd bunch

    delay(3000); // Pauses program for 3 seconds

    digitalWrite(yellowT2, LOW); // Turns off yellow traffic LED from 2nd bunch
    digitalWrite(redT2, HIGH); // Turns on red traffic LED from 2nd bunch

    delay(2000); // Pauses program for 3 seconds
  }

【问题讨论】:

  • 请发布您的代码,或minimal, reproducible example
  • 我添加了代码。
  • 请修正您的评论。你说10000ms暂停程序8秒,2000ms暂停3秒。这是不正确的。
  • 是的,我意识到这一点。目前,我一直在搞乱灯光的时间。请忽略。
  • 解决方案可能涉及在主循环中使用non-blocking delay

标签: arduino arduino-uno arduino-ide arduino-c++


【解决方案1】:

如果您延迟 10 秒,那么您在此期间无法对某事做出反应。

您可以使用millis() 来实现非阻塞延迟。 https://www.arduino.cc/en/tutorial/BlinkWithoutDelay

与其闲着和无法响应,不如花时间检查和响应按钮状态和/或时间条件。

【讨论】:

    【解决方案2】:

    避免使用延迟。延迟会暂停一切,直到时间到,这会降低一切响应速度。延迟在学习如何编码时很有用,但如果您需要对外部传感器或按钮做出反应,它们可能会妨碍可用性。

    一个更好的习惯是使用计时器而不是延迟。这可以让您的代码不断循环而不会暂停,并且您可以添加代码以更频繁地检查用户输入。

    这是一个你不应该做的例子:

    void loop() {
      digitalWrite(MY_LED,HIGH);
      delay(1000);
      digitalWrite(MY_LED,LOW);
      delay(1000);
    
      //This code only gets reached every 2 seconds
      //This means you may need to hold the button for up to
      //2 seconds before it will print a message
      if (digitalRead(MY_BUTTON) == LOW) {
        Serial.println("You pressed the button");
      }
    }
    

    您可以使用 millis() 返回自 arduino 开始运行以来的毫秒数。下面是一个计时器的基本示例:

    bool ledState = false;
    unsigned long toggledTime = 0;  //The last time we toggled the led
    
    void loop() {
    
      //Calculate how much time has passed since the last time
      //we turned the LED on or off
      unsigned long timeElapsedSinceLastToggle = millis() - toggledTime;
    
      //If 1000ms (1s) has passed, we'll toggle the LED
      if (timeElapsedSinceLastToggle > 1000) {
        ledState = !ledState;           //Invert the state
        digitalWrite(MY_LED,ledState);  //Perform the action
        toggledTime = millis();         //Reset our timer to the current time
      }
    
      //This code now checks very frequently since the code above
      //never uses delay()
      if (digitalRead(MY_BUTTON) == LOW) {
        Serial.println("You pressed the button");
      }
    }
    

    我建议您为要切换的每个 LED 使用不同的计时器。这将使您的代码更具响应性,并且您的按钮将(几乎)立即响应。

    关于计时器,您需要注意一件事。 millis() 是自启动以来的毫秒数,但是当您的代码运行很长时间时会发生什么?大约 50 天后,millis() 重置(从 0 开始)。对于很多人来说,这无关紧要,但如果您的代码将无限期地长时间运行,则值得牢记。

    【讨论】:

      【解决方案3】:

      您可以在按钮引脚上使用interrupt 并设置一个标志或从中断例程中调用一个函数,而不是不断地轮询。

      还要确保在硬件或软件中对按钮进行去抖动处理。


      由于您似乎正在学习,因此您可以在练习中添加一些额外的改进:

      • 要切换灯,您可以使用定时器中断而不是延迟(您甚至可以将 mcu 置于睡眠模式)。

      • 另一个改进是创建一个包含所有逻辑的TrafficLight 类。 Here is an interesting tutorial。通过这种方式,您可以轻松创建多个对象:TrafficLight tl1(..), tl2(..); 甚至是交通灯数组(例如具有相同的时间)。

      • 然后您甚至可以创建一个类 Intersection,其中包含所有交通信号灯和该路口的逻辑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-19
        • 2022-01-09
        • 2013-12-24
        相关资源
        最近更新 更多