Go Down

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


New LiquidCrystal: I cannot let it work with my LCD. I, downloaded, expanded and renamed LiquidCrystal_I2C and dropped it  in libraries dir of the Arduino environment. The Hello world example does not compile and i get "LiquidCrystal_I2C: does not name a name." at the following line

LiquidCrystal_I2C lcd(0x27);  // Set the LCD I2C address

I inserted "#include LCD.h" before "#include <LiquidCrystal_I2C.h>" It compiles but the screen flash randomically.

The LCD has a YwRobot Arduino LCM1602 IIC V1 backpack.
Do I make something wrong?


I can't find the datasheet or schematic for the backpack. What chip does it use? Also, you need to map its pins in the library. Do you have an schematic for it? If not, you can always look at the code of the library you were using and see the pin mapping, then call the appropriate constructor to match that pin map.

Also, if you instal the library, you will have to delete the old one. That is why you are getting the compilation errors.


Apr 08, 2012, 07:28 pm Last Edit: Apr 08, 2012, 08:07 pm by brunialti Reason: 1
The chips are hd44780 and PCA8574
I can give you the link of the producer, that is chinese ...
There is also this reference page.


OK, so lets assume is the same configuration as the DFRobot (I mean, these guys don't tend to invent much), so this is what the schematic looks like:

Assuming this is the connection you would have to instantiate the LCD object as follows:

Code: [Select]

#include <LCD.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd ( 0x27, 2, 1, 0, 4, 5, 6, 7); // Addr, En, Rw, Rs, d4, d5, d6, d7

void setup ( )
    lcd.begin ( 16, 2 );  // Size of the LCD

On that LCD, I wouldn't use the backlight as is without modifying the board. Effectively you are going to short the P3 output to ground through the trasnsistor base-emitter (not nice).

Hope it works.


It seems to work (hello world). But without backlight the LCD is more or less unusefull.
I use the following inizialization sequence:

  lcd->setCursor(0, 0);

The init method is not supported in New LiquidCrystal.The other methods does'nt backlight the screen.
The code in my actual LiquidCrystal_I2C involved in backlighting (that is working without any problem) is the following:

Code: [Select]
#define LCD_BACKLIGHT 0x08

void LiquidCrystal_I2C::backlight(void) {
void LiquidCrystal_I2C::expanderWrite(uint8_t _data){                                       
printIIC((int)(_data) | _backlightval);

void LiquidCrystal_I2C::setBacklight(uint8_t new_val){
backlight(); // turn backlight on
noBacklight(); // turn backlight off

What do you suggest?


If you look at the schematic that I posted on the LCD backpack, has a nasty bug. If you look at the transistor, it is connected to P3. When P3 goes high (which is what you do), it will make the transistor to conduct through the base without any resistor to limit the current. If you look at how much that backpack consumes with the backlight on, you will be surprised!

In any case, if you what to use the backlight on that backpack after this comment, the New LiquidCrystal library does have support for backlight. Take a look at the methods in the base abstract class LCD. What you can do is:
Code: [Select]

#include <LCD.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd ( 0x27, 2, 1, 0, 4, 5, 6, 7, 3, NEGATIVE); // Addr, En, Rw, Rs, d4, d5, d6, d7, backlighpin, polarity

void setup ( )
    lcd.begin ( 16, 2 );  // Size of the LCD

   lcd.backlight ( );
   delay (1000);
   lcd.nobacklight ( );

There are other methods you can use like setBacklight. All these are available in the base abstract LCD class and are inherited by the particular driver.

You can also call the creation as in the previous post and use the setBacklightPin method in the LCD base class too:
Code: [Select]

#include <LCD.h>
#include <LiquidCrystal_I2C.h>


LiquidCrystal_I2C lcd ( 0x27, 2, 1, 0, 4, 5, 6, 7); // Addr, En, Rw, Rs, d4, d5, d6, d7, backlighpin, polarity

void setup ( )
    lcd.begin ( 16, 2 );  // Size of the LCD
    lcd.setBacklightPin ( 3, NEGATIVE );

   lcd.backlight ( );
   delay (1000);
   lcd.nobacklight ( );

The cool thing about the library is that if you use a pointer to the base class in you library as I mentioned in previous posts, it will work with a wide range of LCD drivers without a single line of code being changed and being so targeted to a particular module.

The init method is not necessary at all with any LCD. Calling the init method is done directly from the constructor or from the begin method and they are private. No one should use init even with the standard LiquidCrystal Library. With the other I2C library that you are using it is necessary because somehow they needed to initialize the I2C that can't be done during object creation (as the standard), therefore, as opposed to calling it from within begin, they added a new function that needs to be called (that is not very standard).

Hope it helps.


I have a problem. None of the two ways seems to work.
I get a short flash at startup, I can barely see the character on the LCD but no backlight.
I'll try to compare the codes of the two libs.




Great. It works.
Now let my work on menwiz in order to integrate with new liquidcrystal lib.
Thanks a lot!


You are very welcome. Now if you have a polimeter handy measure how much current it draws. You will be surprised.


Apr 10, 2012, 11:42 am Last Edit: Apr 10, 2012, 11:57 am by brunialti Reason: 1
I inserted in github/brunialti/MENWIZ repository the new version 0.2.0 of MENWIZ using the New LiquidCrystal library. This should allow to support many LCD devices other than the I2C I used for testing.
The lcd object must be created inside the user sketch and only a reference to it must be passed to the MENWIZ library. The MENWIZ library does'nt require any change or conditional compiler directive for the use of an interface other than I2C.
Please use the examples as starting point and be carefull about the lib include sequence (this is a point of the Arduino compiler I'm not stil used ....)

Of course my library is still a beta version and not fully debugged. Use it (it is in the attached file) and let me know.


Apr 12, 2012, 06:22 pm Last Edit: Apr 12, 2012, 06:36 pm by brunialti Reason: 1
I need a volunteer for testing  :)
Before v 1.0 delivery I need to test some functionalities in different environments.
For now I would like to test the user callback that allow the user to overload the internal function (simple 6 buttons management) in order to use  its own input device to navigate inside the menus.
If you have a practical case study and an input device able to give you back 6 states (up, down, left, right, escape, confirm)  I can write the full menu code, and you have only to write your funcion managing the device. The callback function overwrite (just calling the function addUsrNav and passing your function as argument) the following simple internal method:

Code: [Select]

int menwiz::scanNavButtons(){
   return MW_BTU;}
 else if (btx.BTD.check()==ON){
   return MW_BTD;}
 else if (btx.BTL.check()==ON){
   return MW_BTL;}
 else if (btx.BTR.check()==ON){
   return MW_BTR;}
 else if (btx.BTE.check()==ON){
   return MW_BTE;}
 else if (btx.BTC.check()==ON){
   return MW_BTC;}
   return MW_BTNULL;

The only requirement for you is to use New LiquidCrystal llibrary with the interface (serial, I2C, 4 wire, 8 wire ,...) you like.
More details to the volunteeer :-)


Used the sample with simpel menu and modfied it to my needs to get the feel of it all.

80% I have coped and understand.
One thing sofar I ran into as a problem is that not more then 5 menu's are shown when scrolling.
after s2=menu.addMenu(MW_VAR,s1,"Min");                  //add a terminal node in the menu tree (that is "variable");
nothing shown and we start at the top again if we scroll.
So it looks my number of menus is declared somewhere as a max of 5 but cant find it.


Code: [Select]
//Needs 6 buttons.
//Navigation tips:
//- to confirm chanhes allways push confirm button

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <buttons.h>
#include <MENWIZ.h>

#define UP_BOTTON_PIN       9
#define DOWN_BOTTON_PIN     10
#define LEFT_BOTTON_PIN     7
#define RIGHT_BOTTON_PIN    8
#define ESCAPE_BOTTON_PIN   11

//Create global object LCD and MENU
menwiz menu;
LiquidCrystal_I2C lcd(0x27,20,4);

//instantiate global variables to bind to menu
byte tp=2;
int  gp=26;
boolean wr=0;

void setup(){
  char b[84];
  _menu *r,*s1,*s2;
  _var *v;
  int  mem;

  // inizialize the menu object (20 colums x 4 rows LCD)

  //create the menu tree
  r=menu.addMenu(MW_ROOT,NULL,"MAIN MENU");              //create a root menu at first (required)
    s1=menu.addMenu(MW_SUBMENU,r,"Settings");            //add a submenu node to the root menu
      s2=menu.addMenu(MW_VAR,s1,"SpeedStart");           //add a terminal node in the menu tree (that is "variable");
        s2->addVar(MW_AUTO_INT,&gp,1,125,5);             //Set value
      s2=menu.addMenu(MW_VAR,s1,"SpeedCurve");           //add a terminal node in the menu tree (that is "variable");
        s2->addVar(MW_AUTO_INT,&gp,1,125,5);             //Set value
      s2=menu.addMenu(MW_VAR,s1,"Brake");                //add a terminal node in the menu tree (that is "variable");
          s2->addVar(MW_AUTO_INT,&gp,1,125,5);           //Set value
      s2=menu.addMenu(MW_VAR,s1,"Model");                //add a terminal node in the menu tree (that is "variable");
          s2->addVar(MW_AUTO_INT,&gp,1,10,1);            //Set value
      s2=menu.addMenu(MW_VAR,s1,"Min");                  //add a terminal node in the menu tree (that is "variable");
          s2->addVar(MW_AUTO_INT,&gp,1,255,1);            //Set value
      s2=menu.addMenu(MW_VAR,s1,"Max");                  //add a terminal node in the menu tree (that is "variable");
          s2->addVar(MW_AUTO_INT,&gp,1,255,1);            //Set value
      s2=menu.addMenu(MW_VAR,s1,"Reset");                //add a terminal node in the menu tree (that is "variable");
          s2->addVar(MW_BOOLEAN,&wr);                    //Set value
      s2=menu.addMenu(MW_VAR,s1,"Calibrate");            //add a terminal node in the menu tree (that is "variable");

  //(optional) create a splash screen (lap 4 seconds) with some usefull infos
  //the character # marks end of line
  //(tip): use preallocated internal menu.sbuf buffer to save memory space!
  sprintf(menu.sbuf,"DIGITAL SLOT WIZARD #Version 1.01#",6);
  menu.addSplash((char *) menu.sbuf, 4000);

  //declare navigation buttons (required)
  // equivalent shorter call: menu.navButtons(9,10,7,8,11,12);
  // create a user define screen callback to activate after 5 secs since last button push

void loop(){

// user defined default screen
void msc(){
        lcd.begin(20, 4);
        lcd.print("SPD ");
        lcd.print("MDL ");
Never to old to learn and I learn every day


That's true. There are two defines you can change in MENWIZ.h:

#define MAX_MENU       15      //maximum number of nodes
#define MAX_OPTXMENU   5    //maximum number of oprions for each node

The first one is the number of nodes you can create with addMenu method.
The second is the max number of options you can add with addItem method for each node.
Keep all of them as low as possible (depending from your application) in order to spare ram space.

I'm working to clean the code, adding comments ad some usefull (I hope) new method.
I can anticipate:

the string passed to the function use \n (0x0A) character as line delimiter instead of '#'

It quick draw LCD screen with the contents of the argument string. Each line to be shown in the LCD is terminated by char 0x0A ('\n') inside the argument string. Example: "Test user screen\nline1\nline2\n\n". This method provide the user with the quick way to write an entire LCD screen (the lib will manage space padding, cursor position and string length checking)     

user defined navigation device routine (callback). The user can use any device other than buttons to overwrite the internal routine. The callback *must* return an int code for any pushed "button" (MW_BTU=UP,MW_BTD=DOWN,MW_BTL=LEFT,MW_BTR=RIGHT,MW_BTE=ESCAPE,MW_BTC=CONFIRM,MW_BTNULL=NO BUTTON).

Hope it helps


--- reading better your last post:

the MW_MAXOPTMENU does not only affects the numeber of options in case of variable of type MW_LIST but also the maximum allowed number of submenus for each nodes.
So you have to change it to 8 in your case. Should you add more variables under the same submenu "Settings" the number could increase.

What I suggest, if it make sense for you,  is to cluster variables into different submenu nodes.
If you do in such a way *and* there are not more than 5 submenus or options in a choice list variable of type MW_LIST the change to the defined max values are not required and you spare some ram space

Go Up