проблема выхода из цикла for в функции и возврата к FSM с помощью кнопки
У меня есть конечный автомат, который переходит в функцию patternOne. Однако, оказавшись в ней, я не могу выйти из этой функции и вернуться в конечный автомат. Когда я нажимаю кнопку, мой последовательный порт показывает, что она нажата, но всё равно остаётся в функции patternOne. Я не знаю, как выйти из неё и почему это происходит. Мой код ниже:
#include <SPI.h>
SPISettings settingsA(2000000, MSBFIRST, SPI_MODE1);
#include <SFE_MicroOLED.h> // Включить библиотеку SFE_MicroOLED
#include <Wire.h> // Включите Wire, если вы используете I2C
volatile unsigned long prevTime = 0;
int time_interval_for_chip = 5;
int blinking_interval = 500;
unsigned long current_time = 0;
#define PIN_RESET A6 // Подключите RST к контакту 9
#define DC_JUMPER 0
MicroOLED oled(PIN_RESET, DC_JUMPER);// Объявление I2C
const int buttonpin = A8;
volatile int buttonState = 0; // переменная для чтения состояния кнопки
volatile int buttonState2 = 0;
int buttonstate3 = 1;
const int buttonpin2 = A7;
enum State {flip, intro, option1, pattern1, intro_flip, option1_flipped, pattern1_flipped, pattern2, pattern3};
//enum — это тип данных, состоящий из определяемых пользователем переменных, например, слов pattern, intro, ext
State state = flip; //указываем начальному состоянию начать с вступления
unsigned int column_pattern1[] = {0b0000000100000100, 0b0000001000001000,0b0100000010000010};
//беззнаковое целое column_off_pattern1[]={0b0000000000000100, 0b00000000000001000,0b01000000000000010};
const int css1 = 10;
const int css2 = A0;
void setup() {
oled.begin(); // Инициализируем OLED
oled.clear(ALL); // Очищаем внутреннюю память дисплея
// oled.display(); // Отображение содержимого буфера (заставка)
// delay(1000); // Задержка 1000 мс
oled.clear(PAGE); // Очищаем буфер.
//
pinMode(css1, OUTPUT);
pinMode(css2, OUTPUT);
Serial.begin(9600);
SPI.begin();
SPI.beginTransaction(settingsA);
pinMode(buttonpin, INPUT_PULLDOWN);
pinMode(buttonpin2, INPUT_PULLDOWN);
// водяной знак генерирует это прерывание
attachInterrupt(buttonpin, button_pressed, FALLING); // прерывание 1 — данные готовы
//attachInterrupt(buttonpin2, button_pressed2, FALLING); // прерывание 1 — данные готовы
}
void loop() {
// мигание выходов 4 и 8 при использовании конечного автомата для перехода от вступления к шаблону
//отключение дисплея при выборе шаблона
switch (state) {
case flip:
oled.setFontType(1);
oled.setCursor(0, 0); // Устанавливаем текстовый курсор в верхний левый угол экрана.
//oled.setFontType(2);
// oled.setCursor(0, 0);
oled.print(" Flip Screen?");
oled.setFontType(0);
oled.setCursor(0, 30);
oled.print("yes");
oled.setCursor(40, 30);
oled.print("no");
oled.circle(10, 43, 3.5);
oled.circle(50, 43, 3.5);
oled.display();
buttonState = 0;
if (digitalRead(buttonpin2) == HIGH) {
oled.circleFill(50, 43, 3.5);
oled.display();
oled.clear(PAGE); // Очищаем буфер.
delay(500);
//buttonstate3=0;
state=intro;
}
if (digitalRead(buttonpin) != buttonState) {
oled.circleFill(10, 43, 3.5);
oled.display();
oled.clear(PAGE); // Очищаем буфер.
delay(500);
state=intro_flip;
}
break;
case intro:
oled.setFontType(1);
oled.setCursor(0, 0); // Устанавливаем текстовый курсор в верхний левый угол экрана.
//oled.setFontType(2);
// oled.setCursor(0, 0);
oled.print("choose pattern");
oled.circle(10, 40, 7);
oled.display();
buttonState = 0;
if (digitalRead(buttonpin) != buttonState) {
buttonState = 0; //сбросить состояние кнопки
oled.circleFill(10, 40, 7);
oled.display();
delay(500);
state = option1;
}
break;
case option1:
oled.clear(PAGE); // Очищаем буфер.
//задержка(300);
oled.setFontType(0);
oled.setCursor(0, 0); // Устанавливаем текстовый курсор в верхний левый угол экрана.
//oled.setFontType(2);
// oled.setCursor(0, 0);
oled.print("Pattern 1");
oled.setCursor(0, 10);
oled.print("next");
oled.setCursor(40, 10);
oled.print("yes");
oled.circle(10, 40, 7);
oled.circle(50, 40, 7);
oled.display();
if (digitalRead(buttonpin2) == HIGH) {
Serial.println("right button pressed");
oled.circleFill(50, 40, 7);
oled.display();
delay(500);
state = pattern1;
}
break;
case pattern1:
oled.clear(PAGE);
oled.display();
patternONE();
buttonState=0;
if (digitalRead(buttonpin) != buttonState) {
Serial.println("left button pressed");
// //задержка для регистрации нажатия кнопки
delay(500);
//
state = intro;
}
break;
////////////////////////////////////////////////////////
///////////ПЕРЕМЕЩЕННЫЙ КОНЕЧНЫЙ АВТОМАТ//////////////////
////////////////////////////////////////////////////////
case intro_flip:
oled.flipVertical(true);
oled.flipHorizontal(true);
oled.setFontType(1);
oled.setCursor(0, 0); // Устанавливаем текстовый курсор в верхний левый угол экрана.
//oled.setFontType(2);
// oled.setCursor(0, 0);
oled.print("choose pattern");
oled.circle(50, 40, 7);
oled.display();
buttonState = 0;
if (digitalRead(buttonpin) != buttonState) {
buttonState = 0; //сбросить состояние кнопки
oled.circleFill(50, 40, 7);
oled.display();
delay(500);
state = option1_flipped;
}
break;
case option1_flipped:
oled.flipVertical(true);
oled.flipHorizontal(true);
oled.clear(PAGE); // Очищаем буфер.
//задержка(300);
oled.setFontType(0);
oled.setCursor(0, 0); // Устанавливаем текстовый курсор в верхний левый угол экрана.
//oled.setFontType(2);
// oled.setCursor(0, 0);
oled.print("Pattern 1");
oled.setCursor(0, 10);
oled.print("yes");
oled.setCursor(40, 10);
oled.print("next");
oled.circle(10, 40, 7);
oled.circle(50, 40, 7);
oled.display();
if (digitalRead(buttonpin2) == HIGH) {
Serial.println("right button pressed");
oled.circleFill(10, 40, 7);
oled.display();
delay(500);
state = pattern1_flipped;
}
break;
case pattern1_flipped:
oled.clear(PAGE);
oled.display();
patternONE();
// buttonState=0;
if (digitalRead(buttonpin) != buttonState) {
Serial.println("left button pressed");
// //задержка для регистрации нажатия кнопки
delay(500);
//
state = intro_flip;
}
break;
}
}////////////////////////////////////////////////////////
///////////Шаблон/////////////////
////////////////////////////////////////////////////////
void patternONE() {
buttonState = 0;
unsigned int chip1 = 0;
unsigned int chip2 = 0;
byte inbyte = 0;
byte inbyte2 = 0;
for (int i = 0; i < 3; ++i) {
digitalWrite(css2, LOW);
chip2 = SPI.transfer16(column_pattern1[i]);
Serial.print("chip2 column off=");
Serial.println(chip2, BIN);
digitalWrite(css2, HIGH);
digitalWrite(css1, LOW);
chip1 = SPI.transfer16(0b0001010000000000);
Serial.print("chip1 row 8 on high driver= ");//не чип - это взгляд назад, поэтому операторы печати - это предыдущий вывод
Serial.println(chip1, BIN);
digitalWrite(css1, HIGH);
delay(1);
digitalWrite(css1, LOW);
chip1 = SPI.transfer16(0b0100000100000000);
Serial.print("chip1 row 4 and 6 on low driver= ");
Serial.println(chip1, BIN);
digitalWrite(css1, HIGH);
delay(2000);
digitalWrite(css1, LOW);
chip1 = SPI.transfer16(0b0001010001010000);
Serial.print("chip1 row 8 on low driver= ");
Serial.println(chip1, BIN);
digitalWrite(css1, HIGH);
delay(1);
digitalWrite(css1, LOW);
chip1 = SPI.transfer16(0b0100000100000100);
Serial.print("chip1 row 4 and 6 on high driver= ");
Serial.println(chip1, BIN);
digitalWrite(css1, HIGH);
digitalWrite(css2, LOW);
chip2 = SPI.transfer16(column_pattern1[i]);
Serial.print("chip2 column on high driver= ");
Serial.println(chip2, BIN);
digitalWrite(css2, HIGH);
//отключить предыдущий столбец
// digitalWrite(css2, LOW);
// чип2 = SPI.transfer16(column_off_pattern1[i]);
// Serial.print("chip2 column on high driver=");
// Serial.println(chip2, BIN);
// digitalWrite(css2, HIGH);
//
delay(2000);
}
}
// водяной знак генерирует это прерывание
void button_pressed()
{
cli();
//подтверждаем, что кнопка была нажата и это не просто отскок"
if (millis() - prevTime > 50) {
Serial.println("left button pressed");
buttonState = 1;
Serial.println("buttonState =");
Serial.println(buttonState);
}
sei();
prevTime = millis();
}
@Bob, 👍0
Обсуждение1 ответ
Судя по вашему вопросу, вы ожидаете, что PatternONE() вернёт значение при нажатии кнопки, но я не вижу в функции кода, который бы ссылался на кнопку или выполнял какие-либо действия. Функция определяет локальную переменную buttonState и инициализирует её значением 0, но больше к ней не обращается.
Я подозреваю, что вы имели в виду объявление глобального buttonState, но у вас есть две проблемы: 1) функция никогда не использует buttonState для инициирования возврата; и 2) локальное определение buttonState скрывает глобальное, пока оно находится в области видимости, т. е. пока функция выполняется.
Если какой-либо код не пропущен, patternOne() не объявляет локальную переменную. Он присваивает глобальной переменной значение 0., @Craig
Упс, верно. Он сбрасывает глобальную переменную, но больше к ней не обращается., @JRobert
Оказалось, что мне нужно было закомментировать buttonState=0; сразу после patternONE(); в случае pattern1, и тогда всё заработало нормально., @Bob
- Использование millis() и micros() внутри процедуры прерывания
- Подсчет импульсов с прерыванием
- Как работают прерывания на Arduino Uno и аналогичных платах?
- Устранение дребезга кнопки с помощью прерывания
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Программа arduino выдаёт ошибку expected //primary-expression before ')' token error: //expected ';' before '}' token E
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- Использование поворотных энкодеров с прерываниями смены контактов
Можно начать с отладки методом прямого перебора с помощью Serial.println. Выведите текущее состояние до переключения и каждое изменение состояния, а затем добавьте дополнительные println по мере необходимости для отслеживания ошибки., @Craig
Откуда вы знаете, что вы никогда не покидаете PatternONE(), а не вызываете его снова и снова?, @Craig
хм, это хороший вопрос, если я буду вызывать его снова и снова, как мне тогда его оставить?, @Bob
См. предыдущий комментарий — отладка с помощью Serial.println(), @Craig
Спасибо за помощь, Крейг! Это сработало, когда я сделал грубую операцию., @Bob