Up Down Counter using FSM

main.cpp

Committer:
eencae
Date:
2020-12-10
Revision:
0:7c0953072ecb

File content as of revision 0:7c0953072ecb:

/*

2645_FSM_UpDown_Counter

Sample code from ELEC2645

Demonstrates how to implement a simple FSM up/down counter

(c) Craig A. Evans, University of Leeds, Jan 2016
Updated Jan 2020
Updated Dec 2020

*/

#include "mbed.h"
#include "platform/mbed_thread.h"

// defines directions as 0/1. Note UPPERCASE
#define UP 0
#define DOWN 1

// create a bus for writing to the output (LEDs) at once
BusOut output(LED4,LED3,LED2,LED1);
// Button A on board
InterruptIn buttonA(p29);

// array of states in the FSM, each element is the output of the counter
// set the output in binary to make it easier, 1 is LED on, 0 is LED off
int g_fsm[4] = {0b0001,0b0010,0b0100,0b1000};

// flag - must be volatile as changes within ISR
// g_ prefix makes it easier to distinguish it as global
volatile int g_buttonA_flag = 0;

// Button A interrupt service routine
void buttonA_isr();

int main()
{
    // Button A has a pull-down resistor, so the pin will be at 0 V by default
    // and rise to 3.3 V when pressed. We therefore need to look for a rising edge
    // on the pin to fire the interrupt
    buttonA.rise(&buttonA_isr);
    // since Button A has an external pull-down, we should disable to internal pull-down
    // resistor that is enabled by default using InterruptIn
    buttonA.mode(PullNone);
  
    // set inital state
    int state = 0;
    // set initial direction
    int direction = UP;

    while(1) {  // loop forever

        // check if flag i.e. interrupt has occured
        if (g_buttonA_flag) {
            g_buttonA_flag = 0;  // if it has, clear the flag

            // swap direction when button has been pressed
            // (could just use ! but want this to be explicit to aid understanding)
            if (direction == UP) {
                direction = DOWN;
            } else {
                direction = UP;
            }
        }

        output = g_fsm[state];  // output current state

        // check which state we are in and see which the next state should be next depending on direction
        switch(state) {
            case 0:
                switch(direction) {
                    case UP:
                        state = 1;
                        break;
                    case DOWN:
                        state = 3;
                        break;
                }
                break;
            case 1:
                switch(direction) {
                    case UP:
                        state = 2;
                        break;
                    case DOWN:
                        state = 0;
                        break;
                }
                break;
            case 2:
                switch(direction) {
                    case UP:
                        state = 3;
                        break;
                    case DOWN:
                        state = 1;
                        break;
                }
                break;
            case 3:
                switch(direction) {
                    case UP:
                        state = 0;
                        break;
                    case DOWN:
                        state = 2;
                        break;
                }
                break;
            default:  // default case
                error("Invalid state!");  //invalid state - call error routine
                state = 0;
                break;
        }

        thread_sleep_for(500);
    }
}

// Button A event-triggered interrupt
void buttonA_isr()
{
    g_buttonA_flag = 1;   // set flag in ISR
}