rome
Offline
Sr. Member
Karma: 13
Posts: 340
|
 |
« Reply #315 on: January 08, 2013, 02:01:02 pm » |
@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. 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
Jr. Member
Karma: 0
Posts: 76
Mechmate #70
|
 |
« Reply #316 on: January 09, 2013, 03:59:40 pm » |
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 .... // +++++++ 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
Jr. Member
Karma: 0
Posts: 76
Mechmate #70
|
 |
« Reply #317 on: January 09, 2013, 04:07:39 pm » |
... And now a little question ... This shows on the LCD a graphic format like that: 0 [10] 100 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
Sr. Member
Karma: 13
Posts: 340
|
 |
« Reply #318 on: January 09, 2013, 04:16:42 pm » |
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
Jr. Member
Karma: 0
Posts: 76
Mechmate #70
|
 |
« Reply #319 on: January 09, 2013, 04:37:59 pm » |
Thanks Roberto, just to know if it was possible ... so many things I don't know.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 13
|
 |
« Reply #320 on: January 09, 2013, 09:19:05 pm » |
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. 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
Sr. Member
Karma: 13
Posts: 340
|
 |
« Reply #321 on: January 10, 2013, 02:53:27 am » |
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
Newbie
Karma: 0
Posts: 13
|
 |
« Reply #322 on: January 10, 2013, 04:08:44 pm » |
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
Sr. Member
Karma: 9
Posts: 351
|
 |
« Reply #323 on: January 10, 2013, 10:41:04 pm » |
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:- // 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 //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 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 #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 //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
Sr. Member
Karma: 13
Posts: 340
|
 |
« Reply #324 on: January 11, 2013, 02:06:26 am » |
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
Sr. Member
Karma: 9
Posts: 351
|
 |
« Reply #325 on: January 11, 2013, 04:48:21 am » |
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
Sr. Member
Karma: 9
Posts: 351
|
 |
« Reply #326 on: January 11, 2013, 06:07:01 am » |
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
Sr. Member
Karma: 9
Posts: 351
|
 |
« Reply #327 on: January 11, 2013, 08:23:29 am » |
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:- // 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:- 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. 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. 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
Sr. Member
Karma: 13
Posts: 340
|
 |
« Reply #328 on: January 11, 2013, 03:06:12 pm » |
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
Sr. Member
Karma: 9
Posts: 351
|
 |
« Reply #329 on: January 11, 2013, 08:34:35 pm » |
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
|
|
|
|
|
|