Arduino 16x2 LCD Keypad Shield + Nucleo-F030R8 controlling PWM LED with LCD menu

Dependencies:   TextLCD mbed

Fork of Nucleo_LCD_Keypad_Shield by Sergey Frolov

Revision:
1:fbe0e730a150
Parent:
0:8f6ff5bb5a2d
Child:
2:f07832d7a563
--- a/main.cpp	Wed Dec 23 16:58:19 2015 +0000
+++ b/main.cpp	Fri Jul 15 12:21:12 2016 +0000
@@ -1,57 +1,363 @@
 #include "mbed.h"
 #include "TextLCD.h"
 
-Serial pc(SERIAL_TX, SERIAL_RX); 
-AnalogIn button(A0);    // Init button (SELECT, LEFT, UP, DOWN, RIGHT)
-// LCD (RS, E, D4, D5, D6, D7);
+////////////////////////////////
+// instantiations
+////////////////////////////////
+Serial pc(SERIAL_TX, SERIAL_RX);
+AnalogIn button(A0); // Init button (SELECT, LEFT, UP, DOWN, RIGHT)
 TextLCD lcd(D8, D9, D4, D5, D6, D7);
-PwmOut backlight(D10);  // Backlight LCD
-DigitalOut led(LED1);
+PwmOut backlight(D10); // Backlight LCD
+PwmOut blueLed(D15);
+Timer t;
+
+////////////////////////////////
+// variables and constants
+////////////////////////////////
+
+// keyboard keys
+#define COMMAND_NONE 0
+#define COMMAND_UP 1
+#define COMMAND_DOWN 2
+#define COMMAND_LEFT 3
+#define COMMAND_RIGHT 4
+#define COMMAND_SELECT 5
+
+// config menu options
+#define MENU_NONE 0
+#define MENU_LED_STATE 1
+#define MENU_LED_VALUE 2
+
+int menuOptions[2] = {
+    MENU_LED_STATE,
+    MENU_LED_VALUE
+};
+
+// config
+struct config_t {
+    bool ledLit;
+    bool ledChanged;
+    float ledValue;
 
-int main() {
-    
-    // Set backlight period and duty cycle 
+    config_t():ledLit(true), ledChanged(true), ledValue(0.5){}
+
+} config;
+
+// variables
+int meas;
+
+int command = COMMAND_NONE;
+int lastCommand = COMMAND_NONE;
+bool isInConfig = false;
+
+int currentOption = MENU_NONE;
+int lastOption = currentOption;
+
+int lastDebounceTime; // the last time the output pin was toggled
+int debounceDelay = 100; // the debounce time; increase if the output flickers
+int debounceReading = COMMAND_NONE; // last read command from keyboard
+int debounceCommand = COMMAND_NONE; // current command
+int debounceLastCommand = COMMAND_NONE; // last command
+
+void printFirstScreen()
+{
+    lcd.cls(); // Clear LCD
+    lcd.locate(0, 0); // Set the pointer to the first column, first row
+    lcd.printf("Press SELECT to enter setup"); // first time initialization
+}
+
+void initialize()
+{
+    // Start serial USB
+    pc.baud(9600);
+
+    // Set the LCD backlight
     backlight.period(0.002);
-    backlight = 1;
-    
-    
-    lcd.cls();                      // Clear LCD
-    lcd.locate(1,0);                // Set locate (1 row, 2 column)
-    lcd.printf("LCD Key Shield");
-    wait(1);
-    
-    int meas;
-    
-    while(1) {
-        led = (led == 1) ? 0 : 1;
+    backlight = 0.7;
+
+    // Print on LCD
+    printFirstScreen();
+
+     // Set the LED backlight
+    blueLed.period(0.001); // blueLed.period: 0.01 = 100Hz; 0.02 = 50Hz; 0.001 = 1kHz; 0.0001 = 10kHz;
+
+    // Start the timer
+    t.start();
 
-        meas = button.read() * 1000; // Read the analog input value (value from 0.0 to 1.0) and convert to int value (from 0 to 1000)
-        
-        lcd.cls();
-        lcd.locate(0,0);
-        lcd.printf("Press button");
-        lcd.locate(0,1);
-        
-        if (meas < 50) { 
-            lcd.printf("BUTTON: Right ");
-            backlight = 0.5;        // Set 50% backlight 
+    // Serial debug
+    pc.printf("Initialization complete\n");
+}
+
+// the debounce was taken from https://www.arduino.cc/en/Tutorial/Debounce
+void readKeyboard()
+{
+    meas = button.read() * 1000; // Read the analog input value (value from 0.0 to 1.0) and convert to int value (from 0 to 1000)
+
+    // read the buttons
+    // right < 40
+    // up: 130 - 170
+    // down: 360 - 400
+    // left: 580 - 620
+    // select: 920 - 960
+    // no button pressed: 1000
+
+    // set a temporary command for the button that has been pushed
+    if (meas < 40) { // right button
+        debounceReading = COMMAND_RIGHT;
+    }
+    else if (meas > 130 && meas < 170) { // up button
+        debounceReading = COMMAND_UP;
+    }
+    else if (meas > 360 && meas < 400) { // down button
+        debounceReading = COMMAND_DOWN;
+    }
+    else if (meas > 580 && meas < 620) { // left button
+        debounceReading = COMMAND_LEFT;
+    }
+    else if (meas > 920 && meas < 960) { // select button
+        debounceReading = COMMAND_SELECT;
+    }
+    else {
+        debounceReading = COMMAND_NONE;
+    }
+
+    int milliseconds = t.read_ms();
+    int lastPushedTime = milliseconds - lastDebounceTime;
+
+    // a button has been pushed or released
+    if (debounceReading != debounceLastCommand) {
+        // reset the debouncing timer
+        lastDebounceTime = t.read_ms();
+    }
+
+    if (lastPushedTime > debounceDelay && debounceReading != debounceCommand) {
+        debounceCommand = debounceReading;
+        command = debounceCommand;
+    }
+
+    debounceLastCommand = debounceReading;
+
+    // reset the timer if keyboard is idle for a specific amount of time
+    if (debounceReading == COMMAND_NONE && lastPushedTime > 1200e3) { // 1200e3 = 20min
+        t.reset();
+    }
+}
+
+/*
+void printKeyboardCommandOnLCD()
+{
+    if (command != lastCommand)
+    {
+        if (command != COMMAND_NONE) {
+            lcd.cls();
+            lcd.locate(0, 0);
         }
-        else if (meas < 210) { 
+
+        if (command == COMMAND_RIGHT) {
+            lcd.printf("BUTTON: Right");
+        }
+        else if (command == COMMAND_UP) {
             lcd.printf("BUTTON: Up");
-            backlight = 1;          // Power ON backlight
-        } 
-        else if (meas < 460){ 
+        }
+        else if (command == COMMAND_DOWN) {
             lcd.printf("BUTTON: Down");
-            backlight = 0;          // Power OFF backlight
-        } 
-        else if (meas < 720){ 
-            lcd.printf("BUTTON: Left"); 
-        } 
-        else if (meas > 950){ 
+        }
+        else if (command == COMMAND_LEFT) {
+            lcd.printf("BUTTON: Left");
+        }
+        else if (command == COMMAND_SELECT) {
             lcd.printf("BUTTON: Select");
         }
-        pc.printf("BUTTON: %4d\n", meas);
-        
-        wait(0.1);
+    }
+}
+*/
+
+void resetKeyboardCommand()
+{
+    lastCommand = command;
+}
+
+void resetMenuOption()
+{
+    lastOption = currentOption;
+}
+
+void handleLed()
+{
+    // LED config has changed
+    if (config.ledChanged)
+    {
+        config.ledChanged = false;
+
+        if (config.ledLit) {
+            blueLed = config.ledValue; // the LED is off
+        } else {
+            blueLed = 0;
+        }
+    }
+}
+
+void clearLCDSecondRow()
+{
+    lcd.locate(0, 1);
+    lcd.printf("                ");
+    //lcd.printf("%*.0i", 16, 0);
+}
+
+void printLedStateConfig()
+{
+    lcd.locate(0, 1);
+    lcd.printf("< LED On:");
+    lcd.locate(10, 1);
+    lcd.printf(config.ledLit ? "Yes" : "No");
+    lcd.locate(14, 1);
+    lcd.printf(" >");
+}
+
+void printLedValueConfig()
+{
+    lcd.locate(0, 1);
+    lcd.printf("< LED Val:");
+    lcd.locate(10, 1);
+    lcd.printf("%.2f", config.ledValue);
+    lcd.locate(14, 1);
+    lcd.printf(" >");
+}
+
+// handle keyboard input
+void handleConfigMenu()
+{
+    // a new command has been triggered
+    if (command != lastCommand)
+    {
+        if (isInConfig)
+        {
+             // exit the config menu
+            if (command == COMMAND_SELECT)
+            {
+                printFirstScreen();
+                isInConfig = false;
+
+                // revert/reset everything to the first state
+                currentOption = MENU_NONE;
+                resetMenuOption();
+                command = COMMAND_NONE;
+                resetKeyboardCommand();
+            }
+            // scroll through menu options
+            else if (command == COMMAND_LEFT || command == COMMAND_RIGHT)
+            {
+                // search for current element position
+                int menuOptionsSize = sizeof(menuOptions) / sizeof(int);
+                int pos = 0;
+                while (pos < menuOptionsSize && currentOption != menuOptions[pos]) {
+                    pos++;
+                }
+
+                if (command == COMMAND_LEFT)
+                {
+                    if (pos == 0) {
+                        currentOption = menuOptions[menuOptionsSize - 1];
+                    } else {
+                        currentOption = menuOptions[--pos];
+                    }
+                }
+                else if (command == COMMAND_RIGHT)
+                {
+                    if (pos == (menuOptionsSize - 1)) {
+                        currentOption = menuOptions[0];
+                    } else {
+                        currentOption = menuOptions[++pos];
+                    }
+                }
+            }
+            // scroll through menu settings
+            else if (command == COMMAND_UP || command == COMMAND_DOWN)
+            {
+                // the LED state has changed
+                if (currentOption == MENU_LED_STATE) {
+                    config.ledLit = !config.ledLit;
+                    config.ledChanged = true;
+
+                    clearLCDSecondRow();
+                    printLedStateConfig();
+                }
+                // the LED value has changed
+                else if (currentOption == MENU_LED_VALUE) {
+                    bool valChanged = false;
+                    if (command == COMMAND_UP) {
+                        if (config.ledValue < 1.0f) {
+                            config.ledValue += 0.1;
+                            valChanged = true;
+                        }
+                    } else if (command == COMMAND_DOWN) {
+                        if (config.ledValue > 0.2) {
+                            config.ledValue -= 0.1;
+                            valChanged = true;
+                        }
+                    }
+
+                    if (valChanged) {
+                        config.ledChanged = true;
+    
+                        clearLCDSecondRow();
+                        printLedValueConfig();
+                    }
+                }
+            }
+        }
+        else {
+             // enter in config menu
+            if (command == COMMAND_SELECT)
+            {
+                lcd.cls();
+                lcd.locate(0, 0);
+                lcd.printf("MENU CONFIG");
+
+                isInConfig = true;
+                currentOption = MENU_LED_STATE;
+            }
+        }
+
+        // a new command has been triggered
+        // browse through options
+        if (currentOption != lastOption)
+        {
+            // clear second row
+            clearLCDSecondRow();
+
+            // LED state
+            if (currentOption == MENU_LED_STATE)
+            {
+                printLedStateConfig();
+            }
+            // LED value
+            else if (currentOption == MENU_LED_VALUE)
+            {
+                printLedValueConfig();
+            }
+        }
+    }
+}
+
+int main()
+{
+    initialize();
+
+    while(1)
+    {
+        // keyboard routines
+        readKeyboard();
+        //printKeyboardCommandOnLCD();
+
+        // config menu routines
+        handleConfigMenu();
+
+        // actions routines
+        handleLed();
+
+        // reset everything
+        resetKeyboardCommand();
+        resetMenuOption();
     }
 }
\ No newline at end of file