Finite State Machine for dummies like me

For long I struggled with the concept of the FSM but I need it to get more complicated sketches running.

For my MouseOleum mousetrap I needed a LED which blinks according to the amount of mice caught.

First I discovered this code I copied but did not understand

void blinkMouseCountLed()
{
  /*
    The count variable controls when to blink and how many times.
    While it's zero, no blinking.
    When not blinking, it keeps comparing actual time with the last time it blinked.
    When the time exceed <INTERVAL>, it puts count to five, and in the next loop, the blinking start.
    Variables are declared static so they keep their values between loop executions.
  */

  unsigned long now = millis();

  if (count > 0)
  {
    count = count - blink();
    lastBlink = now;
  }
  else
  {
    if (now - lastBlink >= LED_BLINK_INTERVAL)
    {
      count = mousecounter;
    }
  }
}

/*
   Do one blink.
   Return 1 when blink is done.
*/
int blink()
{
  static unsigned long lastFlip = 0;
  static int count = 0;
  bool last = true;
  unsigned long now = millis();

  if (now - lastFlip >= LED_BLINK_RATE)
  {
    digitalWrite(LED, !digitalRead(LED));
    lastFlip = now;
    count++;
    if (count == 2)
    {
      count = 0;
      last = false;
    }
  }
  return (last) ? 0 : 1;
}

then I made a very simple to understand FSM myself.
Far from professional coding but this way others who want to build my open source project can understand it and learn to make projects themselves...

#include <Arduino.h>

int ledBlinkCounter = 0;
unsigned long timerLedOn = 0;
unsigned long timerLedOff = 0;
unsigned long timerWait = 0;

// user settings
// normally the HOW_MANY_BLINKS will be a global int variable used elsewhere
#define HOW_MANY_BLINKS 3
#define LED_ON_TIME 500
#define LED_OFF_TIME 200
#define PAUSE_TIME 2000

// this is just to give INTEGERS a NAME so 'START' is really just the numer '0'
// to the compiler etc...
enum blinkStates
{
  START,
  LED_ON,
  LED_ON_DELAY,
  LED_OFF,
  LED_OFF_DELAY,
  REPEAT_BLINK,
  PAUSE
};
// set initial FSM state
int ledState = START;

// compiler stuff
void blink_led(void);

//-----------------------------------------------------------
void setup()
{
  // set ports
  pinMode(13, OUTPUT);
}

//-----------------------------------------------------------
void loop()
{
  // call blink function
  blink_led();

  // rest of your code here
  // NEVER USE DELAY if possible else this won't work anymore
}

//-----------------------------------------------------------
void blink_led()
{
  switch (ledState)
  {
  case START:
    if (HOW_MANY_BLINKS > 0)
    {
      // init counter
      ledBlinkCounter = 0;
      ledState = LED_ON;
    }
    break;

  case LED_ON:
    digitalWrite(13, HIGH);
    // start LED on timer
    timerLedOn = millis();
    // increase blink counter
    ledBlinkCounter += 1;
    // go to next state
    ledState = LED_ON_DELAY;
    break;

  case LED_ON_DELAY:
    // check if the LED_ON time has passed
    if (millis() - timerLedOn > LED_ON_TIME)
    {
      // goto next state, else ignore and exit...
      ledState = LED_OFF;
    }
    break;

  case LED_OFF:
    digitalWrite(13, LOW);
    timerLedOff = millis();
    ledState = LED_OFF_DELAY;
    break;

  case LED_OFF_DELAY:
    if (millis() - timerLedOff > LED_OFF_TIME)
    {
      ledState = REPEAT_BLINK;
    }
    break;

  case REPEAT_BLINK:
    if (ledBlinkCounter < HOW_MANY_BLINKS)
    {
      ledState = LED_ON;
    }
    else
    {
      timerWait = millis();
      ledState = PAUSE;
    }
    break;

  case PAUSE:
    if (millis() - timerWait > PAUSE_TIME)
    {
      ledState = START;
    }
    break;
  }
}

Hopefully someone will benefit...

BTW: need a mousetrap?

50 mice caught in 2 months...

Took a while to get it right but now my design does work very well. :smiley:

Build your own MouseOleum trap