States Machine Example

Hello!

I wanted to write some example for begginers so i decided to make this simple states machine example which only needs Arduino Starter Kit materials :slight_smile: .

this is the circuit if you need to check connections:

States Machine Example

/*
  States Machine
  Sometimes you will need to switch between whats going to be executed on the loop section,
  this is called the machine state, it can be multiple things like diferent methods of motor
  control, switching between manual or automatic modes...etc 
  This example demonstrates a simple states machine who will switch the RGB led color depending on wich
  state its actually running.
  Materials:
  
    - 2 push buttons.
    - 3 resistors (220 Ohm).
    - RGB Led.
    
  The circuit:
  right pushbutton to PIN 3
  left pushbutton to PIN 2
  RGB led to (9,11,10) PINS  // Red = 9 , Green = 11,  Blue = 10 //
  Each Color pin of the RGB led its connected trought a 220 Ohm resistor.
  Created 28 January 2020
  By A.Roca
  
  https://github.com/kintstoner/statesMachine
*/

//PinOut Variables
//RGB LED
const byte red_light_pin= 9;  
const byte green_light_pin = 11;
const byte blue_light_pin = 10;
//Push Buttons
const byte rightPin = 3;
const byte leftPin = 2;

//Changing Variables
int right = 0; // Variables for storing buttons digital input.
int left = 0;
int machineState = 1;  // Variable for store the machine-state.

void setup() {

  // declare INPUT buttons 
  pinMode(rightPin, INPUT_PULLUP);
  pinMode(leftPin, INPUT_PULLUP);
  
  machineState = 1; //initializes machine state to 1
  
}
void loop() {

  loopMachineState(); // States Machine Loop Function

  //Read digital inputs 
  right = digitalRead(rightPin);
  left = digitalRead(leftPin);

  //Check if buttons are pressed - delay added to prevent bouncing.
  // Since we are using INPUT_PULLUP the button its pressed on LOW state.
  
  if(right == LOW){ //if right button pressed. 
    
    machineState++; //increase machine state by one.
    delay(100); 
    
  
  }
  if(left == LOW){ //if left button pressed.
    
    machineState--; //decrease machine state by one.
    delay(100);
  
  }
  
}

void loopMachineState(){
  
  // Loops a State depending on machineState variable, initial state is "1".
  // You can make it non-rotable by putting machineState = 1 in case 0 and machineState = 4 in case 5.
  // You can also add as many states as u want !!
  
  switch(machineState){
    
    case 0:
      machineState = 4;
      // to make it rotable  when you go less than 1 jumps into the last state 4.
      break;
    case 1:
      RGB_color(255, 0, 0); // Red
      delay(100);
      break;
    case 2:
      RGB_color(0, 255, 0); // Green
      delay(100);
      break;
    case 3:
      RGB_color(0, 0, 255); // Blue
      delay(100);
      break;
    case 4:
      RGB_color(255, 255, 0); // Yellow
      delay(100);
      break;
    case 5:
      machineState = 1;
      // to make it rotable  when you go further than 4 jumps into the first state 1.
      break;
  
  }

}

// This is a function writes the output of the RGB led.

void RGB_color(int red_light_value, int green_light_value, int blue_light_value)
 {
  analogWrite(red_light_pin, red_light_value);
  analogWrite(green_light_pin, green_light_value);
  analogWrite(blue_light_pin, blue_light_value);
}

statesMachine.ino (3.12 KB)

Pin numbers should be “const byte”, not “int”.

Pins used for analogWrite do not need to have pinMode set.

Normally, you’d use the built-in pullup resistors for the switch inputs, to simplify the wiring (you mention two 1k resistors, but don’t say how or where they should be wired)

If you’re not going to use machinestate zero, simply initialise machinestate to one when you define it.

Thanks for the advides! already updated. :slight_smile:

Suggest you remove all your delay()s and replace them with the millis() technique of BWD.

OPs component connections:


int right = 0; // Variables for storing buttons digital input.
int left = 0;
int machineState = 1; // Variable for store the machine-state.
Change to:
byte right = 0; // Variables for storing buttons digital input.
byte left = 0;
byte machineState = 1; // Variable for store the machine-state.


void RGB_color(int red_light_value, int green_light_value, int blue_light_value)
Change to:
void RGB_color(byte red_light_value, byte green_light_value, byte blue_light_value)


It’s best to use ‘switch change state detection’ instead of operating on ‘switch levels’.

Example of using a state machine to get rid of delay() calls. :wink:

// add-a-sketch_un-delay 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/18 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows a general method to get rid of delays in code.
// You could upgrade code with delays to work with add-a-sketch.

#include <avr/io.h>
#include "Arduino.h"

const byte ledPin = 13;
unsigned long delayStart, delayWait;

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Un-Delay Example, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows how to get rid of delays in code.\n" ));

  pinMode( ledPin, OUTPUT );
};


/* The section of the original sketch with delays:
 * 
 * digitalWrite( ledPin, HIGH );   --  0
 * delay( 500 );
 * digitalWrite( ledPin, LOW );    --  1
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  2
 * delay( 250 );
 * digitalWrite( ledPin, LOW );    --  3
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  4
 * delay( 1000 );
 * digitalWrite( ledPin, LOW );    --  5
 * delay( 1000 );
 */

byte blinkStep; // state tracking for BlinkPattern() below

void BlinkPattern()
{
  // This one-shot timer replaces every delay() removed in one spot.  
  // start of one-shot timer
  if ( delayWait > 0 ) // one-shot timer only runs when set
  {
    if ( millis() - delayStart < delayWait )
    {
      return; // instead of blocking, the undelayed function returns
    }
    else
    {
      delayWait = 0; // time's up! turn off the timer and run the blinkStep case
    }
  }
  // end of one-shot timer

  // here each case has a timed wait but cases could change Step on pin or serial events.
  switch( blinkStep )  // runs the case numbered in blinkStep
  {
    case 0 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 0 doing something unspecified here at " ));
    Serial.println( delayStart = millis()); // able to set a var to a value I pass to function
    delayWait = 500; // for the next half second, this function will return on entry.
    blinkStep = 1;   // when the switch-case runs again it will be case 1 that runs
    break; // exit switch-case

    case 1 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 1 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 2;
    break;

    case 2 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 2 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 3;
    break;

    case 3 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 3 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 4;
    break;

    case 4 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 4 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 5;
    break;

    case 5 :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "Case 5 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 0;
    break;
  }
}


void loop()  // runs over and over, see how often
{            
  BlinkPattern();
}