【问题标题】:Problem with interruptions in Arduino UnoArduino Uno 的中断问题
【发布时间】:2019-05-25 19:23:08
【问题描述】:

我在 Arduino UNO 中处理中断问题。在这个项目中,我想当门打开时 LED 闪烁 10 次,当门再次关闭时,停止闪烁 LED 并退出该功能。但在此代码中,LED 仅打开和关闭一次,并且不再闪烁。 我的另一个问题是,当门打开或关闭时,有时在系列监视器中会出现多次打开或关闭的单词。

const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin

volatile int SensorState = LOW; // 0 close - 1 open wwitch

void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}

void DoAction()
{
    SensorState = digitalRead(DOOR_SENSOR);
    if (SensorState == HIGH) {
    Serial.println("Opened");
    blinkLED(10, 500);
}
    else {
    Serial.println("Closed");
        }
}

void blinkLED(int repeats, int time)
{
    for (int i = 0; i < repeats; i++) {
        if (SensorState == HIGH) {
        digitalWrite(LED_Red, HIGH);
        delay(time);
        digitalWrite(LED_Red, LOW);
        delay(time);
    }
    else
        return;
}
}

void loop()
{
}

【问题讨论】:

    标签: arduino interrupt


    【解决方案1】:

    您不能简单地将delay() 放在中断函数上。您只需要在门打开时设置一个标志,并基于主循环内的 blinkLED 开始。

    我还建议您使用 millis() 函数在 blinkLED 函数中进行解锁延迟(例如,当您想在门关闭时停止闪烁时)。

    const byte LED_Red = 13;
    const byte DOOR_SENSOR = 2; // magnetic door sensor pin
    
    // flag to check door is opened
    volatile bool isOpened = false;
    
    //flag to check already blinked
    volatile bool isBlinked = false;
    
    void setup()
    {
        Serial.begin(9600);
        pinMode(LED_Red, OUTPUT);
        pinMode(DOOR_SENSOR, INPUT_PULLUP);
        attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
    }
    
    void DoAction()
    {
        if (digitalRead(DOOR_SENSOR) == HIGH)
        {
            //Serial.println("Opened");
            isOpened = true;
        }
        else
        {
            isOpened = false;
            isBlinked = false;
            //Serial.println("Closed");
        }
    }
    
    void blinkLED(int repeats, int time)
    {
        byte LEDState = LOW;
        unsigned long delay_start = millis();
        for (int i = 0; i < 2 * repeats; i++)
        {
            //Toggle LED state
            if (LEDState == HIGH)
                LEDState = LOW;
            else
                LEDState = HIGH;
            // set value
            digitalWrite(LED_Red, LEDState);
            // some unblocking delay
            while (millis() - delay_start < time)
            {
                // return if door is closed
                if (!isOpened)
                {
                    // turn off LED
                    digitalWrite(LED_Red, LOW);
                    return;
                }
            }
            delay_start = millis();
        }
        isBlinked = true;
    }
    
    void loop()
    {
        // Check isBlinked beacue don't want to blink again until door is closed
        if (isOpened && !isBlinked)
        {
            blinkLED(10, 500);
        }
    }
    

    【讨论】:

    • 我会进一步建议不要将打印语句放入您的 ISR。来自 Arduino 文档:“通常,ISR 应该尽可能短且快”。就时间而言,打印语句通常非常“昂贵”。你可以在这里阅读更多:Arduino Docs - AttachInterrupt
    • @GMc 谢谢我编辑了代码并注释掉了那些行。
    • 感谢您提供有用的答案 代码运行良好,我通过添加新中断来扩展程序。现在我想知道是否可以摆脱循环功能。我认为我们不断检查循环中的变量以判断值是否发生变化并不是一个好主意。把程序写成只有在程序有中断时才检查这些变量的值不是更好吗?这个问题有解决办法吗?
    • @hamidmousavi 是的,您可以在中断例程中调用blinkLED,但问题是millis() 不会进行,因此您将无法使用延迟。您可以在here 中找到更多相关信息。此外,检查loop 函数中的标志也不错。
    猜你喜欢
    • 2017-06-20
    • 1970-01-01
    • 2022-12-14
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多