【问题标题】:Why interrupt is stopping program instead of jumping back?为什么中断是停止程序而不是跳回来?
【发布时间】:2016-11-06 14:38:04
【问题描述】:

我正在使用 arduino,我在 loop() 中创建了两种模式,在 while 循环中创建了 mode1,在 while 循环中创建了第二个模式,它们有条件要满足,我使用中断当前执行的例程的按钮在它们之间切换,更改标志以强制程序更改为第二种模式,并且由于某种原因而不是打破当前的 while 循环(因为不再满足条件)更改为另一个它只是不响应

或从自动更改->停止响应

#define modeSwitch 2
boolean manual;
boolean automatic;
String sOld;
boolean flagPrint = false;
volatile int modeSwitchValue;
String receivedData = "";
String invitation = "Welcome to Morse Code Encoder!\nPlease choose a mode: Write 'automatic' for an automatic mode or 'manual' or manual code.\n";



void setup() {
  pinMode(modeSwitch, INPUT);
  attachInterrupt(0, changeMode, RISING);
  manual = false;
  automatic = false;
  volatile int modeSwitchValue = 5;
  Serial.begin(9600);
  Serial.println(invitation);
}

void loop() {
  if (Serial.available() > 0) {
    receivedData = Serial.readStringUntil('\n');
    if (receivedData == "manual" ) {
      manual = true;
      automatic = false;
      modeSwitchValue = 0;
    }
    if ( receivedData == "automatic") {
      automatic = true;
      manual = false;
      modeSwitchValue = 1;
    }

    while ((manual == true) && (modeSwitchValue == 0) ) {
      String s = "Manual mode:";
      while (checkPrint(s) == true) {
        Serial.println(s);
      }

      automatic = false;
    }

    while ((automatic == true) && (modeSwitchValue == 1)) {
      String s = "Automatic mode:";
      while (checkPrint(s) == true) {
        Serial.println(s);
      }
      manual = false;
    }

  }

}

void changeMode() {

  if (  modeSwitchValue == 0) {
    modeSwitchValue = 1;
    automatic = true;
    manual = false;

  }
  if ( modeSwitchValue == 1) {
    modeSwitchValue = 0;
    manual = true;
    automatic = false;

  }
}

我删除了 checkPrint() 函数,因为它只确保消息被打印一次,所以我认为它没有必要在这里显示

我认为在执行自动代码时,我按下按钮并中断,更改模式变量然后回到程序中发生中断的同一位置。然后软件注意到自动模式的while循环条件不再满足,因此它跳到loop()并找到手动模式的while循环,因为条件满足。我想错了吗?还是我错过了什么?

【问题讨论】:

  • 您希望buttonState == LOW;buttonState == HIGH; 做什么?
  • 记住我们当前处于哪种模式以及接下来将更改为哪种模式

标签: c loops arduino interrupt-handling


【解决方案1】:

如果您确实想将 ISR 附加到按钮信号的上升沿,则应忽略多个触发器。最少 2 毫秒,但为什么不忽略不切实际的一切(例如 100 毫秒)

当您只是切换两种状态时,我建议使用布尔变量 istate

volatile bool istate; // the state maintained in the ISR changeMode

void changeMode() {
  static unsigned long lastime;
  if (millis() - lastime > 100) {
     lastime = millis();
     istate = ! istate;
  } 
}

如有必要,可以从主代码中的该易失 ISR 变量构建所有其他冗余内容(自动、手动)。 在我的理解中,buttonState 这个名字是错误的。而且这个变量是不必要的。


你知道数据类型枚举吗?

enum {MANUAL, AUTO} mode;
 if (istate) mode = AUTO;
 else        mode = MANUAL;

可能对你的目的很好。

【讨论】:

  • 我不会使用 'auto',因为它是 c++ 中的关键字。
  • @tddguru:同意。更改了上面的示例。
【解决方案2】:

您在 changeMode() 函数中混淆了赋值“=”和比较“==”。这是该函数的更正版本。

void changeMode() {
  if ( buttonState == HIGH) {
    modeSwitchValue = 1;
    automatic = true;
    manual = false;
    buttonState = LOW;
  }

  if (buttonState == LOW) {
    modeSwitchValue = 0;
    manual = true;
    automatic = false;
    buttonState = HIGH;
  } 
}

您还应该意识到机械按钮可以有触点弹跳。由于您使用中断来检测按钮状态的变化,因此您可能会出现不稳定的行为。通常,最好轮询按钮状态并应用大约 20 毫秒的去弹跳时间延迟。

您还没有分享按钮的接线方式。由于您正在检测上升沿,我假设按钮已连接以在按下时将引脚拉高。如果您使用的是单刀单通按钮,则需要一个下拉电阻接地,否则中断引脚将浮动。

您可以通过在输入引脚和地之间连接一个简单的按钮来避免所需的上拉或下拉电阻。然后将您的初始化代码更改为

pinMode(pin, INPUT_PULLUP)

然后你会想要在下降沿触发中断。

我希望这会有所帮助。

【讨论】:

  • 哎呀,失败了-.-" 我不敢相信我之前没有注意到,谢谢,我也会检查去抖动问题
  • 我改变了那个按钮似乎根本没有响应被按下
  • 由于弹跳,中断和按键是一个非常糟糕的组合。
猜你喜欢
  • 2020-06-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-07
  • 2019-07-09
  • 1970-01-01
  • 2014-10-06
  • 2017-04-12
  • 2018-03-11
相关资源
最近更新 更多