An example solution for the two switch - flashing LED problem

Fork of Task324Solution by University of Plymouth - Stages 1, 2 and 3

main.cpp

Committer:
noutram
Date:
2019-09-11
Revision:
5:0e52b9b0b1f8
Parent:
3:ba009495c5ef

File content as of revision 5:0e52b9b0b1f8:

#include "mbed.h"

//Next state logic for switch debounce
void updateSwitchState(int sw, int &swState, Timer &tmr, unsigned short &debouncedSwitchOutput);
//Moore outputs for switch debounce
void updateSwitchOutputs(int swState, unsigned short &debouncedSwitchOutput);
//Mealy machine for timer interval
static void updateFlashIntervalFSM(float &interval, unsigned short sw1, unsigned short sw2);

DigitalOut  red_led(D7);
DigitalOut  green_led(D5);
DigitalIn   SW1(D4);
DigitalIn   SW2(D3);
//This is the solution based on the proposed flowchart.
//The precise delay required may need adjusting

Timer tmr1;
Timer tmr2;
Timer flashTimer;

#define WAITING4PRESS 0
#define WAITING4BOUNCE_RISING 1
#define WAITING4RELEASE 2
#define WAITING4BOUNCE_FALLING 4

#define SWPRESSED  1
#define SWRELEASED 0

int main()
{
    //Initial logging message
    puts("START");

    //Power on check
    red_led    = 1; //Set RED LED to OFF
    green_led  = 1;
    wait(1.0);
    
    //Initial state
    red_led    = 0; //Set RED LED to OFF
    green_led  = 0;

    //Switch state
    int sw1State = 0;
    int sw2State = 0;

    //Timers
    tmr1.stop();
    tmr1.reset();
    tmr2.stop();
    tmr2.reset();
    flashTimer.stop();
    flashTimer.reset();
    flashTimer.start();

    //Initial logging message
    puts("Entering state WAITING4PRESS");

    //Debounced outputs
    unsigned short sw1_db = SWRELEASED;
    unsigned short sw2_db = SWRELEASED;

    //Timer delay
    float flashInterval = 1.0f;
    
    //Main Polling Loop
    while (true) {

        //Poll inputs (without blocking)
        int sw1 = SW1;
        int sw2 = SW2;

        //SWITCH DEBOUNCE FSM
        updateSwitchState(sw1, sw1State, tmr1, sw1_db);
        updateSwitchState(sw2, sw2State, tmr2, sw2_db);

        //Update flashInterval
        updateFlashIntervalFSM(flashInterval, sw1_db, sw2_db);

        //LED TIMER DELAY FSM (trivial)
        if (flashTimer >= flashInterval) {
            green_led = !green_led;
            flashTimer.reset();
        }
        

    } //end while

}

//Here is an example of a self-contained finite state machine
//sw1 and sw2 are debounced, so no need for timers
//interval is a Mealy output (keeps the FSM small)
static void updateFlashIntervalFSM(float &interval, unsigned short sw1, unsigned short sw2)
{   
    //This data type is private to this function
    enum FI_STATE {NOPRESS, PRESSED};

    //This is a static local - it is initilaised ONCE and remembers it's value with each function call
    static FI_STATE state = NOPRESS;
    
    //Simple FSM to update the interval - reduced to 2 states
    switch (state) {
        case NOPRESS:
            if (sw1 && sw2) {
                state =  PRESSED; 
                interval = 1.0; //Mealy output  
            } else if (sw1 & !sw2) {
                state =  PRESSED; 
                interval += ((interval>0.2f) ?  -0.1f : 0.0f);
            } else if (!sw1 & sw2) {
                state = PRESSED;
                interval += 0.1f;
            }
            break;  
        case PRESSED:  
            //All states lead back to NOPRESS when both are released
            if (!sw1 && !sw2) {
                state = NOPRESS;    
            }
            //If at any time both are pressed, reset the interval
            else if (sw1 && sw2) {
                interval = 1.0; //Mealy output      
            }
            break;
        default:
            printf("ERROR");
            state = NOPRESS;
            interval = 1.0;
    }  //End case
} //End function

// Update the state for a given switch and LED pair
// Parameters:
// sw is the switch input, 0 for released and 1 for pressed, passed by value
// swState is an integer that keeps a record of state, passed by reference (updated by the function)
// REMOVED led is of type DigitalOut, connected to a LED
// tmr is of type Timer, a reference to  unique instance of a timer
// This function cannot be called by an ISR
void updateSwitchState(int sw, int &swState, Timer &tmr, unsigned short &debouncedSwitchOutput)
{
    //LED
    switch (swState) {

            //Waiting for switch to be pressed
        case WAITING4PRESS:

            if (sw == 1) {
                //Output: start timer
                tmr.reset();
                tmr.start();

                //Next state
                swState =  WAITING4BOUNCE_RISING;
                puts("Entering state: WAITING4BOUNCE_RISING");
            }
            break;

            //Waiting for 50ms to elapse
        case WAITING4BOUNCE_RISING:
            if (tmr.read_ms() > 50) {
                //Outputs: Stop timer
                tmr.stop();
                //Next state
                swState =  WAITING4RELEASE;
                puts("Entering state: WAITING4RELEASE");
            }
            break;

            //Waiting for switch to be released
        case WAITING4RELEASE:
            if (sw == 0) {
                tmr.reset();
                tmr.start();
                //Next state
                swState =  WAITING4BOUNCE_FALLING;
                puts("Entering state: WAITING4BOUNCE_FALLING");
            }
            break;

            //Waiting 50ms for switch bounce
        case WAITING4BOUNCE_FALLING:
            if (tmr.read_ms() > 50) {
                //Outputs: Reset timer 1
                tmr.stop();
                tmr.reset();

                //Next state:
                swState = WAITING4PRESS;
                puts("Entering state: WAITING4PRESS");
            }
            break;

        default:
            //Something has gone very wrong
            tmr.stop();
            tmr.reset();
            swState = WAITING4PRESS;
            puts("ERROR");
            break;

    } //end switch

    //Moore outputs
    updateSwitchOutputs(swState, debouncedSwitchOutput);

} //end function


//Moore Outputs - asserted with each pass. Could be convered easily to Mealy outputs
// swState is the state of the switch debounce finite state machine
// debouncedSwitchOutput is the Moore output for the state machine
void updateSwitchOutputs(int swState, unsigned short &debouncedSwitchOutput)
{
    switch (swState) {
            //Waiting for switch to be pressed
        case WAITING4PRESS:
            debouncedSwitchOutput = SWRELEASED;
            break;
            //Waiting for 50ms to elapse
        case WAITING4BOUNCE_RISING:
            debouncedSwitchOutput = SWRELEASED;
            break;
            //Waiting for switch to be released
        case WAITING4RELEASE:
            debouncedSwitchOutput = SWPRESSED;
            break;
            //Waiting 50ms for switch bounce
        case WAITING4BOUNCE_FALLING:
            debouncedSwitchOutput = SWRELEASED;
            break;
        default:
            //Something has gone very wrong
            debouncedSwitchOutput = SWRELEASED;
            printf("ERROR\n\r");
            break;
    } //end switch
} //end function