diff --git a/README.md b/README.md index d1902c2..f07c8ca 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,163 @@ -# Adruino_LCD_MENU README +# Arduino_LCD_MENU + +This library is to combine the functionality of the LCD(LiquidCrystal) and the use of a menu tree. +Very common functionality that. This is combined to speed up the startup time of creating menus on LCDs. + +### Getting Started + +Include the neccessary libraries (See Installing for more details). + + #include + #include + #include + #include + +Identify which pins you will be using for your LCD screen( see https://learn.adafruit.com/character-lcds/wiring-a-character-lcd for more details) + + #define LCD_D7 = 4; + #define LCD_D6 = 6; + #define LCD_D5 = 7; + #define LCD_D4 = 8; + #define LCD_E = 9; + #define LCD_RS = 10; + +Declare your global variables MenuLCD and MenuManager + + MenuLCD(RS, E, D4, D5, D6, D7, NumOfColumns, NumOfRows) + MenuManager(MenuLCD* pMenuLCD); + +Here is an example with the values defined. The use of the '&' symbol gives the menuController access to the lcdController. +This getting started and example expects the use of a 16x2 LCD display. + + MenuLCD lcdController(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7, 16, 2); + MenuManager menuController( &lcdController); + +Now it is time to setup your menu. This is where it is helpful to write out your tree before you begin. +For this example we will be using the following Tree. It is a simple tree that will print "M#-S#" if you select the Node where M# refers to the Main Node, and S# is for the subnode. + + M1Node + | + |----M1-S1Node (prints "M1-S1 Callback", delay 5s) + | + |----M1-S2Node (prints "M1-S2 Callback", delay 5s) + | + M2Node (prints "M2 Callback", delay 5s) + +In your 'void setup()' Code section add the following to initialize the LCD. + + lcdController.MenuLCDSetup(); + +In order for the Nodes to perform some task. It will need instructions on what to do. +We do this by setting up a callback function. It is the function that we want to call when the node is selected. + + void M1S1Callback( char* menuText, void *userData) + { + char *menuLines[2] = {"M1-S1 Callback", "" }; + lcdController.PrintMenu(menuLines, 2, 3);// PrintMenu( char ** MenuString, int number of Lines, SelectedLine) + delay(5000); + } + + void M1S2Callback( char* menuText, void *userData) + { + char *menuLines[2] = {"M1-S2 Callback", "" }; + lcdController.PrintMenu(menuLines, 2, 3);// "Hello" is the string to print, 0 is the Row + delay(5000); + } + + void M2Callback( char* menuText, void *userData) + { + char *menuLines[2] = {"M2 Callback", "" }; + lcdController.PrintMenu(menuLines, 2, 3); + delay(5000); + } + +Now that we have our callbacks, lets start creating the Menu options starting with the root node. Order matters with the library it uses a depth-first traversal order. + + // Define the objects + MenuEntry * rootMenuEntry = new MenuEntry("M1", NULL, NULL); + MenuEntry * M1S1MenuEntry = new MenuEntry("M1-S1", NULL, M1S1Callback); + MenuEntry * M1S2MenuEntry = new MenuEntry("M1-S2", NULL, M1S2Callback); + MenuEntry * M2MenuEntry = new MenuEntry("M2", NULL, M2Callback); + + + //Add the root node + menuController.addMenuRoot(rootMenuEntry); + menuController.addChild(M1S1MenuEntry); + menuController.addChild(M1S2MenuEntry); + menuController.addSibling(M2MenuEntry); + + +It is important to make sure that the menu is in the root starting location when you finish setting up. + + menuController.SelectRoot(); + +To draw the Menu + + menuController.DrawMenu(); + +After the 'setup' and once you are in the 'loop' folder. You will need to manage whether to go 'UP', 'DOWN', 'SELECT', or 'BACK'. +Here is an example of all 4 options. Note: in the example2.ino the actions are triggered by button presses. + + menuController.DoMenuAction( MENU_ACTION_UP); + menuController.DoMenuAction( MENU_ACTION_DOWN); + menuController.DoMenuAction( MENU_ACTION_SELECT); + menuController.DoMenuAction( MENU_ACTION_BACK); + +Whether these actions are tied to a button, or serial input, or something else, It is up to you. +In order to run the 'M1-S1Callback' run the following. + + menuController.DoMenuAction( MENU_ACTION_SELECT); + menuController.DoMenuAction( MENU_ACTION_SELECT); + +For full implementation of Hello Menu World see Example2.ino(todo link to example). + +In order to create Mutliple root level options here is how. + +//TODO Display the Multiple Root level tree +//TODO code example of multiple Root level tree + +### Installing + +Install the library like any other arduino zip library. + + Download the arduino library as a zip file (Arduino_LCD_Menu.zip) + +In the Arduino IDE goto + + Sketch -> Include Library -> Add .ZIP Library + +Find the Arduino_LCD_Menu.zip file and upload that. + +Then add the library by selecting in the list of libraries + + Sketch -> Include Library -> Arduino_LCD_Menu + +That's it the library has be added. Goto the Getting started section for more details on how to use the library. + +### Contributing + +Feel free to post contributions to this library. + +### Authors Original library: By David Andrews - May 6, 2012 -Modified by Tweep, February 2017 +Modified by @Tweep, February 2017 +Modified by @Ashitakalax, March 2017 -License: Modified BSD (See complete license at end) +*License*: Modified BSD (See complete license at end) -Purpose: To shorten the time to get an Adriuno project running using a menuing system. +*Purpose*: To shorten the time to get an Adriuno project running using a menuing system. Changes : + - Added additional example + - Added Syntax Highlighting - new constructor added which allows to enable / disable the execution of callback functions when the root menu has been selected. + + const bool doRootAction = false; MenuLCD g_menuLCD( LCDRS, LCDE, LCDD4, LCDD5, LCDD6, LCDD7, 16, 2); MenuManager g_menuManager( &g_menuLCD, doRootAction); diff --git a/examples/Arduino_LCD_Menu/Example2.ino b/examples/Arduino_LCD_Menu/Example2.ino new file mode 100644 index 0000000..064431f --- /dev/null +++ b/examples/Arduino_LCD_Menu/Example2.ino @@ -0,0 +1,164 @@ +/* + Arduino_LCD_Menu Example2 +Copyright Levi Balling(aka Ashitakalax) +Licensed under the follwing license: +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. +The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +// Using Bounce2 library for button control +#include + +// LCD PINS and Objects +#define LC_RS_PIN 23 +#define LC_EN_PIN 21 +#define LC_D7_PIN 41 +#define LC_D6_PIN 40 +#define LC_D5_PIN 39 +#define LC_D4_PIN 38 + +MenuLCD lcdController(LC_RS_PIN, LC_EN_PIN, LC_D4_PIN, LC_D5_PIN, LC_D6_PIN, LC_D7_PIN, 16, 2); +MenuManager menuController( &lcdController); + +// Example uses 4 buttons +// User Input Switches +#define BUTTON_UP_PIN 45 +#define BUTTON_DOWN_PIN 44 +#define BUTTON_BACK_PIN 43 +#define BUTTON_SELECT_PIN 42 +Bounce debounceUp = Bounce(); +Bounce debounceDown = Bounce(); +Bounce debounceBack = Bounce(); +Bounce debounceSelect = Bounce(); + +/** + * Sets up the LCD Controller, the Menu, and calls the Setup Buttons. + */ +void setup() { + // put your setup code here, to run once: + + lcdController.MenuLCDSetup(); + + // Define the Menu objects + MenuEntry * rootMenuEntry = new MenuEntry("M1", NULL, NULL); + MenuEntry * M1S1MenuEntry = new MenuEntry("M1-S1", NULL, M1S1Callback); + MenuEntry * M1S2MenuEntry = new MenuEntry("M1-S2", NULL, M1S2Callback); + MenuEntry * M2MenuEntry = new MenuEntry("M2", NULL, M2Callback); + + //Add the root node, then it's children + menuController.addMenuRoot(rootMenuEntry); + menuController.addChild(M1S1MenuEntry); + menuController.addChild(M1S2MenuEntry); + menuController.addSibling(M2MenuEntry); + menuController.SelectRoot(); + menuController.DrawMenu(); + + //Setup buttons + setupButtons(); +} + +/** + * Sets up 4 debounced buttons to handle the Menu Options + */ +void setupButtons() +{ + // Setup the Inputs and debouncers + pinMode(BUTTON_UP_PIN, INPUT_PULLUP); + debounceUp.attach(BUTTON_UP_PIN); + debounceUp.interval(5); + + // Setup Down Button + pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); + debounceDown.attach(BUTTON_DOWN_PIN); + debounceDown.interval(5); + + // Setup Back Button + pinMode(BUTTON_BACK_PIN, INPUT_PULLUP); + debounceBack.attach(BUTTON_BACK_PIN); + debounceBack.interval(5); + + // Setup Select Button + pinMode(BUTTON_SELECT_PIN, INPUT_PULLUP); + debounceSelect.attach(BUTTON_SELECT_PIN); + debounceSelect.interval(5); +} + +/** + * Main Loop function that just checks the Buttons repeatedly + */ +void loop() +{ + updateButtons(); +} + +/** + * The Callback for the Sub Node M1-S1 + */ +void M1S1Callback( char* menuText, void *userData) +{ + char *menuLines[2] = {"M1-S1 Callback", "" }; + lcdController.PrintMenu(menuLines, 2, 3);// PrintMenu( char ** MenuString, int number of Lines, SelectedLine) + delay(5000); +} + +/** + * The Callback for the Sub Node M1-S2 + */ +void M1S2Callback( char* menuText, void *userData) +{ + char *menuLines[2] = {"M1-S2 Callback", "" }; + lcdController.PrintMenu(menuLines, 2, 3);// "Hello" is the string to print, 0 is the Row + delay(5000); +} + +/** + * The callback for the sibiling node M2 + */ +void M2Callback( char* menuText, void *userData) +{ + char *menuLines[2] = {"M2 Callback", "" }; + lcdController.PrintMenu(menuLines, 2, 3); + delay(5000); +} + +/** + * Simple function to listen to the button presses to trigger the menu actions + */ +void updateButtons() +{ + debounceUp.update(); + debounceDown.update(); + debounceBack.update(); + debounceSelect.update(); + + if(debounceUp.fell()) + { + menuController.DoMenuAction(MENU_ACTION_UP); + } + else if(debounceDown.fell()) + { + menuController.DoMenuAction(MENU_ACTION_DOWN); + } + else if(debounceBack.fell()) + { + menuController.DoMenuAction(MENU_ACTION_BACK); + } + else if(debounceSelect.fell()) + { + menuController.DoMenuAction(MENU_ACTION_SELECT); + } +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..7115f2d --- /dev/null +++ b/keywords.txt @@ -0,0 +1,39 @@ +MenuLCD KEYWORD1 +MenuManager KEYWORD1 +MenuEntry KEYWORD1 +MenuIntHelper KEYWORD1 +addChild KEYWORD2 +addSibling KEYWORD2 +setPrevSibling KEYWORD2 +addActionCallback KEYWORD2 +getMenuText KEYWORD2 +setParent KEYWORD2 +getNextSibling KEYWORD2 +getPrevSibling KEYWORD2 +getChild KEYWORD2 +getParent KEYWORD2 +ExecuteCallback KEYWORD2 +isBackEntry KEYWORD2 +numIncrease KEYWORD2 +numDecrease KEYWORD2 +getInt KEYWORD2 +MenuLCDSetup KEYWORD2 +PrintMenu KEYWORD2 +PrintLineRight KEYWORD2 +PrintLine KEYWORD2 +getLines KEYWORD2 +getCharacters KEYWORD2 +ClearLCD KEYWORD2 +getLCD KEYWORD2 +WipeMenu KEYWORD2 +addMenuRoot KEYWORD2 +getMenuRoot KEYWORD2 +DrawMenu KEYWORD2 +DoMenuAction KEYWORD2 +MenuUp KEYWORD2 +MenuDown KEYWORD2 +MenuSelect KEYWORD2 +SelectRoot KEYWORD2 +MenuBack KEYWORD2 +DoIntInput KEYWORD2 +DrawInputRow KEYWORD2 \ No newline at end of file