您的逻辑有缺陷,并且代码显示出许多设计缺陷。如果您按下按钮并释放它,它将进入该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 ) ;
}
}