проблема выхода из цикла 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();

}

, 👍0

Обсуждение

Можно начать с отладки методом прямого перебора с помощью Serial.println. Выведите текущее состояние до переключения и каждое изменение состояния, а затем добавьте дополнительные println по мере необходимости для отслеживания ошибки., @Craig

Откуда вы знаете, что вы никогда не покидаете PatternONE(), а не вызываете его снова и снова?, @Craig

хм, это хороший вопрос, если я буду вызывать его снова и снова, как мне тогда его оставить?, @Bob

См. предыдущий комментарий — отладка с помощью Serial.println(), @Craig

Спасибо за помощь, Крейг! Это сработало, когда я сделал грубую операцию., @Bob


1 ответ


1

Судя по вашему вопросу, вы ожидаете, что PatternONE() вернёт значение при нажатии кнопки, но я не вижу в функции кода, который бы ссылался на кнопку или выполнял какие-либо действия. Функция определяет локальную переменную buttonState и инициализирует её значением 0, но больше к ней не обращается.

Я подозреваю, что вы имели в виду объявление глобального buttonState, но у вас есть две проблемы: 1) функция никогда не использует buttonState для инициирования возврата; и 2) локальное определение buttonState скрывает глобальное, пока оно находится в области видимости, т. е. пока функция выполняется.

,

Если какой-либо код не пропущен, patternOne() не объявляет локальную переменную. Он присваивает глобальной переменной значение 0., @Craig

Упс, верно. Он сбрасывает глобальную переменную, но больше к ней не обращается., @JRobert

Оказалось, что мне нужно было закомментировать buttonState=0; сразу после patternONE(); в случае pattern1, и тогда всё заработало нормально., @Bob