Finite State Machine: WOW!!

I have a question but never introduced myself.

I discovered the Arduino platform 1,5 years ago and was amazed... I gave up on electronics 30 years ago because I was ill but at 49 years old, I was better al last and able to enjoy all over again my electronics hobby but now with use of the Arduino!

After being bored looking at the blinking LED for 5 minutes, I decided to do something useful with the Arduino.

The DCF77 radio clocks are my sort of 'addiction', I love them and wanted to build one myself. But not the usual clocks but one that is able to display every bit received besides displaying the time etc.

It was a very steep learning curve, it was difficult but I enjoy my clock now every day.
But programming the clock was not very elegant to say it mildly. Experienced programmers will be laughing, rolling on the floor, seeing my code but it does work. :wink:

Someone mentioned a Finite State Machine but for me it was so overwhelming at that time!

Months later, I decided to make a very simple 'bedside' clock, with 3 buttons to set the time...
Simple? I immediately stumbled in the difficulty how on earth to program button input...

That's when I stumbled again into the Finite State Machine. This was my solution but how???
For newbies there is NO GOOD INFORMATION available on the whole internet... AMAZING

So after day of searching, I found this sketch.
In the comments, the author encouraged people to look through it and this way learn how Finite State Machine coding works. So I did and I was VERY ENTHUSIASTC, discovering the possibilities and getting structure im my programming which is hard enough for an inexperienced elderly man like me :wink:

QUESTION:

I used in my first attempt, separate functions for USERINPUT and TRANSITION, is this the right approach?

my loop() looks like this:
Full code here
Video (sorry, in Dutch...)

void loop()
{
    executeState();                          // execute (new) state of FSM
    checkUserInput();                      // check for button state/user input
    checkRTCstatus();                      // check connection with RTC, ERROR: activate decimal point 
    adjustBrightness();                    // check ambient light and adjust the display brightness
}

I want to learn using Finite State Machine the right way from the start so comments are appreciated!

I discovered the Arduino platform 1,5 years ago and was amazed... I gave up on electronics 30 years ago because I was ill but at 49 years old, I was better al last and able to enjoy all over again my electronics hobby but now with use of the Arduino!

Good for you!

I have not had a chance to look at all your work but here are some examples:

http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html

Here is a very simple skeleton for a state machine:

//State Machine example
//LarryD

byte messageNumber;
unsigned long TaskWait;
unsigned long FlashTime;
unsigned long currentmillis; 

//define the available machine states that we can have for this sketch
//add more states as needed
enum States{
  stateStart, stateApple, stateOrange, statePear, statePeach, stateKiwi};

//mState = machine State
States mState = stateStart;              //we start out in this machine state 

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);
  FlashTime = millis();
  TaskWait = millis();                   //initialize the next wait time
  mState = stateStart;                   //we start out in this machine state 

} //        >>>>>>>>>>>>>> END OF setup() <<<<<<<<<<<<<<<<<


void loop()
{
  //leave this line of code at the top
  currentmillis  = millis();

  //***************************
  //just some code to see if the sketch is blocking
  if (CheckTime(FlashTime, 100UL))
  {
    digitalWrite(13,!digitalRead(13));
  }
  //***************************

  //Put your non-blocking regular stuff here


  //****************************************************************
  //Check machine state and do things that must be done accordingly 
  switch (mState)
  {
    //***************************
  case stateStart:
    {
      //let us wait for 5 seconds before we print the Welcome message
      if (CheckTime(TaskWait, 5000UL)) 
      //if (CheckTime(TaskWait, waitTime)) //we could use a variable for the time to wait 
      {      
        Serial.println(F("Welcome"));
        Serial.println(F("Press a KEY then press SEND"));
        Serial.println();
        //Other start stuff goes here

        mState = stateApple; //advance to the next state
      }
    }

    break; //end case stateStart:

    //***************************
  case stateApple: 
    {
      if (Serial.available() > 0)
      {
        // read the incoming character:
        char incomingChar = Serial.read();

        // print what you received:
        Serial.print(F("I received: "));
        Serial.println(incomingChar);
        Serial.println();

        messageNumber = 1;    //used in the next mState
        mState = stateOrange; //advance to the next mState
      }
    }

    break; //end case stateApple:

    //***************************
  case stateOrange:
    {
      //We will stay in this mState until some things are done
      switch(messageNumber)
      {
        //***************************
      case 1:
        Serial.println();
        Serial.println(F("Here is a message, we will wait 10 seconds and continue."));
        Serial.println(F("Notice the LED on pin 13 keeps flashing."));
        Serial.println();

        TaskWait = millis(); //initialize the next wait time
        messageNumber = 2;   //advance to the next messageNumber state

        break;

        //***************************
      case 2:
        if (CheckTime(TaskWait, 10000UL)) 
        {
          Serial.println   (F("Here is another message."));
          Serial.println   (F("We will now wait 5 sec and continue."));
          Serial.println();

          TaskWait = millis();
          messageNumber = 3;
        }   

        break;

        //***************************
      case 3:
        if (CheckTime(TaskWait, 5000UL)) 
        {
          Serial.println (F("We can print some instructions then pause for a while,"));
          Serial.println (F("this can be done without blocking other code from running."));
          Serial.println (F("We will now wait 10 sec and continue, however other things will still happen."));
          Serial.println();

          TaskWait = millis();
          messageNumber = 4;
        }

        break;

        //***************************
      case 4:
        if (CheckTime(TaskWait, 10000UL)) 
        {

          //we are now finished with this mState, advance to the next mState
          mState = statePear; 
        }

        break;

      } //end of switch messageNumber

      break;
    } //end case stateOrange:


    //***************************
  case statePear:
    {
      // You put statePear stuff here

      mState = statePeach; //we are now finished with this mState, advance to the next mState

      break;
    } //end case statePear:

    //***************************   
  case statePeach:
    {
      // You put statePeach stuff here

      mState = stateKiwi; //we are now finished with this mState, advance to the next mSstate

      break;
    } //end case statePeach:

    //***************************   
  case stateKiwi:
    {
      // You put stateKiwi stuff here

      break;
    } //end case stateKiwi:

  } // end of switch(mState)


} //        >>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<


//======================================================================
//                    F U N C T I O N S
//======================================================================

//***************************
//Delay time expired function
boolean CheckTime(unsigned long &lastMillis, unsigned long wait) 
{
  //is the time up for this task?
  if (currentmillis - lastMillis >= wait) 
  {
    lastMillis += wait;  //get ready for the next iteration

    return true;
  }

  return false;
} //END of CheckTime()

//***************************

//======================================================================
//                             END OF CODE
//======================================================================

Get a copy. Read it. (I see they are $2 for used.)

You may like to look at planning and implementing a program.

It uses states but I have not called them by the rather daunting name of Finite State Machine.

Using states or flag variables is just ordinary programming.

...R

@CB
Book looks interesting, thank you.

I found this link a while back, and it helped me get going on a Finite State Machine approach to my code.

http://digital-diy.com/general-programming/finite-state-machines.html

Yikes! I see the page is gone? (crap!)

Using the Web Archives you can still read it though:

Maybe its on the site somewhere still?

(maybe save the page for later viewing off-line?)

Here is the article in its new home:

http://digitaldiy.io/articles/mcu-programming/general-programming/500-finite-state-machines#.VOPRYBBLj5w

LarryD:
@CB Book looks interesting, thank you.

You are welcome.

The book is well written; easy to read and understand. The material is appropriate for any programming effort; not just microcontrollers. Various FSM implementations are discussed. The framework is beautiful and open source friendly.

Thank you all for the URL's!