Изменить глобальное перечисление из функции прерывания

У меня есть глобальное перечисление.

enum Modes { ModeOne, ModeTwo };
enum Modes currentMode = ModeOne;

У меня также есть функция прерывания, которая по заданному событию должна изменить значение перечисления.

void my_interrupt_handler()
{
    // СОБЫТИЕ ЗАПУЩЕНО ЗДЕСЬ. ИЗМЕНИТЬ ПЕРЕЧИСЛЕНИЕ
    switch (currentMode)
    {
      case ModeOne:
         currentMode = ModeTwo;
      case ModeTwo:
         currentMode = ModeOne;
      default:
         break;
    }

У меня также есть строки Serial.print() в функции прерывания, чтобы увидеть состояние переменной перечисления, однако, даже когда событие срабатывает, состояние перечисления не меняется .

EDIT: Это минимальный пример кода:

const uint8_t button_switch = 2; // вывод внешнего прерывания
const unsigned long debounceDelay = 150 ; // время устранения дребезга

enum Modes { ModeOne = 0, ModeTwo };

enum Modes currentMode = ModeOne;

void button_interrupt_handler()
{
  static uint32_t last_entryAtMs = 0 ;
  if ( millis() - last_entryAtMs > debounceDelay )
  {
    //изменить режим
    switch (currentMode)
    {
      case ModeOne:
         currentMode = ModeTwo;
      case ModeTwo:
         currentMode = ModeOne;
      default:
         break;
    }
    //печатаем, чтобы убедиться, что все работает
    Serial.print("currentMode is: ");
    Serial.println(currentMode);
    last_entryAtMs = millis() ;
  }

}

void setup()
{
  Serial.begin(9600);
  pinMode( button_switch, INPUT_PULLUP) ;
  attachInterrupt(digitalPinToInterrupt(button_switch), button_interrupt_handler, FALLING);
}

void loop()
{
  delay(1000);
  Serial.println(currentMode);
}

EDIT 2: Согласно предложению пользователя timemage, я увеличил уровень предупреждения компилятора. Вот предупреждения, которые я получаю:

C:\...\Temp\arduino_modified_sketch_967886\Blink.ino: In function 'void button_interrupt_handler()':
C:\...\Temp\arduino_modified_sketch_967886\Blink.ino:17:22: warning: this statement may fall through [-Wimplicit-fallthrough=]
          currentMode = ModeTwo;
          ~~~~~~~~~~~~^~~~~~~~~
C:\...\Temp\arduino_modified_sketch_967886\Blink.ino:18:7: note: here
       case ModeTwo:
       ^~~~

, 👍-1

Обсуждение

Каждая переменная, используемая внутри ISR, должна быть объявлена volatile. И последовательная связь работает только вне прерываний. Таким образом, использование соответствующей функции может заблокировать ваш код, если последовательный буфер заполнен. Пожалуйста, предоставьте полный минимальный рабочий пример, который показывает вашу проблему. Итак, полный код, который можно скомпилировать., @chrisl

Вы должны использовать volatile Modes currentMode = ModeOne. В противном случае компилятор может оптимизировать его, поскольку нет ничего, что могло бы изменить значение (и он не знает об ISR)., @KIIV

Я обновил вопрос минимальным рабочим примером., @user1584421

не печатать внутри ISR... вместо этого установите флаг... внутри loop(), если флаг установлен, снимите его и напечатайте, @jsotola

Я вообще не печатаю. Печать внутри ISR была, когда я пробовал материал. Я не получил вашего ответа... Я хочу, чтобы ISR изменил состояние перечисления... Не внутри loop()., @user1584421

Если вы войдете в File/Preferences и повысите уровень предупреждения (для всех), вы, скорее всего, увидите предупреждение о вашем операторе switch, который вполне может быть ответом на ваш вопрос, который, в свою очередь, может быть просто опечаткой в вашем часть. Однако то, что Крисл и KIIV сказали о «изменчивости», важно *независимо от того, проявляется ли она в настоящее время как наблюдаемая проблема., @timemage

Кроме того, в ссылке на Arduino есть это предупреждение о AttachInterrupt: внутри прикрепленной функции delay() не будет работать, и значение, возвращаемое millis(), не будет увеличиваться...., @Chalky

@timemage Спасибо за рекомендацию. Я сделал то, что вы описываете, и отредактировал вопрос с предупреждениями компилятора. не вижу опечатки...., @user1584421

Что касается предупреждения, вы понимаете, что оно означает? Если нет, вы можете поискать в Интернете фразу «C++ switch case fall through»., @Edgar Bonet

@EdgarBonet О боже. Я только что... Нет, если честно, я не понимал этого в то время. Я пропустил случай break. Большое спасибо как timemage, так и Эдгару Боне. Однако я не могу проверить код прямо сейчас, но, вероятно, это он. Результаты выложу позже в течении дня. Большое спасибо!, @user1584421


1 ответ


0

Вы должны быть очень осторожны при работе с контактами, устраняющими дребезг, потому что они не всегда ведут себя так, как вы ожидаете. В этом случае прерывание не приведет к желаемому результату, если только контакты не дребезжат дольше, чем время DebounceDelay. Если контакты закрываются до истечения времени DebounceDelay, то вы не получите другого прерывания, когда ваше тестовое условие DebounceDelay истинно. Другой способ взглянуть на эту проблему — запустить таймер при ПЕРВОМ подавлении дребезга, а затем, когда время ТАЙМЕРА истечет, посмотреть, остается ли вход все еще низким (вместо того, чтобы проверять, истекло ли время таймера при устранении дребезга ключа).

,

Я понимаю, о чем вы говорите, но здесь это не так. У меня есть код прерывания, который включает/выключает встроенный светодиод при нажатии кнопки. Это никогда не подводит. При каждом нажатии кнопки светодиод включается, а затем успешно выключается. Это перечисление, которое не меняется., @user1584421