Go Down

Topic: MENWIZ: yet another character lcd menu wizard library (Read 83531 times) previous topic - next topic

Silverdog63

First of all, thanks for the help and ... Happy new year !
In my humble opinion the 5 option button (analog) option will be great, because it would allow all the users of the lcd shield (which is very common) to benefit of the Menwiz. The 5 buttons menu control is widely used (I have it on my Nikon camera, on the onkyo AVR ampli ecc.) you move "up" and "down" on the menus/options you enter in the sub menus with the "right" button or with "ok" (select) you choose the option by pressing "ok" (select) and the left button is for "exit" (go back).
the 3 button menus the visual back solution.

Now for my particular case .... It Works !! (well quite works ... -:) )
two of the button are working  and two are nor, in any case the menu is working so I just have to trick around the values of the buttons

Code: [Select]

  /*
  Analog values representing the pushbutton value are depending on the resitor value used.
   Test the values first with the serial.monitor
   */
  buttonValue = analogRead(buttonPin); //analog value to simulate the pushed buttons

  if(buttonValue >= 700)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  }
  else  if(buttonValue >= 470 & buttonValue <= 600)
  {
    buttonPressed = 4;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 300 & buttonValue <=420)
  {   
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 100 & buttonValue <=200)
  {   
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 10 & buttonValue <=50)
  {   
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
  }
}

Up is working corectly and down is working but it's the left button which should be "esc".
Code: [Select]

switch (buttonPressed)
    {
    case 1: // Up
      return MW_BTU;
      break;
    case 2: // Confirm
      return MW_BTC;
      break;
    case 3: // Down
      return MW_BTD;
      break;   
    case 4: // Escape
      return MW_BTE;
      break;
    }
  }



the working test line is:
Code: [Select]

int adc_key_val[5] ={30, 150, 360, 535, 760 };

so in some ways I'll find the solution.

.... Grazie Brunialti, for the particular attention to my stupid problems, I apreciate that and I will do my best to understand and follow your advices.
As soon I get the solution to the buttons problem I'll post it. I think can help those are starting like me.
ciao

Khalid

You can check the values of button presses on Serial Monitor. Just add
Code: [Select]
Serial.println(buttonValue ); as shown in the following code of yours:
Code: [Select]
  /*
  Analog values representing the pushbutton value are depending on the resitor value used.
   Test the values first with the serial.monitor
   */
  buttonValue = analogRead(buttonPin); //analog value to simulate the pushed buttons
Serial.println(buttonValue );
  if(buttonValue >= 700)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  }
  else  if(buttonValue >= 470 & buttonValue <= 600)
  {
    buttonPressed = 4;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 300 & buttonValue <=420)
  {   
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 100 & buttonValue <=200)
  {   
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 10 & buttonValue <=50)
  {   
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
  }
}
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

Silverdog63

Kalid, thank you a great help !! ( and exacly what a "dummy" like me need ! explanation and example ! thanks !! )


This is my solution for the Lcd Keypad Shield with the anologic buttons !
I think something like a delay has to be put somewhere because sometimes I have to push the button twice ... let give me a bit more time to fix it :-)  (or help :-) )
Code: [Select]

/*
  Analog values representing the pushbutton value are depending on the resitor value used.
   Test the values first with the serial.monitor
   */
  buttonValue = analogRead(buttonPin); //analog value to simulate the pushed buttons
  Serial.println(buttonValue );
 
  if(buttonValue >= 850)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  }
  else  if(buttonValue >= 380 & buttonValue <= 450)
  {
    buttonPressed = 4;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 200 & buttonValue <=300)
  {   
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 0 & buttonValue <=50)
  {   
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 80 & buttonValue <=150)
  {   
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
  }
}

int noButtonPressed()
{
  return MW_BTNULL;
}


As soon I do my homework ...
Quote

(from the Master Brunialti)
at a first glance I see some point to check:
- the following line is not necessary: MW_navbtn=4;
- when you use  addusernav the declared callback should be in charge with button checking and code returning. The call to readButtons() should be therefore inside the callback funcion , not in the loop. the code works the same, but is more polite
- you defined the menu framework, but after each  creation of menu nodes of type MW_VAR you need to create the variable with addVar in order to let the menu working.

I will post the complete code
Thanks

Khalid

Ok..You can also add in if-else statements the button name for example:
Code: [Select]
Serial.println("DOWN");..This will ensure you the button press behavior...
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

Silverdog63

..... :-) I'm starting having fun !!
Code: [Select]

/*
  Analog values representing the pushbutton value are depending on the resitor value used.
   Test the values first with the serial.monitor
   */
  buttonValue = analogRead(buttonPin); //analog value to simulate the pushed buttons
  Serial.println(buttonValue );
 
 
  if(buttonValue >= 850)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  }
  else  if(buttonValue >= 380 & buttonValue <= 450)
  {
    buttonPressed = 4;
    buttonAct = 1; // set the menu flag1
    Serial.println("Escape");
  }
  else if(buttonValue >= 200 & buttonValue <=300)
  {   
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
    Serial.println("DOWN");
  }
  else if(buttonValue >= 0 & buttonValue <=50)
  {   
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
    Serial.println("Confirm");
  }
  else if(buttonValue >= 80 & buttonValue <=150)
  {   
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
    Serial.println("Up");
  }
}


Thanks Khalid

brunialti

#290
Jan 02, 2013, 02:47 pm Last Edit: Jan 02, 2013, 04:42 pm by brunialti Reason: 1
Hi.
for all people interested in "odd" button models (that is 3 or 5 button models) I give you a *very simple* patch to implement it now. The next version will consolidate the change.

Inside the library is implemented a "logical level" where are defined all actions performed  after a button push.
Those functions are private members of class menwiz,  so it is necessary to make just one  change to the MENWIZ.h file, moving  the  definition of actBTE() from private to public. That is all.

In your sketch you can implement a menu entry acting exactly as the escape button as following (example):

Code: [Select]
     s2=menu.addMenu(MW_VAR,s1,F("Back"));     //add a terminal node (that is "variable");
         s2->addVar(MW_ACTION,&bte);                    //create a variable of type "action"
         s2->setBehaviour(MW_ACTION_CONFIRM,false);         // you don't need action confirmation to emulate Escape button!!!


EDIT:
Code: [Select]

void bte(){
menu.actBTE();
}





Silverdog63

Ciao Roberto,
This is what I tried, but I got "57: error: 'bte' was not declared in this scope". I don't know what I did wrong, it was just a test I don't need it at the moment. The Menu frame it's working, I just have to think and put my variable in. (P.S. my project is to control with a stepper the height of my Saw, Planner and shaper ... http://www.bricosergio.it/combinate/Sicar/furore300i%20NEW.htm ... )

Code: [Select]

//create the menu tree
  r=menu.addMenu(MW_ROOT,NULL,F("MAIN MENU"));                      //create a root menu at first (required)

  //--------------- 
  s1=menu.addMenu(MW_SUBMENU,r,F("SAW"));                        //add a submenu node 1 to the root menu
    s2=menu.addMenu(MW_VAR,s1,F("ABS Height"));                         //add a terminal node in the menu tree (that is "variable");
      s2=menu.addMenu(MW_VAR,s1,F("REL Move"));                         //add a terminal node in the menu tree (that is "variable");
        s2=menu.addMenu(MW_VAR,s1,F("Zero"));                         //add a terminal node in the menu tree (that is "variable");
          s2=menu.addMenu(MW_VAR,s1,F("Back"));     //add a terminal node (that is "variable");
            s2->addVar(MW_ACTION,&bte);                    //create a variable of type "action"
            s2->setBehaviour(MW_ACTION_CONFIRM,false);         // you don't need action confirmation to emulate Escape button


And in the MENWIZ.h file:
Code: [Select]

class menwiz{
public:
           menwiz();
  void     begin(void *,int, int);
  void     addSplash(char *,int);
  void     addUsrScreen(void (*f)(), unsigned long);
  void     addUsrNav(int (*f)(), int);
  void     setBehaviour(MW_FLAGS,boolean);
  _menu*   addMenu(int, _menu *, MW_LABEL);
  void     draw();
  void     drawUsrScreen(char *);       //draw user screen(s)
  int      getErrorMessage(boolean); //if arg=true, err message is printed to the default Serial terminal, otherwise the function returns error code only
  int      freeRam();
  void     actBTE();


Silverdog63

Ciao,
This is a "perfecly" working ( at least I hope ) start base of MENWIZ to be used with the Arduino Lcd Keypad Shield ( http://www.robotshop.com/cytron-lcd-keypad-shield-arduino.html )

Code: [Select]

// +++++++ Libaries included
#include <Wire.h>
#include <LiquidCrystal.h>
//INSERT ALL THE LIBARIES AFTER INCLUDING WIRE LIB (MENWIZ request)
#include <LiquidCrystal_I2C.h>
#include <buttons.h>
#include <MENWIZ.h>
#include <EEPROM.h>

// Create global object for menu and lcd
menwiz menu;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
/*LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Addr, En, Rw, Rs, d4, d5, d6, d7, backlightpin, polarity 4 x 20 LCD
*/
boolean wr=0; // Instantiate global variables to bind to menu

const int buttonPin = A0;             // 4 button switch circuit input connected to analog pin 0
const int led13Pin = 13;              // the number of the LED output pin

boolean buttonBlock = 0;
boolean buttonAct = 0; // flag 1
boolean stopMenu = 0; // flag 2
byte buttonPressed = 0;  // which button was pressed
byte lastButtonPressed = 0; // prev button pressed
int buttonValue = 0;  // read value from analog port for the 4 navigation pushbuttons
long menuOffTime = 0;  //used for timer

extern byte MW_navbtn;  //needed to run the software key navigation in Menwiz



void setup()
{
  Serial.begin(9600);                       // Output to serial writing

  digitalWrite((54), HIGH);  // enable the 20k internal pullup for MEGA board for analog port A0
  // digitalWrite((A0), HIGH);  // enable the 20k internal pullup for UNO based board for analog port A0

  //++++++++++++++++++++Menu and LCD 
  char b[84];
  _menu *r,*s1,*s2;

  // initialize the menu object ( 4 x rows x 20 colums LCD)
  menu.begin(&lcd,16,2); //initialize the menwiz menu object passing the lcd object and the colums and rows params
  menu.addUsrNav(navMenu,4);
  MW_navbtn=4;  // force 4 or 6 buttons mode for menu navigation -> MW_navbtn=4; or MW_navbtn=6;

  //create the menu tree
  r=menu.addMenu(MW_ROOT,NULL,F("MAIN MENU"));                      //create a root menu at first (required)

  //--------------- 
  s1=menu.addMenu(MW_SUBMENU,r,F("SAW"));                        //add a submenu node 1 to the root menu (control the heigh of my Saw)
  s2=menu.addMenu(MW_VAR,s1,F("ABS Height"));                         //add a terminal node in the menu tree (that is "variable"); (should move at a certain mm height)
  s2=menu.addMenu(MW_VAR,s1,F("REL Move"));                         //add a terminal node in the menu tree (that is "variable"); (should move of a certain mm the height)
  s2=menu.addMenu(MW_VAR,s1,F("Zero"));                         //add a terminal node in the menu tree (that is "variable");

  //---------------
  s1=menu.addMenu(MW_SUBMENU,r,F("PLANNER"));                    //add a submenu node 2 to the root menu (control the heigh of my Planner)
  s2=menu.addMenu(MW_VAR,s1,F("ABS Height"));                         //add a terminal node in the menu tree (that is "variable"); (should move at a certain mm height)
  s2=menu.addMenu(MW_VAR,s1,F("REL Move"));                         //add a terminal node in the menu tree (that is "variable"); (should move of a certain mm the height)
  s2=menu.addMenu(MW_VAR,s1,F("Zero"));                         //add a terminal node in the menu tree (that is "variable"); (should set the zero)

  //---------------
  s1=menu.addMenu(MW_SUBMENU,r,F("SHAPER"));                    //add a submenu node 3 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("ABS Height"));                         //add a terminal node in the menu tree (that is "variable"); (should move at a certain mm height)
  s2=menu.addMenu(MW_VAR,s1,F("REL Move"));                     //add a terminal node in the menu tree (that is "variable"); (should move of a certain mm the height)
  s2=menu.addMenu(MW_VAR,s1,F("Zero"));                     //add a terminal node in the menu tree (that is "variable"); (should set the zero)

  /*
  //++++++ Splash screen +++++++
 
  sprintf(menu.sbuf,"TEST minimum menu\nwith 4 or 6\nanalog push buttons\n",1);
  menu.addSplash((char *) menu.sbuf, 1000);

  //++++++ Userscreen ++++++++++
  // create an user define screen callback to activate after X secs since last button push
  menu.addUsrScreen(msc,3000);
  */
  pinMode(led13Pin, OUTPUT);                // initialize the led as a output control pin
}

void loop()   
{
// NAVIGATION MANAGEMENT & DRAWING ON LCD. NOT BLOCKING has to be the first in the void loop
  menu.draw();
/*
  put your regular code here
   */
  readButtons();
}

//  ++++++ functions +++++++

void readButtons()

// ++++ Control 4 buttons ++++
{
  lastButtonPressed = buttonPressed;

  /*
  Analog values representing the pushbutton value are depending on the resitor value used.
   Test the values first with the serial.monitor
   */
  buttonValue = analogRead(buttonPin); //analog value to simulate the pushed buttons
 
  if(buttonValue >= 850)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  }
  else  if(buttonValue >= 380 & buttonValue <= 450)
  {
    buttonPressed = 4;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 200 & buttonValue <=300)
  {   
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 0 & buttonValue <=50)
  {   
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 80 & buttonValue <=150)
  {   
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
  }
}

int noButtonPressed()
{
  return MW_BTNULL;
}

int navMenu() // called from menu.draw
{
  /*
   As soon as a button is pushed the first time flag 1 is set to HIGH and if the buttonnumber is not 0 then a timer is started.
   The menu action then should only be performed once.
   After 2000 msecs the flag will be set to LOW and a new buttonpush can be processed.
   Menu action is blocked for 2000 msec even if the same button is being kept pressed for 2000 msecs by flag2.
   */

  long menublockTime = millis();

  if (buttonAct == 1 && buttonPressed != 0 && stopMenu == 0)  // we have a state were we process a menu navigation step once and block it for 2 secs
  {
    digitalWrite(led13Pin,HIGH);  // set timer led ON
    menuOffTime = menublockTime  + 2000; //start the timer. You can change this blocking time to your convenience but do not make it lower aa 200 msecs
    stopMenu = 1;

    switch (buttonPressed)
    {
    case 1: // Up
      return MW_BTU;
      break;
    case 2: // Confirm
      return MW_BTC;
      break;
    case 3: // Down
      return MW_BTD;
      break;   
    case 4: // Escape
      return MW_BTE;
      break;
    }
  }

  if (menuOffTime != 0  &&  menublockTime  > menuOffTime)  //  Reset of the timer so a new menu action can be processed
  {
    buttonAct = 0; // resets the flag 1
    buttonPressed = 0;
    menuOffTime = 0;  // resets timer to zero
    stopMenu = 0;
    digitalWrite(led13Pin,LOW);  // set timer led OFF
  }
}
/*
// user defined default screen.
void msc()
{
  sprintf(menu.sbuf,"User screen\nUptime (s): %ld\nFree mem  : %d\n\n",millis()/1000,(int)menu.freeRam());
  menu.drawUsrScreen(menu.sbuf);
}*/


P.S.
/*
   As soon as a button is pushed the first time flag 1 is set to HIGH and if the buttonnumber is not 0 then a timer is started.
   The menu action then should only be performed once.
   After 2000 msecs the flag will be set to LOW and a new buttonpush can be processed.
   Menu action is blocked for 2000 msec even if the same button is being kept pressed for 2000 msecs by flag2.
   */
This is why sometimes I had to push twice a button to operate .... didn't wait enough !  :smiley-red:

brunialti

#293
Jan 02, 2013, 04:40 pm Last Edit: Jan 02, 2013, 04:44 pm by brunialti Reason: 1
You've got the 57 error because I' forgot to insert the bte function of course :-)
Code: [Select]

void bte(){
menu.actBTE();
}


sorry...

Silverdog63

Roberto, it's me who apology ... if I was just a bit smarter, I could be able to understand what was missing.
Thank you very much for your work.
Sergio

Khalid

Silverdog63, so you own Mechmate. I also visit Mechmate forum and my login is Khalid;)
Regards
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

Thomas_berg_

#296
Jan 03, 2013, 02:02 am Last Edit: Jan 03, 2013, 02:24 am by Thomas_berg_ Reason: 1
is there a comlete Terry thermostat_meny.ino whitout the problems from post 194 i cant seem to get that one compiled  .. i have the 6button test_all_var_type runing very nice inded but want to look try build on terrys menu i gues.

im a total newbie 8) as you probably understand sins i cant fix the probs but i cant figure out the changes to get it to compile i run ide 1.0.3 * THERMOSTAT_MENU.ino (13.62 KB  from reply 194


best regards.

Khalid


is there a comlete Terry thermostat_meny.ino whitout the problems from post 194 i cant seem to get that one compiled  ..

Tell us the compilation errors...
Simply...You can't afford me..

Author Of:
http://my-woodcarving.blogspot.com/
http://www.free3dscans.blogspot.com/
http://my-diysolarwind.blogspot.com/

Oops..some one gave me Karma...:)

Thomas_berg_

#298
Jan 04, 2013, 04:13 pm Last Edit: Jan 04, 2013, 04:18 pm by Thomas_berg_ Reason: 1
okey i think im gonna hold my horses with that .ino becouse it seems terry has got later one , if i get probs, starting or compile that one il get back and i probobly will when i start modding it. :%


the one from reply 194

menu.begin(&lcd,16,2);
menu.addUsrNav(navMenu,);  <----this one whas obvius    as allso with the savevar lines..
MW_navbtn=4;

THERMOSTAT_MENU.ino: In function 'void loop()':
THERMOSTAT_MENU:148: error: 'tempF' was not declared in this scope
THERMOSTAT_MENU.ino: In function 'void msc()':
THERMOSTAT_MENU:303: error: 'tempF' was not declared in this scope
THERMOSTAT_MENU:328: error: a function-definition is not allowed here before '{' token
THERMOSTAT_MENU:333: error: a function-definition is not allowed here before '{' token

but i think i will get new .ino frof terry so i will wait for that one insted of trying to fix the one from reply 194

Silverdog63

Just a guess .... as I am an absolute beginner ..... it seems a library problem ... do you have all the necessary library included ?

Go Up