Does State machine coding work on Nano

Just another question, can a State Machine work on a nano? This is just for pure interest.

I was trying test sketch I tried using off a tutorial wouldn't work. Had heaps of errors. They were using a UNO I am not familiar enough with arduino boards to know if all sketches are universal on all boards if the sketch doesn't involve onboard sensors etc. This sketch was a very basic push button debouncing.

example:

//Title: Button Debouncing using a State Machine
//Author: Chris Guichet
//Date: Jan 15, 2018
//
//Description:
//  -A State Machine is a useful tool to organize complex code
//  -Think of it like the next step beyone "If Else" statements
//  -This example code uses a State Machine to handle tac switch debouncing
//  -It also has a "Hold" function to enable interaction with long button presses
//  -The tac switch is used to control a buzzer and an LED, it can multitask
//
//Wiring Instructions:
//  -Wire a SPST momentary switch between a Digital IO Pin 12 and Ground.  
//    (we will use an internal pullup resistor, so no need to worry about wiring a resistor)
//  -Wire an LED and a small resistor (~300 Ohm) in series
//  -Wire the series LED & Resistor between  Digital IO Pin 7 and Ground.
//    (be sure the + terminal of the LED points toward the IO pin)
//
//Code Reading Tip:
//  -Before mentally digesting this code, collapse all folds to get a bird's eye view. Instrucitons:
//  -Ctrl-a (to select all) -> Right Click -> Folding -> Collapse All Folds

//Top Level Variables:
int DEBUG = 1;  //Set to 1 to enable serial monitor debugging info

//Switch Variables (I'm calling this switch "s1"):
int state_s1 = 0;                   //The actual ~state~ of the state machine
int state_prev_s1 = 0;              //Remembers the previous state (useful to know when the state has changed)
int pin_s1 = 12;                    //Input/Output (IO) pin for the switch
int val_s1 = 0;                     //Value of the switch ("HIGH" or "LOW")
unsigned long t_s1 = 0;             //Typically represents the current time of the switch
unsigned long t_0_s1 = 0;           //The time that we last passed through an interesting state
unsigned long bounce_delay_s1 = 10; //The delay to list for bouncing
unsigned long hold_delay_s1 = 1000; //The time required to register a long press (a.k.a. "hold")

//Buzzer Variables (I'm calling this buzzer "bz1"):
int state_bz1 = 0;                  //The actual state of the state machine
int state_prev_bz1 = 0;             //Remember the previous state (useful to know if the state has changed)
int pin_bz1 = 6;                    //Buzzer pin
int val_bz1 = 0;                    //Buzzer value (on or off)
unsigned long t_bz1 = 0;            //Current time of the buzzer state machine (in milli seconds)
unsigned long t_0_bz1 = 0;          //The time that we last passed through a state of interest (in milli seconds)
unsigned long on_delay_bz1 = 500;   //On time for the buzzer as it beeps (in milli seconds)
unsigned long off_delay_bz1 = 500;  //Off time for the buzzer as it beeps (in milli seconds)
int beep_count_bz1 = 0;             //Number of times we've beeped on this journey
int beep_number_bz1 = 4;            //Number of times we should beep before resetting

//LED Variables (Variables similar to those above)
int state_led1 = 0;
int state_prev_led1 = 0;
int pin_led1 = 7;
int val_led1 = 0;
unsigned long t_led1 = 0;
unsigned long t_0_led1 = 0;
unsigned long on_delay_led1 = 500;
unsigned long off_delay_led1 = 500;
int beep_count_led1 = 0;
int beep_number_led1 = 4;

void setup() {
  // initialize digital pins
  pinMode(pin_s1,INPUT_PULLUP); //INPUT_PULLUP will use the Arduino's internal pullup resistor
  pinMode(pin_bz1,OUTPUT);
  pinMode(pin_led1,OUTPUT);

  //if DEBUG is turned on, intiialize serial connection
  if(DEBUG) {Serial.begin(115200);Serial.println("Debugging is ON");}
}

void loop() {
  //Instruct all the state machines to proceed one step (sometimes called a "cycle)
  StateMachine_s1();
  StateMachine_bz1();
  StateMachine_led1();

  //Provide events that can force the state machines to change state
  //I like to program interactions between state machines here in the top level loop
  if (state_s1 == 5) {state_led1 = 2;} //short press
  if (state_s1 == 6) {state_bz1 = 2;}  //long press

  if(DEBUG) {
    //Make a note whenever a state machine changes state
    //("Is the current state different from the previous? Yes? OK well let's tell the world the new state")
    if((state_prev_s1 != state_s1) | (state_prev_led1 != state_led1) | (state_prev_led1 != state_bz1)) {
      Serial.print("Switch State: "); Serial.print(state_s1);
      Serial.print(" | LED State: "); Serial.print(state_led1);
      Serial.print(" | Buzzer State: "); Serial.println(state_bz1);
    }
  }
}


void StateMachine_s1() {
  
  //Almost every state needs these lines, so I'll put it outside the State Machine
  val_s1 = digitalRead(pin_s1);
  state_prev_s1 = state_s1;

  //State Machine Section
  switch (state_s1) {
    case 0: //RESET!
      //Catch all "home base" for the State MAchine
      state_s1 = 1;
    break;

    case 1: //WAIT
      //Wait for the switch to go low
      if (val_s1 == LOW) {state_s1 = 2;}
    break;

    case 2: //ARMING!
      //Record the time and proceed to ARMED
      t_0_s1 = millis();
      state_s1 = 3;
    break;

    case 3: //ARMED
      //Check to see if the proper has delay has passed.  If a bounce occures then RESET
      t_s1 = millis();
      if (t_s1 - t_0_s1 > bounce_delay_s1) {state_s1 = 4;}
      if (val_s1 == HIGH) {state_s1 = 0;}
    break;

    case 4: //DRAWN
      //If switch goes HIGH, then TRIGGER. Also check timer for a "Long Pess"
      t_s1 = millis();
      if (val_s1 == HIGH) {state_s1 = 5;}
      if (t_s1 - t_0_s1 > hold_delay_s1) {state_s1 = 6;}
    break;

    case 5: //TRIGGERED!
      //reset the State Machine
      if (DEBUG) {Serial.println("TRIGGERED!!");}
      state_s1 = 0;
    break;

    case 6: //HOLD!
      //proceed to LOW WAIT
      if (DEBUG) {Serial.println("HOLDED!!");}
      state_s1 = 7;
    break;

    case 7: //LOW WAIT
      //wait for switch to go back HIGH, then reset
      if (val_s1 == HIGH) {state_s1 = 0;}
    break;
  }
  
}

void StateMachine_bz1() {

  //Almost every state needs these lines so I'll put it outside the State Machine
  state_prev_bz1 = state_bz1;

  //State Machine Section
  switch(state_bz1) {
    case 0: //RESET
      //Set Beep Count to 0 then proceed to WAIT
      beep_count_bz1 = 0;
      state_bz1 = 1;
    break;

    case 1: //WAIT
      //do nothing, the main loop can progress this Machine from state 1 to state 2
    break;

    case 2: //TURN ON
      //Start buzzer, record time then proceed to ON, 
      digitalWrite(pin_bz1,HIGH);
      t_0_bz1 = millis();
      state_bz1 = 3;
    break;

    case 3: //ON
      //Wait for time to elapse, then proceed to TURN OFF
      t_bz1 = millis();
      if (t_bz1 - t_0_bz1 > on_delay_bz1) {state_bz1 = 4;}
    break;

    case 4: //TURN OFF
      //Increment the beep counter, turn off buzzer, proceed to OFF
      beep_count_bz1++;
      t_0_bz1 = millis();
      digitalWrite(pin_bz1,LOW);
      state_bz1 = 5;
    break;

    case 5: //OFF
      t_bz1 = millis();
      if (t_bz1 - t_0_bz1 > off_delay_bz1) {state_bz1 = 2;}
      if (beep_count_bz1 >= beep_number_bz1) {state_bz1 = 0;}
    break;
  }
  
}

void StateMachine_led1() {
  //Almost every state needs these lines so I'll put it outside the State Machine
  state_prev_led1 = state_led1;
  //State Machine Section
  switch(state_led1) {
    case 0: //RESET
      //Set Beep Count to 0 then proceed to WAIT
      beep_count_led1 = 0;
      state_led1 = 1;
    break;
    case 1: //WAIT
      //Do nothing.  Only the top level loop can force us out of this state into state 2 "TURN ON"
    break;
    
    case 2: //TURN ON
      //Start buzzer, record time then proceed to ON, 
      digitalWrite(pin_led1,HIGH);
      t_0_led1 = millis();
      state_led1 = 3;
    break;
    case 3: //ON
      //Wait for time to elapse, then proceed to TURN OFF
      t_led1 = millis();
      if (t_led1 - t_0_led1 > on_delay_led1) {state_led1 = 4;}
    break;
    case 4: //TURN OFF
      //Increment the beep counter, turn off buzzer, proceed to OFF
      beep_count_led1++;
      t_0_led1 = millis();
      digitalWrite(pin_led1,LOW);
      state_led1 = 5;
    break;
    case 5: //OFF
      t_led1 = millis();
      if (t_led1 - t_0_led1 > off_delay_led1) {state_led1 = 2;}
      if (beep_count_led1 >= beep_number_led1) {state_led1 = 0;}
    break;
  }

}

Could you put your sketch between lines with three backslash-single-quotes ?

```
Your sketch
```

Or use the </> button.

Any device that can run code can run a Finite State Machine. It is just code.

Some Arduino boards have a EEPROM, some have Wifi, some have sensors, some have little memory and others a lot. Those kind of things are the differences.

By the way, the Nano is just a smaller Uno, they are almost the same.

Please follow the advice given in the link below when posting code , use code tags and post the code here to make it easier to read and copy for examination

Sorry still new to this. I was interested in this format of programming as it a good way to use multiple separate codes. I was trying it on a Nano 33BLE but I couldn't get it to run.

State machines are universal that is not language dependent. It is a technique to structure your analysis. They are used for FPGA programming, PLC programming, Arduino programming in all kinds of languages including VHDL, C, C++ and whatever language you can imagine.
The idea is that if you use discrete boolean logic, your system can end up in a undefined state and will be blocked. State machines define limited states and defined ways to go from A to B to C etc limiting the possibilities to end in a lock up. They are also easier to maintain compared to other techniques used for programming.

there are several cases where the state transition is ambiguous. i doubt the tutorial had such cases

should these cases be "else if"?

come state machines unnecessarily complicated

My first encounter with a state machine wasn't even able to run code. The device was built around core memory and the state machine was hard wired in TTL.

3 Likes

I've seem a couple of examples that used a prom/eprom to implement a state machine - the current state as well as some input signals are presented as the address, with the output of the selected memory address being the next state.

What types of errors? The sketch compiles without error.

A famous state machine was implemented in low level TTL hardware designed by a guy named Steve Wozniak at a little California start-up in the 70s.

Later it was redeployed as an ASIC known as the IWM, Integrated Wozniak Machine.

Disk controller.

a7

1 Like

Thank Johi.

I thought that was the case, it must be just an issue with something in the sketch.

Thanks all that answered my question.

David, it must of been a user error not code, ran it now and was fine.