In simpler terms, a state machine will read a series of inputs. When it reads an input, it will switch to a different state. Each state specifies which state to switch to, for a given input. Lets start with a very simple ans useless example but good for illustrative purpose:

The following diagram illustrate a program with two states, a is an state polling a mechanical button, if this button has been press a transition to state b will happens, in state b a counter will be incremented and then a transition back to state a is generated automatically. Inside state a if no press action ocurres then the program will remain waiting in the same state.

Very good, but tell me how can i reflect the previous diagram into actual code, well it’s pretty simple. One way is using the switch statement:

switch( state )
{
    case STATE_A :
        if( button == PRESS )
        {
            /*move the state machine to state B*/
            state = STATE_B;
        }
    break;
    case STATE_B :
        counter++;
        /*This transition is not under any condition*/
        state = STATE_A;
    break;
}

know, i know, this code can be easily simplified to one if statement, but like i say it is only to illustrate how a state machine can be translated to code. We can do something more elaborated, for instance an crappy algorithm to detect a single click and double click ( like a computer mouse ). Its state machine will look like this:

  • State idle will wait until the first press is detected then start a timer and transition to debounce
  • State debounce wait until the button has been release to transition to single click
  • State single click wait until the button is press a second time or a timeout of 300ms to transition to idle again or double click
  • State double click waits until the button has bee released

Again, this is only to illustrate a more elaborated state machine ( it has a lot of room for improvements ), but keep it simple is my philosophy

switch( state )
{
    case STATE_IDLE :
        if( button == PRESS )
        {
            StartTimer();
            state = STATE_DEBOUNCE;
        }
    break;
    case STATE_DEBOUNCE :
        if( button == RELEASE )
        {
            state = STATE_SINGLE_CLICK;
        }
    break;
    case STATE_SINGLE_CLICK :
      if( GetTimer() >= _300ms )
      {
          Report( SINGLE_CLICK );
          ResetTimer();
          state = STATE_IDLE;
      }
      else if( button == PRESS )
      {
          state = STATE_DOUBLE_CLICK;
      }
    break;
    case STATE_DOUBLE_CLICK :
      if( button == RELEASE )
      {
          Report( DOUBLE_CLICK );
          ResetTimer();
          state = STATE_IDLE;
      }
    break;
}

There is something interesting we can do, there is no need to poll the button continuously, it is much better if we do every 50ms, so we can enclosure the state machine into a function, and call this function every 50ms. The timer inside the machine can be replace by a counter, because 50ms x 6 = 300ms.

:
:
while(1)
{
    if( Timer() == _50ms )
    {
        clikingStateMachine();
    }
}
:
:
/*somewhere else in the code*/
void clikingStateMachine( void )
{
    static int counter;
    static int state = IDLE;
    
    /*instead of a timer we use a variable counter, every increment indicate 50ms has been passed*/
    counter++; 
    
    switch( state )
    {
        case STATE_IDLE :
            if( button == PRESS )
            {
                counter = 0;
                state = STATE_DEBOUNCE;
            }
        break;
        case STATE_DEBOUNCE :
            if( button == RELEASE )
            {
                state = STATE_SINGLE_CLICK;
            }
        break;
        case STATE_SINGLE_CLICK :
            if( counter >= 6 )
            {
                Report( SINGLE_CLICK );
                state = STATE_IDLE;
            }
            else if( button == PRESS )
            {
                state = STATE_DOUBLE_CLICK;
            }
        break;
        case STATE_DOUBLE_CLICK :
            if( button == RELEASE )
            {
                Report( DOUBLE_CLICK );
                state = STATE_IDLE;
            }
        break;
    }
}

There is another way to represent state machines, using pointer to functions where each state is represented by a function. From the previous code example lets convert it to pointer to functions

uint8_t state = 0;
uint8_t counter = 0;

/*Array of fucntion pointers*/
void (*vfPointerFunctions[])(void) =
{
    stIdle,
    stDebounce,
    stSingleClick,
    stDoubleClick
};

/*This function should be called every 50ms*/
void clikingStateMachine( void )
{
    vfPointerFunctions[state]();
}

void stIdle( void )
{
    if( button == PRESS )
    {
        counter = 0;
        state = STATE_DEBOUNCE;
    }
}

void stDebounce( void )
{
    if( button == RELEASE )
    {
        state = STATE_SINGLE_CLICK;
    }
}

void stSingleClick( void )
{        
    if( counter >= 6 )
    {
        Report( SINGLE_CLICK );
        state = STATE_IDLE;
    }
    else if( button == PRESS )
    {
        state = STATE_DOUBLE_CLICK;
    }
}

void stDoubleClick( void )
{        
    if( button == RELEASE )
    {
        Report( DOUBLE_CLICK );
        state = STATE_IDLE;
    }
}

This was a very simple example on ow to work with state machines, try to implement this paradigm as often as you need in your programs, and also combine with concurrent process both plays very well. On further publication we are going to talk more about state machines, and trust me can be as powerful as complex