MENWIZ: yet another character lcd menu wizard library

@calim
the freeram value is really low. It could be the source of your problem.
In order to save a little amount of memory, try to disable EEPROM support (comment #define EEPROM_SUPPORT line in MENWIZ.h)

@calim
about recurring menus there are many problems: the label cannot be changed dinamically after declaration (it could be even dangerous as it stored in the prog mem space), even more internally the library stores the pointer to the sketch variable defined by user and the last confirmed value (in order to allow the user to cancel unwanted changes) and the eeprom support method stores just one variable for each menu vaiable object.

Hi, thanks for this great lib!

I've got a few questions:

I'm building something like this:

Root 
 -> Room 1
     -> P1
     -> P2
 -> Room 2
     -> P1
     -> P2

is it possible to define P1, P2 (which are indeed quite long) strings once and re-use for the different rooms? I guess this would save some PROGMEM space.

Also, I would like to make the number of rooms configurable through a #define, do you think I could add the menu items dynamically within a for loop in setup() ?

about label duplication:
it could be a good idea, and it quite easy to implement in MENWIZ. I do'nt know if the label duplication is really a common practice or not.

about dynamic menu(s) creation:
of course you can create menu entries inside a loop.

@tomega3
The problem of the list index is a (regression) bug of MENWIZ. I solved it and I'll put on gethub asap.
Thanks tom

EDIT the new version 1.0.2 with the above patch is available at

https://github.com/brunialti/MENWIZ/downloads

Hi there,
including or uncommenting eeprom support had no effect because I didn't use it anyway. I tried different values of MAX_MENU. With 25 it has freeRam of 198. With 30 it has 98 and produces the error, with 29 it has 118 and the values in the las menu jump around wild but the menu point still is available after leaving the menu, with 28 it has 138 freeRam and everything works fine. I hope it still does when I have created all of the scetch. :slight_smile:

Thanks, calim

@elpaso: good idea with the label duplication. I'll try it for my time-setting menus. However, I don't know how to declare a const __FlashStringHelper*. When I try const __FlashStringHelper* hh="Stunde"; I getcannot convert ‘const char*’ to ‘const __FlashStringHelper*’ in initialization

About eeprom : you have to comment #define EEPROM_SUPPORT *AND * you have to not include the EEPROM.h lib in your sketch. In this way MENWIZ saves some memory both in progmem (about 900 bytes) and in ram memory (just a little bit) independently from the fact that you use or not the provided methods.

I think the next version will include a check to control duplicated label strings ... It seems to be too easy to implement ... to not implement it .

I hope to optimize the code in order to save some memory (but I think it could be not more than about 100 bytes). In the meantime :cold_sweat: if you use arduino Mega or any compatible board with the same microcontroller (or even better the Due) you of course will have no problems ...

EDIT the duplication check is a nonsense code. Once you insert F("....") inside the sketch code you allocate at compile time the space. The method inside MENWIZ only store the pointer of type "const __FlashStringHelper*". It does not allocate any memory. The only way to spare memory is to pass a pointer variable to a const __FlashStringHelper data type for any duplicate string. But that is up to the user. Menwiz cannot do any memory save at that point.

Hi,
I did check my files and MENWIZ.h already has//#define EEPROM_SUPPORT    //uncomment if you want to use the readEeprom and writeEeprom methods! and in my scetch I have

#include <Wire.h>
#include <Time.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <buttons.h>
#include <MENWIZ.h>
//#include <EEPROM.h>

so it seems it is not the eeprom that's eating up RAM but one of the other libraries. When I have time I will do the whole menu and check the memory again. May be next week. Then I'll try lower values of MAX_MENU.
Thanks! calim

PS: I'm using an Arduino Nano v3.0

I suppose you have the ATmega328 version, is'nt it?

Hi,
yes, the Nano v3 comes with the ATmega 328. It should have the full power of the Uno. 8)
calim

Ok. I'll try to let you fit 30+ menus ... :drooling_face:

Hello,

I have two questions about the code attached...

First... the section "DEFINE BOARD PINS FOR THE NAVIGATION BUTTONS" I have verified my electronics by continuity test to the pins on the ATMEL, ATMEGA328 and they are attached correctly with a 10K SIP Resistor pack to ground, the only button that works is the DOWN, I can scroll through the S1 menu but the CONFIRM, UP, ESCAPE, LEFT & RIGHT buttons do not work, any assistance you can offer is greatly appreciated?

Second... the section ("// menu.addSplash(("TLHurley Engineering 12'\nEMZ Technologies 09/2012") menu.sbuf, 10000);") returns an error ( Expected ")" before "menu" ) why is this? I have the line commented out to verify the sketch compiles. I cannot find what the actual error is.

Thank you for any help,

Terry

[quote]
[color=#7E7E7E]//The full code is in library example file Sample MENWIZ.ino[/color]
#include <[color=#CC6600]Wire[/color].h>
#include <[color=#CC6600]LCD[/color].h>
#include <[color=#CC6600]LiquidCrystal[/color].h>
#include <[color=#CC6600]buttons[/color].h>
#include <MENWIZ.h>
#include <[color=#CC6600]EEPROM[/color].h>

[color=#7E7E7E]// DEFINE BOARD PINS FOR THE NAVIGATION BUTTONS (DCM2053 Pins shown below in notes)[/color]
#define UP_BUTTON_PIN       0  [color=#7E7E7E]// DCM2053 PIN 19[/color]
#define DOWN_BUTTON_PIN     1  [color=#7E7E7E]// DCM2053 PIN 20[/color]
#define LEFT_BUTTON_PIN     2  [color=#7E7E7E]// DCM2053 PIN 23[/color]
#define RIGHT_BUTTON_PIN    3  [color=#7E7E7E]// DCM2053 PIN 24[/color]
#define CONFIRM_BUTTON_PIN  4  [color=#7E7E7E]// DCM2053 PIN 22[/color]
#define ESCAPE_BUTTON_PIN   5  [color=#7E7E7E]// DCM2053 PIN 21[/color]


menwiz menu;
[color=#7E7E7E]// create lcd obj using LiquidCrystal lib[/color]
[color=#CC6600]LiquidCrystal[/color] lcd(7, 8, 9, 10, 11, 12);

[color=#7E7E7E]/*[/color]
[color=#7E7E7E]*LCD RS Pin - Dorkbaord D7[/color]
[color=#7E7E7E]*LCD EN Pin - Dorkbaord D8[/color]
[color=#7E7E7E]*LCD D4 Pin - Dorkbaord D9[/color]
[color=#7E7E7E]*LCD D5 Pin - Dorkbaord D10[/color]
[color=#7E7E7E]*LCD D6 Pin - Dorkbaord D11[/color]
[color=#7E7E7E]*LCD D7 Pin - Dorkbaord D12[/color]
[color=#7E7E7E]*LCD R/W Pin - GND[/color]
[color=#7E7E7E]*10K Resistor[/color]
[color=#7E7E7E]*ends to 5V and GND[/color]
[color=#7E7E7E]*/[/color]

[color=#7E7E7E]//instantiate global variables to bind to menu[/color]
[color=#CC6600]int[/color]      tp=0;
[color=#CC6600]float[/color]    f=26.0;
[color=#CC6600]boolean[/color]  bb=0;
[color=#CC6600]byte[/color]     b=50;

[color=#CC6600]void[/color] [color=#CC6600][b]setup[/b][/color](){
  [color=#CC6600]_menu[/color] *r,*s1,*s2;
  [color=#CC6600]_var[/color] *v; 
  [color=#CC6600]int[/color]  mem;

  [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]begin[/color](19200);  
  
  [color=#7E7E7E]// have a look on memory before menu creation[/color]
  [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]println[/color](sizeof(menwiz));
  mem=menu.freeRam();
  
  [color=#7E7E7E]// inizialize the menu object (20 colums x 4 rows)[/color]
  menu.[color=#CC6600]begin[/color](&lcd,24,2);

  [color=#7E7E7E]//create the menu tree[/color]
  r=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_ROOT[/color],NULL,F([color=#006699]"MAIN MENU"[/color]));              [color=#7E7E7E]//create a root menu at first (required)[/color]
    s1=menu.[color=#CC6600]addMenu[/color](MW_SUBMENU,r,F([color=#006699]"MEASURE SUBMENU"[/color]));     [color=#7E7E7E]//add a child (submenu) node to the root menu[/color]
    
      s2=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],s1,F([color=#006699]"Test list"[/color]));            [color=#7E7E7E]//add a terminal node (that is "variable"); [/color]
          s2->[color=#CC6600]addVar[/color]([color=#006699]MW_LIST[/color],&tp);                          [color=#7E7E7E]//create a variable of type "option list".. [/color]
          s2->[color=#CC6600]addItem[/color]([color=#006699]MW_LIST[/color],F([color=#006699]"option 1"[/color]));               [color=#7E7E7E]//add option to the OPTION LIST[/color]
          s2->[color=#CC6600]addItem[/color]([color=#006699]MW_LIST[/color],F([color=#006699]"option 2"[/color]));               [color=#7E7E7E]//add option to the OPTION LIST[/color]
          s2->[color=#CC6600]addItem[/color]([color=#006699]MW_LIST[/color],F([color=#006699]"option 3"[/color]));               [color=#7E7E7E]//add option to the OPTION LIST[/color]
          s2->[color=#CC6600]addItem[/color]([color=#006699]MW_LIST[/color],F([color=#006699]"option 4"[/color]));               [color=#7E7E7E]//add option to the OPTION LIST[/color]
          s2->[color=#CC6600]addItem[/color]([color=#006699]MW_LIST[/color],F([color=#006699]"option 5"[/color]));               [color=#7E7E7E]//add option to the OPTION LIST[/color]

      s2=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],s1,F([color=#006699]"Test float var"[/color]));       [color=#7E7E7E]//add a terminal node (that is "variable"); [/color]
          s2->[color=#CC6600]addVar[/color](MW_AUTO_FLOAT,&f,11.00,100.00,0.5); [color=#7E7E7E]//create a variable of type "float number"... [/color]
                                                         [color=#7E7E7E]//...associated to the terminal node and bind it to the app variable "f" of type float[/color]
      s2=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],s1,F([color=#006699]"Test byte var"[/color]));        [color=#7E7E7E]//add a terminal node (that is "variable"); [/color]
          s2->[color=#CC6600]addVar[/color](MW_AUTO_BYTE,&b,25,254,10);         [color=#7E7E7E]//create a variable of type "byte"...[/color]
                                                         [color=#7E7E7E]//...associated to the terminal node and bind it to the app variable "b" of typr byte[/color]
      s2=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],s1,F([color=#006699]"Test boolean var"[/color]));     [color=#7E7E7E]//add a terminal node (that is "variable"); [/color]
          s2->[color=#CC6600]addVar[/color](MW_BOOLEAN,&bb);                    [color=#7E7E7E]//create a variable of type "boolean" [/color]
                                                         [color=#7E7E7E]//...associated to the terminal node and bind it to the app variable "bb" of type boolean[/color]
    s1=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],r,F([color=#006699]"WRITE TO SERIAL"[/color]));             [color=#7E7E7E]//add a terminal node (that is "variable") create an "action" associated to the terminal node... [/color]
      s1->[color=#CC6600]addVar[/color](MW_ACTION,act);                         [color=#7E7E7E]//the act function as default will be called when enter button is pushed[/color]

    s1=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],r,F([color=#006699]"SAVE TO EPROM"[/color]));           [color=#7E7E7E]//add a terminal node (that is "variable") create an "action" associated to the terminal node... [/color]
      s1->[color=#CC6600]addVar[/color](MW_ACTION,savevar);                     [color=#7E7E7E]//the act function as default will be called when enter button is pushed[/color]

    s1=menu.[color=#CC6600]addMenu[/color]([color=#006699]MW_VAR[/color],r,F([color=#006699]"LOAD FROM EEPROM"[/color]));        [color=#7E7E7E]//add a terminal node (that is "variable") create an "action" associated to the terminal node... [/color]
      s1->[color=#CC6600]addVar[/color](MW_ACTION,loadvar);                     [color=#7E7E7E]//the act function as default will be called when enter button is pushed[/color]

  [color=#7E7E7E]//declare navigation buttons (required)[/color]
  menu.navButtons(UP_BUTTON_PIN,DOWN_BUTTON_PIN,LEFT_BUTTON_PIN,RIGHT_BUTTON_PIN,ESCAPE_BUTTON_PIN,CONFIRM_BUTTON_PIN);


 [color=#7E7E7E]// menu.addSplash(("TLHurley Engineering 12'\nEMZ Technologies 09/2012") menu.sbuf, 10000);[/color]
  }

  }

[/quote]

at first glance:
do not use the digital pins 0,1 they are reserved for serial comms. Use the pins starting from 7 instead;
let me know

p.s. try to insert the code without the color markups!

For those who are interessted here the code to use for analog value simulated push buttons to control Menwiz.
Maybe good idea to put it in the manual or in the samples?

edit one error in the first line of void loop. check
// NAVIGATION MANAGEMENT & DRAWING ON LCD. NOT BLOCKING has to be the first in the void loop
menu.draw();

/*

Schematic:

 /*
 
 This is the way the ressitor ladder is used.
 *
 *   analogPin A0                 +5 V
 *      |                         |
 *      |                         \
 *      ----------------          /  
 *                     |          \  1K
 *                     |          /
 *                     |          \
 *                     |____ \____|
 *                     |   SW1    |
 *                     |          \
 *                     |          /  
 *                     |          \  1K
 *                     |          /
 *                     |          \
 *                     |____ \____|
 *                     |   SW2    |
 *                     |          |
 *                     |          \
 *                     |          /  
 *                     |          \  1K
 *                     |          /
 *                     |          \
 *                     |____ \____|
 *                     |   SW3    |
 *                     |          |
 *                     |          \
 *                     |          /  
 *                     |          \  1K
 *                     |          /
 *                     |          \
 *                     |____ \____|
 *                         SW4    |
 *                                |
 *                                \
 *                                /  
 *                                \  1K
 *                                /
 *                                \
 *                                |
 *                                |
 *                                |
 *                                |
 *                                |
 *                              _____  
 *                               ___     ground
 *                                _
 *
 */

// +++++++ Libaries included
#include <Wire.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_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,20,4);
  menu.addUsrNav(navMenu);
  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("SET1"));                        //add a submenu node 1 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("MD"));                         //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("BR"));                         //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("RH"));                         //add a terminal node in the menu tree (that is "variable");

  //---------------
  s1=menu.addMenu(MW_SUBMENU,r,F("SET2"));                    //add a submenu node 2 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("CP"));                         //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("DB"));                         //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("SQ"));                         //add a terminal node in the menu tree (that is "variable");

  //---------------
  s1=menu.addMenu(MW_SUBMENU,r,F("SET3"));                    //add a submenu node 3 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("RS"));                         //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("RCALIB"));                     //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("SCALIB"));                     //add a terminal node in the menu tree (that is "variable");


  //++++++ 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 >= 1000)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  } 
  else  if(buttonValue >= 900 & buttonValue <= 950)
  {
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 800 & buttonValue <=900)
  {    
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 700 & buttonValue <=800)
  {    
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 600 & buttonValue <=700)
  {    
    buttonPressed = 4;
    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);
}

Regarding reply #186 and 187...

Thank you,

I was not aware of the conflict with dual purposing the D0 (RXD) and D1 (TXD) for button use. I am using Digital Pins 7-12 for the display output, is there something in your Libraries that prevent the use of these pins for button use?

also, I was wondering about the addsplash issue in my previous post, can you address the line of code and tell me why I get the error?

Thank you,

Terry

backbone;

Thank you I will attempt to modify my code and prototype to accommodate the 4 button system you have here this will free up my digital pins for sensor inputs. I like the idea of the single Analog Pin for all 4 buttons too.

Thanks again for the insight,

Cheers,

Terry

your usage of the addSplash is wrong because the code does not make sense in c++.
Try the following:

sprintf(menu.sbuf,"TLHurley Engineering 12\nEMZ Technologies 09-2012"); // printout string setup
menu.addSplash((char *) menu.sbuf, 10000); // declare splash string

the sprintf allows you to insert some runtime values into a formatted string also (you are using a constant string variable).

How can I set up the code to change these through the menu interface?

I am still learning C++ and this interface for Arduino. My menus are working but I do not have the Integer Variables for (HEAT ON, PRIMARY FAN ON, and SECONDARY FAN ON) called out in my Menu structure yet (type byte, increment 1, values 32 - 99). This is in Fahrenheit. My current code is attached.

Basically I want to be able to set the temperature through the interface in Fahrenheit 32 - 99 degrees for HEAT, COOL, and SECONDARY FAN.

[quote]
                               // Menu and LCD
char b[48];
_menu *r,*s1,*s2;

                                // initialize the menu object ( 2 x rows x 16 colums LCD)
menu.begin(lcd,16,2);
menu.addUsrNav(navMenu);
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("SET HEAT ON"));                    //add a submenu node 1 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("HEAT ON AT: "));            //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("SET: "));           //add a terminal node in the menu tree (that is "variable");

  //---------------
  s1=menu.addMenu(MW_SUBMENU,r,F("SET COOL ON"));                    //add a submenu node 2 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("COOL ON AT: "));            //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("SET: "));          //add a terminal node in the menu tree (that is "variable");

  //---------------
  s1=menu.addMenu(MW_SUBMENU,r,F("SET 2ND FAN"));                   //add a submenu node 3 to the root menu
  s2=menu.addMenu(MW_VAR,s1,F("2ND FAN ON: "));            //add a terminal node in the menu tree (that is "variable");
  s2=menu.addMenu(MW_VAR,s1,F("SET: "));           //add a terminal node in the menu tree (that is "variable");

                                         // Userscreen
                                         // create an user define screen callback to activate after X secs since last button push
  menu.addUsrScreen(msc,5000);

 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

{
  total= total - readings[index];                // subtract the last reading:
  readings[index] = analogRead(inputPin);  // read from the sensor:
  total= total + readings[index];               // add the reading to the total:
  index = index + 1;                               // advance to the next position in the array:
 if (index >= numReadings)                     // if we're at the end of the array...
  index = 0;                                         // ...wrap around to the beginning:
  average = total / numReadings;           // calculate the average:
  voltage = (average*5000)/1024;           // convert raw sensor value to millivolts
  voltage = voltage-475;                        // remove voltage offset
  tempC = voltage/10;                          // convert millivolts to Celsius
  tempF = ((tempC * 1.8)+32);              // convert celsius to Fahrenheit

if (tempF < (setTemp - 8))                   // if the current temp is 8 degrees lower than the setpoint
    heat_on = 1;                                  // set heater variable to 1
  
if ((heat_on == 1) && (tempF  < (setTemp - 3))) // if heating variable is set to 1 and temp is more than
  {                                                         // 3 degrees lower than the set point
digitalWrite (heat_relay, HIGH);                // turn on the heater relay
  } 
 else                                                    // otherwise
  {
 digitalWrite (heat_relay, LOW);               // turn off the heater relay
    heat_on = 0;                                    // set the heater variable back to 0
  }  

if (tempF  > (setTemp + 8))                    // if the current temp is 8 degrees higher than the set point
    cool_on = 1;                                     // set the cooling variable to 1

 if ((cool_on == 1) && (tempF > (setTemp + 3)))    // if the cooling variable is set to 1 and the temp is more than
  {                                                          // 3 degrees higher than the setpoint
  digitalWrite (cool_relay, HIGH);                // turn on the cooling relay
  }
 else                                                       // otherwise
  {
   digitalWrite (cool_relay, LOW);                 // turn off the cooling relay
    cool_on = 0;
  }
   
 if ((cool_on == 1) && (tempF > (setTemp + 18)))    // if cool is on and temp is greater than 18 degrees above setpoint
   {
   digitalWrite (sec_cool_rly, HIGH);            // turn on the secondary cooling relay
   }
  else                                                    // otherwise
     {
  digitalWrite (sec_cool_rly, LOW);            // turn off the secondary cooling relay
     }
  if ((heat_on == 0) && (cool_on == 0))     // if the heating and cooling varibles are set to 0
  {                                                   
  digitalWrite (allOK, HIGH);                    // turn on the all OK LED
  }
else                                                    // otherwise
  {
digitalWrite (allOK, LOW);                       // turn the all OK LED off
  }

delay(200);                                           // delay in between reads for stability 
}

  menu.draw();
  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 >= 1000)
  {
    buttonPressed = 0;
    noButtonPressed();                   // is calling an extra fucntion
  } 
else if(buttonValue >= 30 & buttonValue <= 50)
  {
    buttonPressed = 1;
    buttonAct = 1;                      // set the menu flag1 "DOWN"
  }
 else if(buttonValue >= 50 & buttonValue <=80)
  {    
    buttonPressed = 2;
    buttonAct = 1;                       // set the menu flag1 "ESCAPE"
  }
  elseif(buttonValue >= 80 & buttonValue <=100)
  {    
    buttonPressed = 3;
    buttonAct = 1;                       // set the menu flag1 "CONFIRM"
  }
else if(buttonValue >= 100 & buttonValue <=130)
  {    
    buttonPressed = 4;
    buttonAct = 1;                       // set the menu flag1 "UP"
  }
}

int noButtonPressed()
{
  return MW_BTNULL;
}

int navMenu()                           // called from menu.draw 
{

long menublockTime = millis();

if(buttonAct == 1 && buttonPressed != 0 && stopMenu == 0)
  
  {
digitalWrite(led13Pin,LOW);        // set timer led ON
    
    menuOffTime = menublockTime  + 200; 
                                        
    stopMenu = 1;

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

if (menuOffTime != 0  &&  menublockTime  > menuOffTime)
  
                                        //  Reset of the timer so a new menu action can be processed
  {
    buttonAct = 0;                      // resets the flag 1[/color]
    buttonPressed = 0;
    menuOffTime = 0;                    // resets timer to zero
    stopMenu = 0;
    digitalWrite(led13Pin,HIGH[);         // set timer led OFF
  }
}

                                        // user defined default screen.[/color]
void msc()
{
 
 lcd.clear();
 
lcd.print("TEMPERATURE: "); lcd.print(tempF,0);
 
lcd.setCursor(0,1);
 
if ((cool_on == 1) && (tempF < (setTemp + 18)))
{
lcd.[print("PRIMARY FAN ON");
 }
 
if (heat_on == 1)
{
lcd[/color].print("HEAT ON");
 }
 
if ((cool_on == 1) && (tempF > (setTemp + 18)))
{
lcd.print("SECONDARY FAN ON");
 }
 
 ((heat_on == 0) && (cool_on == 0))
{
lcd.print("IN RANGE");
 }
 
//delay(5000);                 // Wait for 5 seconds before reading again

}

[/quote]

Thank you for any assistance,

Terry smiley-red

Terry, with your code you correctly implemented the overall menu structure.
Now for each terminal node (that is after each addMenu of type MW_VAR) you need to create you variables.
For instance, if you want to create an int variable to be managed by the menu you have at first to declare a int global variable (the variable you'll test in your code) and after addMenu call use the addVar method:

int temp1;
...
s2=menu.addMenu(MW_VAR,s1,F("COOL ON AT: "))
s2->addVar(MW_AUTO_INT,&temp1,32,39,1);         //create a menu variable of type "integer"...

The code does the following:

  • create your sketch vatiable to test (temp1)
  • create the terminal node ("COOL ON AT: ")
  • create the menu variable of the above terminal node: the variable is of type int, is binded with your variable temp1, the value ranges between 32 and 39 and increment by step of 1

You need to use as many addVar as terminal nodes you defined.
By the way for small values you can also use byte variables.

brunialti,

Thank you, the Menu shows the variable now and it can be set, the only problem I have now is I can't seem to save the set point to Eeprom memory,

where shound I place;

void savevar(){
menu.writeEeprom();
}
and...

void loadvar(){
menu.readEeprom();
}

I need this to store the settings and then read them for code execution... Correct?

So you can understand what I am trying to accomplish I have attached the whole .ino file. I hope it is not too much.

Again thank you for all of your help, you are a very valuable resource.

Cheers,

Terry

THERMOSTAT_MENU.ino (13.6 KB)