为什么中断是停止程序而不是跳回?

Why interrupt is stopping program instead of jumping back?

我在 arduino 上工作,我在 loop() 中创建了两种模式,while 循环中的模式 1 和 while 循环中的模式 second 它们有条件要满足,我使用中断例程的按钮在它们之间切换当前执行,更改标志以强制程序更改为第二种模式并且出于某种原因而不是打破当前的 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 循环。我想错了吗?还是我错过了什么?

您在 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)

然后您将希望在下降沿触发中断。

希望对您有所帮助。

如果您真的想将 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;

可能适合您的目的。