Pages: 1 ... 20 21 [22] 23 24 ... 32   Go Down
Author Topic: MENWIZ: yet another character lcd menu wizard library  (Read 59658 times)
0 Members and 1 Guest are viewing this topic.
rome
Offline Offline
Sr. Member
****
Karma: 15
Posts: 474
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@khalid
the difference should be less than 1k. probably around 4-500bytes. btw, did you commented the button support (As you use your own analog button management). That should save some space.
Frankly i would'nt work on an "old version" to fork a new branch...

@stretched59
the following code (from menwiz.h) does compile on my ide and allows you to call actBTE directly from your sketch. this changes will be in the next version.
Code:
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();

#ifdef EEPROM_SUPPORT
  void     writeEeprom();
  void     readEeprom();
#endif

#ifdef BUTTON_SUPPORT
  _nav*    btx;
  void     navButtons(int,int,int,int,int,int);
  void     navButtons(int,int,int,int);
  int      scanNavButtons();
#endif

  MW_FLAGS flags;
  MW_LCD*  lcd;
  char*    sbuf;                        //lcd screen buffer (+ 1 for each line)
  _cback   usrScreen;         //callback
  _cback   usrNav;    
  byte     idx_m;
  _menu    m[MAX_MENU];
  _menu*   cur_menu;
  _menu*   root;
  void     actBTE();

private:
  byte     row;
  byte     col;
  byte     cur_mode;
  int   last_button;                 //last pushed button code
  unsigned long tm_push;                //last pushed button time
  unsigned long tm_start;       //start time (set when begin method is invocated)
  unsigned long tm_splash;       //splash screen duration  
  unsigned long tm_usrScreen;   //lap time before usrscreen  
  void     apply2vars(void (*f)(_menu *));
  int      actNavButtons(int);
  void     drawMenu(_menu *);
  void     drawVar(_menu *);
  void     drawList(_menu *, int);
  void     actBTU();
  void     actBTD();
  void     actBTL();
  void     actBTR();
  void     actBTC();
protected:
};

« Last Edit: January 08, 2013, 03:18:28 pm by brunialti » Logged

Roma
Offline Offline
Jr. Member
**
Karma: 0
Posts: 76
Mechmate #70
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ciao,
I made some progress on the Menu, and it's working very well with the Lcd Keypad shield ....  this is the code for those with the same LCD Keypad ....
Code:
// +++++++ Libaries included
#include <Wire.h>
#include <LiquidCrystal.h>
//INSERT ALL THE LIBARIES AFTER INCLUDING WIRE LIB (MENWIZ request)
//#include <LiquidCrystal_I2C.h>               //eliminato, non più necessario
#include <buttons.h>
#include <MENWIZ.h>
#include <EEPROM.h>
#include <Stepper.h>

// Create global object for menu and lcd
menwiz menu;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution for your motor
Stepper myStepper(stepsPerRevolution, 0,1,2,3);   // initialize the stepper library on pins 0 through 3:

/*                                                eliminato, non più necessario
//Addr, En, Rw, Rs, d4, d5, d6, d7, backlightpin, polarity 4 x 20 LCD
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
*/

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
int stepCount = 0;                    // number of steps the motor has taken

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

int list,sp=0;                       // sp variable has 0 as default value (ABS height)

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"); (move at a certain mm height)
     s2->addVar(MW_AUTO_INT,&sp,0,100,1);                   //int type, fd binded variable, rage 0-100, step 1
  s2=menu.addMenu(MW_VAR,s1,F("REL Move"));                     //add a terminal node in the menu tree (that is "variable"); (move of a certain mm the height)
     s2->addVar(MW_AUTO_INT,&sp,0,100,1);                   //int type, fd binded variable, rage -100 +100, step 1
  s2=menu.addMenu(MW_VAR,s1,F("Zero"));                         //add a terminal node in the menu tree (that is "variable");  (set the zero)
      s2->addVar(MW_LIST,&list);
      s2->addItem(MW_LIST, F("Option1"));
      s2->addItem(MW_LIST, F("Option2"));
      s2->addItem(MW_LIST, F("Option3"));
  s2=menu.addMenu(MW_VAR,s1,F("Setup"));                        //add a terminal node in the menu tree (that is "variable");  (set the parameters)

  //---------------
  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->addVar(MW_AUTO_INT,&sp,0,100,1);                   //int type, fd binded variable, rage 0-100, step 1
  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->addVar(MW_AUTO_INT,&sp,-100,100,1);                   //int type, fd binded variable, rage 0-100, step 1
  s2=menu.addMenu(MW_VAR,s1,F("Zero"));                         //add a terminal node in the menu tree (that is "variable"); (should set the zero)
  s2=menu.addMenu(MW_VAR,s1,F("Setup"));                        //add a terminal node in the menu tree (that is "variable");  (set the parameters)
 
  //---------------
  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)
  s2=menu.addMenu(MW_VAR,s1,F("Setup"));                        //add a terminal node in the menu tree (that is "variable");  (set the parameters)
 
  /*
  //++++++ 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
*/
//  ++++++ 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  + 400; //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);
}*/

The stepper part is still to be implemented and also the menu code, but it's a "good" start (well there are maybe some errors but it works)
Logged

Roma
Offline Offline
Jr. Member
**
Karma: 0
Posts: 76
Mechmate #70
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

... And now a little question ...
This shows on the LCD a graphic format like that:
0 [10] 100
Code:
     s2->addVar(MW_AUTO_INT,&sp,0,100,1);                   //int type, fd binded variable, rage 0-100, step 1
Is it possible to change that format ?
I would like to display something like:
      10 mm     without the limit 0 - 100.
thanks
Logged

rome
Offline Offline
Sr. Member
****
Karma: 15
Posts: 474
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

currently it is not possible. But is quite easy to add in next versions an option to avoid limits. It is not planned to add text label on the same variable value row.
Logged

Roma
Offline Offline
Jr. Member
**
Karma: 0
Posts: 76
Mechmate #70
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Roberto, just to know if it was possible ... so many things I don't know.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Due to my complete ignorance it took me a while to figure this 3 or 5 button thing out completely. But that is part of the learning process is trying to figure out where my mistakes are.

I have it compiled but not tested. Program is at 30.7k and I have to get my double PID data converted to float for menwiz.h and then converted back to float for the PID_V1.h.

One question I have: does the new "BACK" menu option need to be in each terminal node?

OK, make it 2 questions: Can it be a menu.addItem instead of menu.addMenu? I'll find out in testing for sure.

Code:
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!!!
Logged

rome
Offline Offline
Sr. Member
****
Karma: 15
Posts: 474
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

BACK: yes. as far as you do not want use a button for escape, BACK action should be the last option for each submenu. I can work on  Menwiz in order to implemnet an "immediate" mode, that is any change is immediately consolidated, with  CONFIRM button the only way to go back. But the code changes are  not so easy ...

Unfortunately I can associate an action only to a menu node, not to a list item ... that is memory consuming, I know...

The good new: I found many serial debug tracing statements. That is consuming quite a lot of memory. Deleted. Some minor changes  to the code:  180 code lines affected just to spare few bytes ....It' a dirty work, but someone has to do it ....  :-)
« Last Edit: January 10, 2013, 04:41:40 am by brunialti » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'll have to get back to this. I melted my new I2C display due to a wiring mistake. Another learning opportunity.
Logged

UK
Offline Offline
God Member
*****
Karma: 17
Posts: 568
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The use of custom button navigation using addUsrNav is giving me a bit of a headache. I can't see why it doesn't work.

I'm using MENWIZ Version 1.2.0 on IDE 1.0.1 with a breadboarded 328P and Arduino Uno selected as the Board.

What I am doing is basing all my input on a 4x4 Keypad, theKeypad and Keypad_I2C libraries. When I use my own buttons I just emulate a particular position on the keypad by connecting across the appropriate row/col; i.e I have 3 buttons on my device that emaulate the keys 4, 6 and #. Thus the Keypad library takes care of all my edge triggering and debouncing for me and I get up to 16 buttons sharing teh I2C lines via a PCF8574 expander.

For this menu I am choosing 2-UP, 4-LEFT, 6-RIGHT, 8-DOWN, *-ESCAPE, #-CONFIRM, so my custom function looks for these particular keypresses and returns the approrpiate MW_BTU, MW_BTL, MW_BTR, MW_BTD, MW_BTE and MW_BTC. It returns MW_BTNULL if no key is pressed when scanned.

I removed all the defines for the buttons in my sketch:-

Code:
// DEFINE ARDUINO PINS FOR THE MENU NAVIGATION BUTTONS
//#define UP_BOTTON_PIN       16
//#define DOWN_BOTTON_PIN     17
//#define LEFT_BOTTON_PIN     18
//#define RIGHT_BOTTON_PIN    19
//#define CONFIRM_BOTTON_PIN  20
//#define ESCAPE_BOTTON_PIN   21

I commented out the navButtons declaration and added a line for addUsrNav

Code:
   //menu.navButtons(UP_BOTTON_PIN,DOWN_BOTTON_PIN,LEFT_BOTTON_PIN,RIGHT_BOTTON_PIN,ESCAPE_BOTTON_PIN,CONFIRM_BOTTON_PIN);
    menu.addUsrNav(menuKeys,6);

I created my new function to read the keypad and just check for the keys we are using for menu items

Code:
int menuKeys()
{
  char keyPressed = keypad1.getKey();
  
  if (keyPressed != NO_KEY)
  {
    if (keyPressed == '2')
    {
      return MW_BTU;
    }
    else if (keyPressed == '8')
    {
      return MW_BTD;
    }
    else if (keyPressed == '4')
    {
      return MW_BTL;
    }
    else if (keyPressed == '6')
    {
      return MW_BTR;
    }
    else if (keyPressed == '*')
    {
      return MW_BTE;
    }
    else if (keyPressed == '#')
    {
      return MW_BTC;
    }
    else
    {
    return MW_BTNULL;
    }
  }

I also comment out the BUTTON_SUPPORT define in MENWIZ.h

Code:
#define EEPROM_SUPPORT     //uncomment if you want to use the readEeprom and writeEeprom methods!
//#define BUTTON_SUPPORT     //uncomment if you want to use the readEeprom and writeEeprom methods!!

(Incidentally, note the incorrect comment, I found the reference to this define and was looking for it up and down the code, but scanning comments too made it look like this section was just for EEPROM)

From what I've seen in previous posts, this should now work and let me navgate the menu structure with the keypad. I can call the function from loop() and Serial.print the returned values to Serial Monitor and I get the values 2,3,4,5,6,7 returned for U,D,L,R,E,C so the function is working fine, it just seems that MENWIZ isn't calling it.

Full sketch code below

Code:
//The full code is in library example file Quick_tour.ino
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <buttons.h>
#include <MENWIZ.h>
#include <EEPROM.h>
#include <Keypad_I2C.h>
#include <Keypad.h>

#define keypad1_addr 0x22
#define lcd1_addr 0x27

// DEFINE ARDUINO PINS FOR THE MENU NAVIGATION BUTTONS
//#define UP_BOTTON_PIN       16
//#define DOWN_BOTTON_PIN     17
//#define LEFT_BOTTON_PIN     18
//#define RIGHT_BOTTON_PIN    19
//#define CONFIRM_BOTTON_PIN  20
//#define ESCAPE_BOTTON_PIN   21

int GAMETIME=30, POINTPERIOD=10, POINTSPERPERIODRED=5, POINTSPERPERIODBLUE=5;
int RESETSCOREPERIOD=0, COUNTDOWNTIMER=3, SPLASHSCREEN=1, WIRELESS = 1, DEBUG = 1;
int LEDBLINK =1, LEDBLINKON = 500, LEDBLINKOFF = 500, CURSORBLINKRATE = 500, BACKLIGHTDELAY = 1;
int list, sp;

// Keypad setup
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {3, 2, 1, 0}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {7, 6, 5, 4}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad_I2C keypad1( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS, keypad1_addr);

menwiz menu;
// create lcd obj using LiquidCrystal lib
//LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
LiquidCrystal_I2C lcd(lcd1_addr, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE); // addr, EN, RW, RS, D4, D5, D6, D7, Backlight, POLARITY

void setup(){
  _menu *r,*s1,*s2,*s3;
  
  keypad1.begin();

  Serial.begin(115200);    
  menu.begin(&lcd,16,2); //declare lcd object and screen size to menwiz lib
  
  menu.setBehaviour(MW_MENU_INDEX,false); // turn off the menu index - 1/3 etc

  r=menu.addMenu(MW_ROOT,NULL,F("MAIN MENU"));
 
    s1=menu.addMenu(MW_SUBMENU,r, F("General"));
      s2=menu.addMenu(MW_SUBMENU,s1, F("Game Setup"));
        s3=menu.addMenu(MW_VAR,s2, F("Game Time (m)"));  
          s3->addVar(MW_AUTO_INT,&GAMETIME,0,5999,1);
        s3=menu.addMenu(MW_VAR,s2, F("Pts Period (s)"));
          s3->addVar(MW_AUTO_INT,&POINTPERIOD,0,3600,1);
        s3=menu.addMenu(MW_VAR,s2, F("Red Points"));
          s3->addVar(MW_AUTO_INT,&POINTSPERPERIODRED,0,1000,5);
        s3=menu.addMenu(MW_VAR,s2, F("Blue Points"));
          s3->addVar(MW_AUTO_INT,&POINTSPERPERIODBLUE,0,1000,5); // min, max, increment
        s3=menu.addMenu(MW_VAR,s2, F("Reset Period"));  
          s3->addVar(MW_LIST,&RESETSCOREPERIOD);
          s3->addItem(MW_LIST, F("No")); // returns index 0
          s3->addItem(MW_LIST, F("Yes")); // returns index 1
        s3=menu.addMenu(MW_VAR,s2, F("Countdown (s)"));
          s3->addVar(MW_AUTO_INT,&COUNTDOWNTIMER,0,30,1);
      s2=menu.addMenu(MW_SUBMENU,s1, F("Device Setup"));
        s3=menu.addMenu(MW_VAR,s2, F("Splash Screen"));  
          s3->addVar(MW_LIST,&SPLASHSCREEN);
          s3->addItem(MW_LIST, F("Off")); // returns index 0
          s3->addItem(MW_LIST, F("On")); // returns index 1

    s1=menu.addMenu(MW_SUBMENU,r, F("Advanced"));
        s2=menu.addMenu(MW_VAR,s1, F("Wireless"));  
          s2->addVar(MW_LIST,&WIRELESS);
          s2->addItem(MW_LIST, F("Off")); // returns index 0
          s2->addItem(MW_LIST, F("On")); // returns index 1
        s2=menu.addMenu(MW_SUBMENU,s1, F("LED Control"));
          s3=menu.addMenu(MW_VAR,s2, F("LED Flashing"));  
            s3->addVar(MW_LIST,&LEDBLINK);
            s3->addItem(MW_LIST, F("Off")); // returns index 0
            s3->addItem(MW_LIST, F("On")); // returns index 1
          s3=menu.addMenu(MW_VAR,s2, F("On Time (ms)"));  
            s3->addVar(MW_AUTO_INT,&LEDBLINKON,0,1000,100);
          s3=menu.addMenu(MW_VAR,s2, F("Off Time (ms)"));  
            s3->addVar(MW_AUTO_INT,&LEDBLINKOFF,0,1000,100);
         s2=menu.addMenu(MW_VAR,s1, F("Cursor Flash"));  
           s2->addVar(MW_AUTO_INT,&CURSORBLINKRATE,0,1000,100);
 
    s1=menu.addMenu(MW_SUBMENU,r, F("Developer"));
      s2=menu.addMenu(MW_VAR,s1, F("Serial Debug"));  
        s2->addVar(MW_LIST,&DEBUG);
        s2->addItem(MW_LIST, F("Off")); // returns index 0
        s2->addItem(MW_LIST, F("On")); // returns index 1

    s1=menu.addMenu(MW_VAR,r, F("SAVE & EXIT"));
      s1->addVar(MW_ACTION,save_settings);
      s1->setBehaviour(MW_ACTION_CONFIRM,false); // turn confirmation off

    s1=menu.addMenu(MW_VAR,r, F("EXIT NO SAVE"));
      s1->addVar(MW_ACTION,exit_menu);
      s1->setBehaviour(MW_ACTION_CONFIRM,false); // turn confirmation off

    //menu.navButtons(UP_BOTTON_PIN,DOWN_BOTTON_PIN,LEFT_BOTTON_PIN,RIGHT_BOTTON_PIN,ESCAPE_BOTTON_PIN,CONFIRM_BOTTON_PIN);
    menu.addUsrNav(menuKeys,6);
      
    Serial.println(menu.freeRam());
  }

void loop()
{
  menu.draw();
  
  int key = menuKeys();
 
  if (key != MW_BTNULL)
  {
    Serial.println(key);
  }
  
  //char customKey = keypad1.getKey();
  
  /* if (customKey != NO_KEY){
    Serial.println(customKey);
    if(customKey == '2')
    {
      Serial.println(F("Did the comparison"));
    }
  } */
}
 
 void save_settings()
 {
     Serial.println(F("SAVE SETTINGS TO EEPROM"));
 }
 
 void exit_menu()
 {
     Serial.println(F("EXIT MENU WITHOUT SAVING TO EEPROM"));
 }
 
void myfunc()
{
  Serial.println(F("ACTION FIRED"));
}

int menuKeys()
{
  char keyPressed = keypad1.getKey();
  
  if (keyPressed != NO_KEY)
  {
    if (keyPressed == '2')
    {
      return MW_BTU;
    }
    else if (keyPressed == '8')
    {
      return MW_BTD;
    }
    else if (keyPressed == '4')
    {
      return MW_BTL;
    }
    else if (keyPressed == '6')
    {
      return MW_BTR;
    }
    else if (keyPressed == '*')
    {
      return MW_BTE;
    }
    else if (keyPressed == '#')
    {
      return MW_BTC;
    }
    else
    {
    return MW_BTNULL;
    }
  }
}
« Last Edit: January 10, 2013, 10:51:54 pm by tack » Logged

rome
Offline Offline
Sr. Member
****
Karma: 15
Posts: 474
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

what is happening? The steps seems ok.
first aid: do not call inside loop your function. leave loop with only draw call. I suspect that double call (remember that inside draw method a call to your function is done each loop) to your function could affect the keyboard driver
« Last Edit: January 11, 2013, 02:09:44 am by brunialti » Logged

UK
Offline Offline
God Member
*****
Karma: 17
Posts: 568
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I added the call inside loop() just to prove of the keypad and function were actually working, whih they are.

I'll have a frenzy look at it today. It was 4am when I gave up. LOL

I quickly tried switching back to the normal buttons and that didn't work either. When I switched to the original sketch, without Keypad in, it worked again. The only other differene is me changing the same menu structure from 'tree' to 'menu'.

It may be something else and I'll investigate further today and have another attempt at making it work, before I bring all this code into my main project.

Hopefully I can get it working and you can then use this as your custom keys example if you like. It would be good as it shows how to do it with a standard keypad using another library. That can easily expand to a user creating their own whole button hanging routine for something like analogue buttons.
Logged

UK
Offline Offline
God Member
*****
Karma: 17
Posts: 568
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Amazing what going to getting some sleep and looking at it fresh does.

As I suspected, it was nothing to do with the custom buttons or keypad. It was actually LCD related. DOH!

Bear with me here as I try to explain it.

I have one copy of the sketch with normal buttons, which was saved, and another with the keypad code added; 'menu' and 'menu_keypad'.

I have a 328P and a 1284P on the same cluster of breadboards, with an LCD on each. Each LCD is attached to an I2C backpack, but they have different addresses (0x20 v 0x27).

My 'menu' sketch had been working on the 328P fine, but RAM was low, so I thought I'd need the additional RAM of the 1284, but when trying to run it I got a INPUT_PULLUP related compile error (1284P will be the final platform).

So...I know it all compiles with Uno as the board. I'd had 'menu' running on the 328P (I2C 0x20), but the 'menu_keypad' was first tried on the 1284P (I2C 0x27).

What had happened is that the addr wasn't changed, so the LCD wasn't actually being used, BUT.....as I'd had the original 'menu' running, the display hadn't updated! The LCD's don't reset on MCU reset so it still shows the last thing on the screen, i.e. my root menu, so it seemed like there was no navigation!

I was actually looking at the screen written by the previously loaded 'menu' sketch (using the correct LCD addr), when I switched to running the 'menu_keypad' sketch (using the LCD address on the other MCU). Obviously they are identical as it's the same menu layout.

Now I've found that silly error on my part it all works fine!!! :-)

Now to add in the EEPROM save and read.

What I'll be doing is declaring those variables at the beginning and then, once MENWIZ is started, doing a readEeprom(). If it's the first time the sketch has ever been run then there will be nothing in EEPROM and I'm assuming the library handles this and leaves the declared variables intact. If there is data in EEPROM then it will replace the values of the declared variables.

When I select SAVE & EXIT I'll simply call writeEeprom() in my ACTION function for that item.
« Last Edit: January 11, 2013, 06:10:55 am by tack » Logged

UK
Offline Offline
God Member
*****
Karma: 17
Posts: 568
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, now I seem to be having a problem with the EEPROM saving but first, a tidied up custom key function, in case you want to include it in docs:-

Code:
// function to wrap keypad presses and return values to menu as custom keys input
// this uses the logical direction keys and the * and # keys (on a normal 4x4 keypad).
//      2
//   4    6
//      8
//   *    #
int menuKeys()
{
  char keyPressed = keypad1.getKey(); // read the keypad to see if a key has been pressed
 
  switch (keyPressed)
  {
    case NO_KEY:
      return MW_BTNULL; // no key pressed
    case '2':
      return MW_BTU; // key 2 pressed for direction UP
    case '8':
      return MW_BTD; // key 8 pressed for direction DOWN
    case '4':
      return MW_BTL; // key 4 pressed for direction LEFT
    case '6':
      return MW_BTR; // key 6 pressed for direction RIGHT
    case '*':
      return MW_BTE; // key * pressed for ESCAPE
    case '#':
      return MW_BTC; // key # pressed for CONFI|RM
  }

Right, with that out of the way, I am adding the readEeprom() and writeEeprom() methods in my sketch as below:-

Code:
void setup(){
  _menu *r,*s1,*s2,*s3; // menu structure, root plus each submenu
  
  keypad1.begin(); // start Keypad number 1

  Serial.begin(115200);
  
  menu.begin(&lcd1,16,2); //declare lcd1 object and screen size to menwiz lib
  
  [b]menu.readEeprom();[/b] // read any stored values in the EEPROM
  
  menu.setBehaviour(MW_MENU_INDEX,false); // turn off the menu index - 1/3 etc

  r=menu.addMenu(MW_ROOT,NULL,F("MAIN MENU"));
 
    s1=menu.addMenu(MW_SUBMENU,r, F("General"));
      s2=menu.addMenu(MW_SUBMENU,s1, F("Game Setup"));
        s3=menu.addMenu(MW_VAR,s2, F("Game Time (m)"));  
          s3->addVar(MW_AUTO_INT,&GAMETIME,0,5999,1);
        s3=menu.addMenu(MW_VAR,s2, F("Pts Period (s)"));
          s3->addVar(MW_AUTO_INT,&POINTPERIOD,0,3600,1);
        s3=menu.addMenu(MW_VAR,s2, F("Red Points"));
          s3->addVar(MW_AUTO_INT,&POINTSPERPERIODRED,0,1000,5);
        s3=menu.addMenu(MW_VAR,s2, F("Blue Points"));
          s3->addVar(MW_AUTO_INT,&POINTSPERPERIODBLUE,0,1000,5); // min, max, increment
        s3=menu.addMenu(MW_VAR,s2, F("Reset Period"));  
          s3->addVar(MW_LIST,&RESETSCOREPERIOD);
          s3->addItem(MW_LIST, F("No")); // returns index 0
          s3->addItem(MW_LIST, F("Yes")); // returns index 1
        s3=menu.addMenu(MW_VAR,s2, F("Countdown (s)"));
          s3->addVar(MW_AUTO_INT,&COUNTDOWNTIMER,0,30,1);
      //s2=menu.addMenu(MW_SUBMENU,s1, F("Device Setup"));
        //s3=menu.addMenu(MW_VAR,s2, F("Splash Screen"));  
          //s3->addVar(MW_LIST,&SPLASHSCREEN);
          //s3->addItem(MW_LIST, F("Off")); // returns index 0
          //s3->addItem(MW_LIST, F("On")); // returns index 1

    s1=menu.addMenu(MW_SUBMENU,r, F("Advanced"));
        s2=menu.addMenu(MW_VAR,s1, F("Wireless"));  
          s2->addVar(MW_LIST,&WIRELESS);
          s2->addItem(MW_LIST, F("Off")); // returns index 0
          s2->addItem(MW_LIST, F("On")); // returns index 1
        s2=menu.addMenu(MW_SUBMENU,s1, F("LED Control"));
          s3=menu.addMenu(MW_VAR,s2, F("LED Flashing"));  
            s3->addVar(MW_LIST,&LEDBLINK);
            s3->addItem(MW_LIST, F("Off")); // returns index 0
            s3->addItem(MW_LIST, F("On")); // returns index 1
          s3=menu.addMenu(MW_VAR,s2, F("On Time (ms)"));  
            s3->addVar(MW_AUTO_INT,&LEDBLINKON,0,1000,100);
          s3=menu.addMenu(MW_VAR,s2, F("Off Time (ms)"));  
            s3->addVar(MW_AUTO_INT,&LEDBLINKOFF,0,1000,100);
         s2=menu.addMenu(MW_VAR,s1, F("Cursor Flash"));  
           s2->addVar(MW_AUTO_INT,&CURSORBLINKRATE,0,1000,100);
 
    s1=menu.addMenu(MW_SUBMENU,r, F("Developer"));
      s2=menu.addMenu(MW_VAR,s1, F("Serial Debug"));  
        s2->addVar(MW_LIST,&DEBUG);
        s2->addItem(MW_LIST, F("Off")); // returns index 0
        s2->addItem(MW_LIST, F("On")); // returns index 1

    s1=menu.addMenu(MW_VAR,r, F("SAVE & EXIT"));
      s1->addVar(MW_ACTION,saveSettings);
      //s1->setBehaviour(MW_ACTION_CONFIRM,false); // turn confirmation off

    s1=menu.addMenu(MW_VAR,r, F("EXIT NO SAVE"));
      s1->addVar(MW_ACTION,exitMenu);
      //s1->setBehaviour(MW_ACTION_CONFIRM,false); // turn confirmation off

    //menu.navButtons(UP_BOTTON_PIN,DOWN_BOTTON_PIN,LEFT_BOTTON_PIN,RIGHT_BOTTON_PIN,ESCAPE_BOTTON_PIN,CONFIRM_BOTTON_PIN);
    menu.addUsrNav(menuKeys,6);
      
    Serial.println(menu.freeRam());
  }

The menu now only displays when I want it to, using a displayMenu variable, where 0 = no menu, 1 = display menu.

In the main project this variable will be activated by simultaneously pressing a certain key at the time the device is turned on, a bit like entering the BIOS on a PC.

Code:
void loop()
{
  while (displayMenu == 1)
  {
    menu.draw();
  }
 
  lcd1.clear();
  lcd1.setCursor(0,0);
  lcd1.print(F("  Menu  Exited  "));
  lcd1.setCursor(0,1);
  lcd1.print(F("  Game  Starts  "));
  
  while (displayMenu != 1); // do nothing forever, after doing a single print to the LCD; halt changes for test purposes
}

My 'SAVE & EXIT' Option should write the values to Eeprom and then change the value of global displayMenu to 0 so the menu no longer displays and the game starts.

Code:
void saveSettings()
 {
   menu.writeEeprom(); // save the settings to EEPROM
   Serial.println(F("Settings Saved To EEPROM"));
   displayMenu = 0; // set menu to off so it is no longer active and the rest of the sketch continues
 }

When I change a setting and select 'EXIT & SAVE', I then reset the MCU and go back in and the value is back to the originally declared value at the beginning of the sketch. Surely the menu.readEeprom() should update these from stored values?

The most obvious question is; do I have this readEeprom() in the correct place, or does it need to be closer to the beginning of the sketch? I've placed it after the menu class is initialised.
« Last Edit: January 11, 2013, 08:34:14 am by tack » Logged

rome
Offline Offline
Sr. Member
****
Karma: 15
Posts: 474
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the keypad callback!
the readEeprom() **for each menwiz declared variable** read from eeprom the stored values.
Therefore you need to declare all the variables before, that is readEeprom must be placed **after** the last addVar call....
Logged

UK
Offline Offline
God Member
*****
Karma: 17
Posts: 568
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, thanks for that.

I've tried that and it looks like the EEPROM is being read. However, when I run this on an MCU that hasn't run it before I get all my declared variables set to -1, presumably as the EEPROM is empty at that point.

I'm sure there are things to do with this so I guess I'll go read up on using EEPROM. I guess it couldn't be that easy. LOL.

As far as the documents go, I think it would benefit new users immensely to have actual examples of how each method is used, and where. The documentation talks in programmer terms and kind of assumes the reader has the same level of knowledge as you do. Most users will be hobbyists and will need actual examples.

Things like this EEPROM stuff. The docs just mention method readEeprom() in class MENWIZ. I almost just tried calling readEeprom() to start, but realised it is a method so needs to be menu.readEeprom() but I think some users would struggle even more.

I'll do some reading on EEPROM use and have another try at fixing my code, to work how I want, tomorrow.

If empty EEPROM returns -1 values then maybe the library could handle that in the background and. He k it against the legal value range for each addVar item. If the retrieved value is outside legally declared range then don't update the live variable.

There will always be abl first time this code is run, and also menu items added or removed from a device, so there will be variables for which there is no corresponding value in EEPROM.
« Last Edit: January 11, 2013, 08:37:10 pm by tack » Logged

Pages: 1 ... 20 21 [22] 23 24 ... 32   Go Up
Jump to: