Up Down Counter using FSM

Revision:
0:7c0953072ecb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 10 13:42:11 2020 +0000
@@ -0,0 +1,126 @@
+/*
+
+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
+}
\ No newline at end of file