Использование 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;
}
3 ответа
Вам нужен неблокируемый код в сочетании с конечным автоматом:
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;
}
}
Примечание: в зависимости от вашей цели вы можете захотеть добавить код для устранения дребезга кнопок, чтобы одно нажатие кнопки действительно воспринималось как одно нажатие, а не больше. Это актуально в большинстве случаев, когда у вас есть неблокирующий код. Устранение дребезга было описано много раз в Интернете, так что просто погуглите
Вам следует включить подробную компиляцию в 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). Обратите внимание, что это не эквивалентно
Аппаратный сброс по причине:
- это не приведет к запуску загрузчика
- Что еще более важно, он не сбрасывает регистры ввода-вывода периферийных устройств. в состояние сброса по умолчанию.
... .любым способом я могу прервать программу во время ее работы и переключиться на любую другую функцию программы. например, когда мы нажимаем кнопку сброса, происходит сброс, если мы нажимаем кнопку, происходит переход к любой другой функции.
Прерывание не поможет вам достичь вашего требования. Вы хотите «сбросить состояние» вашего работающего скетча. Но после прерывания MCU возвращается в код, где он был до прерывания, и продолжает работу.
Вам следует реализовать «сброс состояния» в вашем алгоритме. В цикле неблокирующего скетча вы можете проверить кнопку и, если она нажата, «сбросить состояние» скетча.
- Как прервать функцию цикла и перезапустить ее?
- Кнопка Отправить работает только при нажатии сразу после этого
- Внешнее прерывание кнопки (цифровой вывод 3) Arduino не работает
- Программное обеспечение, устраняющее дребезг кнопки при отпускании
- Сброс Arduino Uno в коде
- Как сбросить или отформатировать Arduino?
- Определение того, была ли нажата и отпущена кнопка
- Устранение дребезга кнопки с помощью прерывания