Использование attachInterrupt() для создания кнопки сброса для кода

Я использовал attachInterrupt() для сброса моей программы в начало. На самом деле он прерывается во время выполнения 3 состояний, как показано ниже внутри оператора if, но когда я нажимаю фактическую кнопку, он не выходит, а переходит к функции и продолжает в следующем состоянии. Это работает (означает выход/сброс) только после того, как все три состояния полностью выполнены.

if(buttoncount<2){
  originalstate();
  alertstate();
  evacuationstate();

Я хотел бы сделать кнопку, которая остановит программу во время ее выполнения и запустит ее снова.

Код:

// Объявление пинов

// Входные контакты
const int sensor1button_pin = 6;
const int sensor2button_pin = 3;
const int sensor3button_pin = 4;
const int sensor4button_pin = 5;
const int sensor5button_pin = 2;
const int sensor6button_pin = 15;
const int sensor7button_pin = 15;

// Выходные контакты
const int led1_pin = 8;
const int led2_pin = 9;
const int led3_pin = 10;
const int led4_pin = 11;
const int buzzerpin = 15;

// Первоначально зуммер в ложном режиме
boolean flag1;
boolean flag2;
int flag3 ;


// для светодиодов
int ledState1 = LOW;   // Оригинал
int ledState2 = LOW;   // Тревога
int ledState3 = LOW;   // Эвакуировать
int ledState4 = LOW;   // Изолировать

// Кнопки
int button1_state = LOW;
int button2_state = LOW;
int button3_state = LOW;
int button4_state = LOW;
int button6_state = LOW;
int button7_state = LOW;
int button5_state = LOW;

// Другие переменные
int buttoncount = 0;
int reset_switch=0;

void setup() {
  // ВХОДНЫЕ контакты
  pinMode(sensor1button_pin, INPUT);
  pinMode(sensor2button_pin, INPUT);
  pinMode(sensor3button_pin, INPUT);
  pinMode(sensor4button_pin, INPUT);

  pinMode(sensor5button_pin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(sensor5button_pin), clearreset, CHANGE); 

  pinMode(sensor6button_pin, INPUT);
  pinMode(sensor7button_pin, INPUT);

  // ВЫХОДНЫЕ контакты
  pinMode(buzzerpin, OUTPUT);
  pinMode(led1_pin, OUTPUT);
  pinMode(led2_pin, OUTPUT);
  pinMode(led3_pin, OUTPUT);
  pinMode(led4_pin, OUTPUT);

  Serial.begin(9600);
}

void loop() {
  button1_state = digitalRead (sensor1button_pin);
  button2_state = digitalRead (sensor2button_pin);
  button3_state = digitalRead (sensor3button_pin);
  button4_state = digitalRead (sensor4button_pin);
  button5_state = digitalRead (sensor5button_pin);
  button6_state = digitalRead (sensor6button_pin);
  button7_state = digitalRead (sensor7button_pin);

  Serial.println(digitalRead (sensor5button_pin));

  if( button1_state == HIGH || button2_state == HIGH || button3_state == HIGH || button4_state == HIGH) {
    delay(280);
    buttoncount = buttoncount + 1;
  }

  if (button1_state == HIGH || button2_state == HIGH || button3_state == HIGH || button4_state == HIGH) {
    if(buttoncount<2){
      originalstate();
      alertstate();
      evacuationstate();
    }
  } 
}

// Светодиодные осветительные приборы
void originalstate() {
  digitalWrite(led1_pin, HIGH);
  digitalWrite(led2_pin, LOW);
  digitalWrite(led3_pin, LOW);
  digitalWrite(led4_pin, LOW);
  delay(1500);
}

void alertstate() {
  digitalWrite(led1_pin, LOW);
  digitalWrite(led2_pin, HIGH);
  digitalWrite(led3_pin, LOW);
  digitalWrite(led4_pin, LOW);
  delay(1500);
}

void evacuationstate() {
  digitalWrite(led1_pin, LOW);
  digitalWrite(led2_pin, LOW);
  digitalWrite(led3_pin, HIGH);
  digitalWrite(led4_pin, LOW);
  delay(1500);
}

void isolatestate() {
  digitalWrite(led1_pin, LOW);
  digitalWrite(led2_pin, LOW);
  digitalWrite(led3_pin, LOW);
  digitalWrite(led4_pin, HIGH);
}

// Очистить или сбросить обратно в начало

void clearreset() { 
 button1_state = LOW;
 button2_state = LOW;
 button3_state = LOW;
 button4_state = LOW;
 button5_state = LOW;
 button6_state = LOW;
 button7_state = LOW;

 digitalWrite(led1_pin, LOW);
 digitalWrite(led2_pin, LOW);
 digitalWrite(led3_pin, LOW);

 buttoncount = 0;        
 exit;
}

, 👍1


3 ответа


1

Вам нужен неблокируемый код в сочетании с конечным автоматом: 1. Неблокирующий код: не следует использовать delay(), так как он просто занят ожиданием. Вместо этого используйте функцию millis() для измерения временного интервала между последним выполнением части кода и текущим временем. Если он достиг определенного уровня (например, 1500 мс), выполните код и сохраните текущее время в метке времени в качестве ссылки для следующего выполнения. Обратитесь к примеру BlinkWithoutDelay в Arduino IDE. В Интернете также есть много руководств по этому вопросу, поэтому я не буду объяснять это здесь далее. 2. Конечный автомат: Здесь ваша функция loop() содержит оператор switch с переменной состояния (в основном числовой) в качестве параметра. Каждый случай содержит только код для своего особого случая. Чтобы перейти из одного состояния в другое, вам просто нужно изменить переменную состояния на соответствующее значение. Вы также можете сделать это в ISR (если вы установите переменную состояния как volatile). Если вы используете неблокируемый код, как описано выше, функция loop() выполняется очень быстро, так что изменение переменной состояния внутри ISR вступает в силу практически немедленно (задержка не будет ощутима для человека). Что-то вроде этого:

volatile int state=0;

void isr_function(){
    state++;
    if(state>1) state=0;
}

void loop(){
    switch(state){
        case 0: // state 0
            do_something();
            break;
        case 1: // state 1
            do_another_thing();
            break;
    }
}

Примечание: в зависимости от вашей цели вы можете захотеть добавить код для устранения дребезга кнопок, чтобы одно нажатие кнопки действительно воспринималось как одно нажатие, а не больше. Это актуально в большинстве случаев, когда у вас есть неблокирующий код. Устранение дребезга было описано много раз в Интернете, так что просто погуглите

,

1

Вам следует включить подробную компиляцию в IDE. Тогда у вас будет вероятность увидеть это предупреждение компилятора:

warning: statement is a reference, not call, to function ‘exit’
  exit;
      ^
warning: statement has no effect

Именование функции без ее вызова — это способ получить указатель на функция. Это эквивалентно &exit. Но поскольку вы ничего не делаете с этим указатель, утверждение не имеет никакого эффекта, и это именно то, что Компилятор предупреждает вас о.

Предположительно, вы хотите вызвать функцию exit(), как в:

exit(0);

Изменить: Тем не менее, exit(), вероятно, не то, что вам нужно. Эта функция просто останавливает вашу программу, помещая ее в бесконечный цикл. Если вы хотите перезапустить его с нуля, вы можете сначала объявить

extern "C" void __init();

тогда вместо exit(0); вызовите __init();. Это отправит ваш программу в начало кода инициализации из среды выполнения C, который отвечает за сброс стека и инициализацию памяти (разделы .data и .bss). Обратите внимание, что это не эквивалентно Аппаратный сброс по причине:

  • это не приведет к запуску загрузчика
  • Что еще более важно, он не сбрасывает регистры ввода-вывода периферийных устройств. в состояние сброса по умолчанию.
,

0

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

Прерывание не поможет вам достичь вашего требования. Вы хотите «сбросить состояние» вашего работающего скетча. Но после прерывания MCU возвращается в код, где он был до прерывания, и продолжает работу.

Вам следует реализовать «сброс состояния» в вашем алгоритме. В цикле неблокирующего скетча вы можете проверить кнопку и, если она нажата, «сбросить состояние» скетча.

,