【问题标题】:Arduino Project阿杜诺项目
【发布时间】:2021-07-11 12:03:08
【问题描述】:

所以,我正在制作一个项目,其中我将使用 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);
    }
  }
}

我哪里出错了??

我哪里错了?

【问题讨论】:

  • 请不要在真正的自行车上摆弄爱好者板,这在大多数国家都是非常危险和非法的。自行车上的电子设备将通过广泛的型式认证和 EMC 测试,而您的爱好者委员会则没有。
  • “我哪里出错了?”您似乎将电线连接到了触觉开关的错误引脚......而且您将拉电阻连接到了开关的错误一侧。
  • 仅当您希望按钮工作时。在插入任何东西之前,使用万用表上的“哔”声来验证您的电路。无论如何,从您的电线图片中无法判断哪些极属于同一根。
  • 我看到你使用的是 13 号引脚,它也是 Arduino 内部使用的,所以你必须小心使用。请参阅 [Arduino 数字引脚](“数字引脚 | Arduino”arduino.cc/en/Tutorial/Foundations/DigitalPins)。
  • 我不知道“两轮车”可能指的是什么,也不知道为什么它甚至与此代码或电路相关。由于它显然与您的问题无关,因此我将省略所有提及它的内容。最终你的最终应用程序是什么并不重要,它只是分散注意力。您还可以更清晰、更简单地描述 a) 它应该做什么,b) 它实际做什么 - 在问题中,而不是在 cmets 中。也就是说,去掉华夫饼,切入正题,准确无误。不要将问题与 5 分钟与 10 秒的废话混淆 - 只需描述此测试代码必须做什么。

标签: arduino embedded microcontroller arduino-uno atmega32


【解决方案1】:

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

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

设计缺陷包括:

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

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

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

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

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

您可以运行此here 的模拟。我已包含调试输出 - 单击“代码”按钮并展开“串行监视器”以查看调试输出,然后单击“开始模拟”,然后单击模拟的轻触开关。仿真时序不准确,比标称的 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 ) ;
    }
}

【讨论】:

  • 非常感谢,@Clifford。我通过这个答案学到了很多东西。此外,模拟运行得非常好。我现在明白你的意思了。 delaymillis() 不要一起去。再次非常感谢。
  • 另外,这正是我想要的。我是 Arduino 新手,不了解其编程的所有方面。我做过一些不需要这样的项目。这是我第一次做这样的事情。再次非常感谢。
猜你喜欢
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
  • 2020-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多