【问题标题】:Interrupts causing strange timer behavior导致奇怪的计时器行为的中断
【发布时间】:2020-11-14 20:59:05
【问题描述】:
  1. 目标:
  • 我正在使用 Arduino Nano 在 Arduino 环境中编写一个非常简单的程序。 (旧的)。
  • 我试图让引脚 2 充当中断,然后调用蜂鸣器功能。为清楚起见,请查看代码。
  1. 问题:
  • 当我在“loop()”中使用“buzzer_make_sound”运行以下代码时,蜂鸣器按预期工作。
  • 当触发中断并调用回调函数时,它没有正确执行定时器和蜂鸣器,导致蜂鸣器根本不响,定时器做奇怪的事情。
  1. 代码
#include "includes.h"    // this includes arduino.h 

void callback_rc_receive();
void buzzer_make_sound();

void setup() {
  Serial.begin(115200);

  pinMode(RC_INPUT_CHANNEL1_PIN, INPUT);      // pin 5
  pinMode(RC_INPUT_CHANNEL2_PIN, INPUT);      // pin 6
  pinMode(RC_INPUT_CHANNEL3_PIN, INPUT);      // pin 7
  pinMode(RC_INPUT_CHANNEL4_PIN, INPUT);      // pin 8
  pinMode(RC_INCOMING_SIGNAL_TRIGGER_PIN, INPUT);      // pin 2
  pinMode(BUZZER1_PIN, OUTPUT);                        // pin 3

  pinMode(LED_BUILTIN,OUTPUT);

  attachInterrupt(digitalPinToInterrupt(RC_INCOMING_SIGNAL_TRIGGER_PIN), callback_rc_receive, RISING);

  ReceiverOne.channel1State = 0;            // typedef struct
  ReceiverOne.channel2State = 0;
  ReceiverOne.channel3State = 0;
  ReceiverOne.channel4State = 0;

}

void loop() {
  //buzzer_make_sound();                      // this sounds the buzzer
}


void buzzer_make_sound(){
  Serial.println("Buzzer entry");
  int startTime = millis();

  tone(BUZZER1_PIN, 2000);
  delay(1000);
  noTone(BUZZER1_PIN);
  delay(1000);

  Serial.println("Buzzer exit");
  Serial.println(millis() - startTime);
}

void callback_rc_receive(){
  
  if (digitalRead(RC_INPUT_CHANNEL1_PIN) == 1){
    Serial.println("1");

    buzzer_make_sound();

  }else if (digitalRead(RC_INPUT_CHANNEL2_PIN) == 1){
    Serial.println("2");
  }else if (digitalRead(RC_INPUT_CHANNEL3_PIN) == 1){
    Serial.println("3");
  }else if (digitalRead(RC_INPUT_CHANNEL4_PIN) == 1){
    Serial.println("4");
  }else{
    Serial.println("Error");
  }

}
  1. 终端打印:

在循环中运行“buzzer_make_sound()”时:

Buzzer entry
Buzzer exit
2001

触发中断时:

1
Buzzer entry
Buzzer exit
0
1
Buzzer entry
Buzzer exit
0
1
Buzzer entry
Buzzer exit
65536
1
Buzzer entry
Buzzer exit
65536

奇怪的是,当触发中断时,它立即完成了任务。没有 2 秒延迟。

有人知道发生了什么吗?中断会停止计时器吗?如果是这样,如何处理依赖于计时器的事情?

【问题讨论】:

    标签: timer arduino interrupt


    【解决方案1】:

    问题描述取自https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

    从我的大脑中提取的解决方案。

    millis()delay()micros() 都使用中断来完成它们的工作,因此在另一个中断例程内部时不能调用。在微处理器上,当处于中断状态时,通常不能进入另一个中断(其他中断将被“调度”,当您离开当前中断时,这些中断将按优先级顺序调用)。一些处理器具有中断抢占,其中较高优先级的中断可以中断较低优先级的中断,但纳米处理器(ATmega238)没有。请参阅此处的数据表https://www.microchip.com/wwwproducts/en/ATmega328。搜索“中断”或“优先级”。

    无论如何,Arduino 网站上的中断文档是这样的

    在附加函数内部,delay() 不起作用,millis() 返回的值不会增加。在函数中接收的串行数据可能会丢失。您应该将您在附加函数中修改的任何变量声明为 volatile。有关详细信息,请参阅下面有关 ISR 的部分。

    通常,ISR 应尽可能短且快。如果您的草图使用多个 ISR,一次只能运行一个,其他中断将在当前中断完成后执行,顺序取决于它们的优先级。 millis() 依赖于中断来计数,因此它永远不会在 ISR 内递增。由于 delay() 需要中断才能工作,因此如果在 ISR 内调用它将不起作用。 micros() 最初可以工作,但会在 1-2 毫秒后开始表现异常。 delayMicroseconds() 不使用任何计数器,所以它会正常工作。

    一种解决方案是使用delayMicroseconds(),但这违反了中断应尽可能短且快的建议。通常,您使用它们将数据放入队列或设置标志或填充缓冲区,然后在主循环中检查该队列或标志时让实际工作得到处理。您不应该让 ISR 在一段时间内什么都不做(比如只是拖延时间)。

    我会修改你的代码,让中断设置一个名为buzzer_scheduled 的全局布尔标志(确保它被指定为volatile,如上所述)。修改 buzzer_make_sound() 以取消设置此标志。修改您的 loop() 以检查此标志,如果已设置,请调用 buzzer_make_sound()

    【讨论】:

    • 我试图让事情变得简单,但这样做却忘记了中断的一些基本原理。谢谢你的上述,它回答了一切等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 1970-01-01
    • 1970-01-01
    • 2017-12-31
    • 2017-07-21
    • 1970-01-01
    相关资源
    最近更新 更多