Menu now works perfectly with the multi-directional button! I hope this is useful to someone in the future.
Here is a better schematic:
PaulS:
unsigned char button = analogRead(inputPin) >> 2;
Unsigned char? Why? Why not byte?
Ehh...good point. Thanks! Still learning...
PeterH:
I'm a bit perplexed by the number of state variables you are using in readButtons.Using buttonState and lastButtonState looks fine to hold the current detected state and previously detected state so you can detect changes. Using lastButtonPushed as a way to pass the change from readButtons() to navigateMenus() (and then clear it once it's been processed) is also OK. Personally I'd have preferred to have readButtons() return the key that was pressed (or 0 is nothing was pressed) rather than using a global variable, because this reduces the amount of global data and that is always a good thing, but that's mainly a matter of style. But then you also have buttonPushed and buttonPushCounter, and I have no idea what they're for. If you can eliminate them that would reduce the complexity by a useful amount.
Another good point. Got the code from the ButtonStateChange example. I was running out the door when I added it and didn't clean it up very well. Not sure how it would look to eliminate the lastButtonPushed. This is what I have now:
/*
IMPORTANT: to use the menubackend library by Alexander Brevig download it at http://www.arduino.cc/playground/uploads/Profiles/MenuBackend_1-4.zip and add the next code at line 195
void toRoot() {
setCurrent( &getRoot() );
}
*/
#include <MenuBackend.h> //MenuBackend library - copyright by Alexander Brevig
//#include <LiquidCrystal.h> //this library is included in the Arduino IDE
#define buttonPinLeft (1<<0)
#define buttonPinRight (1<<1)
#define buttonPinEsc (1<<2)
#define buttonPinEnter (1<<3)
int buttonState = 0; // current state of the button
int lastButtonState = 0; //last button state
int lastButtonPushed = 0;
int inputPin = 0;
// LiquidCrystal display with:
// rs on pin 7
// rw on ground
// enable on pin 6
// d4, d5, d6, d7 on pins 5, 4, 3, 2
//LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
//Menu variables
MenuBackend menu = MenuBackend(menuUsed,menuChanged);
//initialize menuitems
MenuItem menu1Item1 = MenuItem("Item1");
MenuItem menuItem1SubItem1 = MenuItem("Item1SubItem1");
MenuItem menuItem1SubItem2 = MenuItem("Item1SubItem2");
MenuItem menu1Item2 = MenuItem("Item2");
MenuItem menuItem2SubItem1 = MenuItem("Item2SubItem1");
MenuItem menuItem2SubItem2 = MenuItem("Item2SubItem2");
MenuItem menuItem3SubItem3 = MenuItem("Item2SubItem3");
MenuItem menu1Item3 = MenuItem("Item3");
void setup()
{
Serial.begin(9600);
//lcd.begin(16, 2);
//configure menu
menu.getRoot().add(menu1Item1);
menu1Item1.addRight(menu1Item2).addRight(menu1Item3);
menu1Item1.add(menuItem1SubItem1).addRight(menuItem1SubItem2);
menu1Item2.add(menuItem2SubItem1).addRight(menuItem2SubItem2).addRight(menuItem3SubItem3);
menu.toRoot();
//lcd.setCursor(0,0);
Serial.print("$GO 1 1\r\n");
//lcd.print("Hello World!");
Serial.print("$PRINT Hello World! \r\n");
} // setup()...
void loop()
{
readButtons(); //I splitted button reading and navigation in two procedures because
navigateMenus(); //in some situations I want to use the button for other purpose (eg. to change some settings)
} //loop()...
void menuChanged(MenuChangeEvent changed){
MenuItem newMenuItem=changed.to; //get the destination menu
//lcd.setCursor(0,1); //set the start position for lcd printing to the second row
if(newMenuItem.getName()==menu.getRoot()){
//lcd.print("Main Menu ");
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Main Menu \r\n");
}else if(newMenuItem.getName()=="Item1"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item1 \r\n");
//lcd.print("Item1 ");
}else if(newMenuItem.getName()=="Item1SubItem1"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item1SubItem1 \r\n");
//lcd.print("Item1SubItem1");
}else if(newMenuItem.getName()=="Item1SubItem2"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item1SubItem2 \r\n");
//lcd.print("Item1SubItem2 ");
}else if(newMenuItem.getName()=="Item2"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item2 \r\n");
//lcd.print("Item2 ");
}else if(newMenuItem.getName()=="Item2SubItem1"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item2SubItem1 \r\n");
//lcd.print("Item2SubItem1 ");
}else if(newMenuItem.getName()=="Item2SubItem2"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item2SubItem2 \r\n");
//lcd.print("Item2SubItem2 ");
}else if(newMenuItem.getName()=="Item2SubItem3"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item2SubItem3 \r\n");
//lcd.print("Item2SubItem3 ");
}else if(newMenuItem.getName()=="Item3"){
Serial.print("$CLEAR 2 1\r\n");
Serial.print("$GO 2 1\r\n");
Serial.print("$PRINT Item3 \r\n");
//lcd.print("Item3 ");
}
}
void menuUsed(MenuUseEvent used){
//do something useful here
}
void readButtons(){ //read buttons status
byte button = analogRead(inputPin) >> 2;
if (button == 0){
buttonState=0;
}
if (button > 20 && button < 60){
buttonState=buttonPinLeft;
}
else if (button > 60 && button < 100){
buttonState=buttonPinEnter;
}
else if (button > 140 && button < 160){
buttonState=buttonPinEsc;
}
else if (button > 160 && button < 200){
buttonState=buttonPinRight;
}
else {
buttonState=0;
}
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
if (buttonState != 0 ) {
lastButtonPushed = buttonState;
}
else {
lastButtonPushed = 0;
}
}
// save the current state as the last state for next time through the loop
lastButtonState = buttonState;
}
void navigateMenus() {
MenuItem currentMenu=menu.getCurrent();
switch (lastButtonPushed){
case buttonPinEnter:
if(!(currentMenu.moveDown())){ //if the current menu has a child and has been pressed enter then menu navigate to item below
menu.use();
}else{ //otherwise, if menu has no child and has been pressed enter the current menu is used
menu.moveDown();
}
break;
case buttonPinEsc:
menu.toRoot(); //back to main
break;
case buttonPinRight:
menu.moveRight();
break;
case buttonPinLeft:
menu.moveLeft();
break;
}
lastButtonPushed=0; //reset the lastButtonPushed variable
}