如何完善和扩展 Arduino 有限状态机

How to Refine and Expand Arduino Finite State Machine

我正在努力在我的 Arduino 程序中建立一个状态机,我想我有一个足够简单的程序来学习有限状态机。目前我遇到的问题是每次程序更改状态时,它都会用它的状态或正在记录的数据淹没串行监视器。我创建了一些在非常有限的级别上工作的东西,但我觉得我无法扩展它,因为这段代码只有在我有 3 个状态时才有效。但是如果我想要 4 或 5 个状态呢?

我希望在程序继续 运行 时每次状态更改时在串行监视器中只提示一次。 例如,

  1. 如果程序空闲(状态 0),串口监视器什么也不显示。
  2. 如果程序只读,提示串行监视器(状态 1)一次,而不是每次执行读取时。
  3. 如果因为SPST开关状态改变导致程序正在读取和记录,则提示串口监视器(状态2)一次,而不是每次读取和记录时都提示。

我还想知道如何更好地解决这个问题,因为我觉得这似乎只适用于 3 态示例。如果我添加更多开关或更多状态会怎样?

快捷编程功能:

  1. 等待 100 毫秒。
    • LED1 状态高
    • LED2 状态低
  2. 如果 SPST 开关为高电平,读取模拟输入引脚并 return 回到空闲状态。(此时会有一个显示器挂起,无论是否正在记录数据都会显示值)。
    • LED1 状态低
    • LED2 状态低
  3. 如果 SPST 开关为低电平,则将读取的数据记录到文件中。
    1. 如果这是第一次,请使用 unix 名称创建一个文件。
    2. 如果这不是第一次(文件存在),打开它并附加到它。
      • LED1 状态低
      • LED2 状态为高

我有这样的工作,但感觉效率低下,我是幸运的。我一直在努力执行有限状态机。

void setup() {
  Serial.begin(57600);   // Initiate serial
  delay(100);
  // Set pinmodes
  // Start and adjust RTC
  // Begin RTC
  delay(100);
  // Initialize SD Card
}

void loop() {
  // Read to see if the switch has changed states
  PIN_STATE = digitalRead(PIN_SWITCH);
  currentMillis = millis();

  // State 0 - Idle
  if (currentMillis - previousMillis < interval) {
    STATE = STATE;   // State flag set
    led_status(HIGH, LOW);
    digitalWrite(PIN_READ, LED_READ);
  }

  // State 1 - Read Only
  if ((PIN_STATE == HIGH) && (currentMillis - previousMillis >= interval)) {
    if (CHANGE_STATE) {
      STATE = 1;   // State flag set
      Serial.println("Changed state: Read");
    }
    previousMillis = currentMillis;  // Remember the time
    led_status(LOW, LOW);  // Update LEDs
    read();  // Read the pins
    CHANGE_STATE = false;
  }

  //State 2 - Read and Record
  else if ((PIN_STATE == LOW) && (currentMillis - previousMillis >= interval)) {
    if (!CHANGE_STATE) {
      Serial.println("Changed state: Read and Record");
    }
    previousMillis = currentMillis;  // Remember the time
    led_status(LOW, HIGH);  // Update LEDs
    read();   // Read the pins

    if (STATE < 2) {  // Was a file already created?
      // Create new file
    }
    filename = filename;
    open();   // Open the file
    write();  // Write to the file
    close();  // Close the file
    STATE = 2;   // State flag set
    CHANGE_STATE = true;
  }
}

void read() {
  //Read Values

  //Calculate Values
}

void open() {
  // Open the file
}


void write() {
  // Write to file
}

void close() {
  // Close the file
}

void led_status(int led_one, int led_two) {
  // Change the status of LEDS

更新,解决。 从 Arcadien 下面提供的文章中,我能够重新思考程序流程并将其重写为 switch case 状态机。

// Declare the states
enum state {
  _readState,
  _displayState,
  _createState,
  _openState,
  _writeState,
  _saveState,
  _errorState
};

void loop() {
  pinState = digitalRead(pinSwitch);
  // Green LED HIGH
  // Yellow LED LOW
  currentMillis = millis();

  if ((currentMillis - previousMillis) >= interval) {
    switch (_currentState) {

      case _readState:
        //Serial.println("Current State: _readState");
        // Green LED LOW
        _currentState = _readState;
        previousMillis = currentMillis;
        //Read Values

      case _displayState:
        //Serial.println("Current State: _displayState");
        _currentState = _displayState;
        previousMillis = currentMillis;
        if (pinState != LOW) {    // If not recording, then break
          filename = "";
          _currentState = _readState;
          break;
        };

      case _createState:
        //Serial.println("Current State: _createState");
        // Yellow LED HIGH
        _currentState = _createState;
        previousMillis = currentMillis;
        if (filename == NULL) {
          //Serial.print("Creating new file... ");
          DateTime now = rtc.now();
          filename = String(now.unixtime(), DEC);
          filename = filename + ".txt";
          //Serial.print(filename);
          //Serial.println(" created!");
          //Serial.print("Writing header to file... ");
          //dataFile = SD.open(filename, FILE_WRITE);
          dataFile = SD.open(filename, O_WRITE | O_CREAT);
          dataFile.println("Time(ms), TPS, AFR");
          //Serial.println("header written!");
          dataFile.close();
        };

      case _openState:
        //Serial.println("Current State: _openState");
        _currentState = _openState;
        dataFile = SD.open(filename, O_CREAT | O_APPEND | O_WRITE);     // Open filename.txt

      case _writeState:
        //Serial.println("Current State: _writeState");
        _currentState = _writeState;
        // if the file is available, write to it:
        if (dataFile) {
          // Create a single line string of data
          dataFile.println(_data);  // Write data
        }
        // if the file didn't open, throw errors
        else {
          Serial.print("error opening ");
          Serial.println(filename);
          _currentState = _errorState;
        }

      case _saveState:
        //Serial.println("Current State: _saveState");
        _currentState = _saveState;
        dataFile.flush();
        dataFile.close();
        _currentState = _readState;
        break;

      case _errorState:
        _currentState = _errorState;
        // Red LED HIGH
    }
  }
  // Return to the begining
}

你应该看看这里的其他答案,比如 this one。粗略地说,您必须将机器及其状​​态分开。嵌入式代码通常需要紧凑和高效,状态机可以使用转换表来实现。