0

所以,我正在制作一个项目,其中我将使用 Arduino Uno。我想要做的是,只要开关打开,Arduino 就会让 LED 闪烁。但是有一个转折点。LED 将在开关状态变为高 10 秒后开始闪烁。但发生的情况是 LED 关闭 10 秒,然后打开 0.5 秒,然后再次关闭 10 秒。我想要它做的是,在保持关闭状态 10 秒后,它会一直闪烁。

这是代码

const int upperSwitch=2;
int buttonState;
const int ledPin=13;
unsigned long startMillis;  
unsigned long currentMillis;
const unsigned long period = 10000; 

void setup()
{
  pinMode(upperSwitch,INPUT);
  pinMode(ledPin,OUTPUT);
  startMillis=millis();
}

void loop()
{
  buttonState=digitalRead(upperSwitch);
  if(buttonState==HIGH)
  {
    delay(10000);
    currentMillis = millis();
    if (currentMillis - startMillis >= period)  
    {
      digitalWrite(ledPin,HIGH);
      delay(500);
      digitalWrite(ledPin,LOW);
      delay(500);
    }
  }
}

我哪里错了??在此处输入图像描述

我哪里错了?

4

1 回答 1

2

您的逻辑有缺陷,并且代码显示出许多设计缺陷。如果您按下按钮并释放它,它将进入该if(buttonState==HIGH)部分一次,因此闪烁一次。如果您按住按钮(或使用拨动开关),它将重新进入该if(buttonState==HIGH)部分,但在闪烁之前重复延迟。

您的代码缺少“状态”——一种记住您在上loop()一次迭代中所做的事情以告知下一次要做什么的方法。

设计缺陷包括:

  • 不必要地使用全局变量——这是 Arduino 代码中常见的坏习惯,Arduino 网站上的许多示例都鼓励这种习惯。你只需要那些在setup()和之间共享的变量的全局变量loop()——即使那样,这也不是绝对必要的,但我会放手——Arduino 代码很少变得复杂到足以成为一个问题。通常允许变量在必要的最窄范围内。

  • delay()中的使用loop()。这会使您的代码无响应并且浪费 CPU 资源——什么都不做。在这种情况下,一旦您开始延迟,在延迟完成之前就无法取消它或进行其他工作。您对 的想法是正确的if (currentMillis - startMillis >= period),但是通过延迟它在程序开始时进行初始化startMillis而不是在按下按钮时进行初始化,从而使它变得毫无意义。耽误了以后,currentMillis - startMillis >= period肯定会true这样试探无济于事。

以下代码实现了按钮的按下/按下切换语义,并具有必要的去抖动功能。可以随时打开/关闭按钮状态(不会延迟读取按钮)。

当打开时,延迟从给事件加时间戳开始,测试时间从时间戳开始。当延迟到期时,它开始闪烁 - 为每个 LED 状态切换添加时间戳以影响闪烁时间。

关闭时,不会执行任何延迟/闪烁代码,因此您可以随时取消延迟和闪烁。LED 在此状态下被强制关闭。这似乎是您想要的语义。

您可以在此处运行此模拟。我已包含调试输出 - 单击“代码”按钮并展开“串行监视器”以查看调试输出,然后单击“开始模拟”,然后单击模拟的轻触开关。仿真时序不准确,比标称的 YMMV 长约 50%。当按钮状态被切换并且 LED 闪烁时输出调试。我添加的电压表用于验证按钮是否正确接线。

const int UPPER_SWITCH = 2 ;
const int LED_PIN = 13 ;

void setup()
{
    pinMode( UPPER_SWITCH, INPUT ) ;
    pinMode( LED_PIN, OUTPUT ) ;
}

void loop()
{
    // Get initial button state
    static int button_toggle_state = digitalRead( UPPER_SWITCH ) ;
    
    // Indicator timing 
    static unsigned long delay_start_timestamp = 0 ;
    
    // Get current time
    unsigned long current_millis = millis();

    // Toggle button state on press (press-on/press-off) with debounce
    static const unsigned long DEBOUNCE_MILLIS = 20 ;
    static unsigned long debounce_timestamp = 0 ;
    static int previous_button_state = digitalRead( UPPER_SWITCH ) ;
    int current_button_state = digitalRead( UPPER_SWITCH ) ;
    if( current_millis - debounce_timestamp > DEBOUNCE_MILLIS &&
        current_button_state == HIGH && previous_button_state == LOW )
    {
        debounce_timestamp = current_millis ;
        
        if( button_toggle_state == LOW )
        {
            button_toggle_state = HIGH ;
            delay_start_timestamp = current_millis ;
        }
        else
        {
            button_toggle_state = LOW ;
        }
    }
    previous_button_state = current_button_state ;
  
    // If button toggle state has remained HIGH for DELAY_PERIOD...
    static const unsigned long DELAY_PERIOD = 10000 ;
    if( button_toggle_state == HIGH && 
        current_millis - delay_start_timestamp > DELAY_PERIOD)
    {
      
        // ... start flashing
        static const int FLASH_PERIOD = 500 ;
        static int led_state = LOW ;
        static unsigned long flash_toggle_timestamp = 0 ;
        if( current_millis - flash_toggle_timestamp > FLASH_PERIOD )
        {
            flash_toggle_timestamp = current_millis ;
            led_state = led_state == HIGH ? LOW : HIGH ;
        }
        digitalWrite( LED_PIN, led_state ) ;
    }
    else
    {
        // LED off
        digitalWrite( LED_PIN, LOW ) ;
    }
}
于 2021-04-16T19:33:26.193 回答