Up Down counter using a transition table

main.cpp

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

File content as of revision 1:1e34d5c96ecf:

/*

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);

// struct for state
struct State {
    int output;  // output value for current state
    int time;  // wait time for state (ms)
    int next_state[2]; // next state (depending on direction 0 - UP, 1 - DOWN)
};

// array of states in the FSM, each element is the output of the counter, wait time, next state(s)
State g_fsm[4] = {
    {0b0001,500,{1,3}},
    {0b0010,500,{2,0}},
    {0b0100,500,{3,1}},
    {0b1000,500,{0,2}},
};

// 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
            direction = ! direction;
        }

        // set output of current state (use dot syntax to access struct members)
        output = g_fsm[state].output;
        // implement required delay
        thread_sleep_for(g_fsm[state].time);
        // set the next state depending on direction
        state = g_fsm[state].next_state[direction];

    }
}

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