Menu LCD+ Encoder + click encoder... como hacerlo?

Bueno tratando de ver lo que estabas haciendo implementé un LCD i2c con proteus.
Luego se me ocurre buscar algo y como siempre.. apareció un menú i2c para lcd

Aca esta el topic que lo referencia

muy intuitivo, vale la pena mas alla que ya estabas avanzando en tu idea.

Y acá lo que falta: Ya que el ejemplo es para botones simples y el LCD I2C
Pero solo debes reemplazar la rutina que scanea los botons de navegaciones cuidando los valores asignados que estan indicados mas abajo.
Resultado final una librería para i2c usando el rotary enconder.

How to use your input devices instead of standard digital buttons (addUsrNav)

if you want to use your own device to replace the standards buttons managed by MENWIZ and Buttons
libraries (and declared with navButtons functions) you need to write your own function and to declare it
to MENWIZ library using addUsrNav method.
The user defined function will replace the following internal one:

int menwiz::scanNavButtons(){ 
 if(btx->BTU.check()==ON){
   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;}
 else
   return MW_BTNULL;
 }

MENWIZ 0.6.0 Quick Tour 10

The user defined function must return one of the following integer values, defined in MENWIZ.h (allways

use the literals instead of the values, as values can be changed in new MENWIZ versions):

// BUTTON CODES
// ----------------------------------------------------------------------
#define MW_BTNULL      30   //NOBUTTON
#define MW_BTU         31   //UP
#define MW_BTD         32   //DOWN
#define MW_BTL         33   //RIGTH
#define MW_BTR         34   //LEFT
#define MW_BTE         35   //ESCAPE
#define MW_BTC         36   //CONFIRM

The returned integer code represent the last pushed button, if any, or MW_BTNULL if no button has been
pushed since last call.
The user defined function, as the internal scanNavButtons, is called once for every time the method
menwiz::draw is called.
The returned code will activate the behavior associated to the pushed button (or no behaviour if no button
has been pushed).
Resuming

in case of any custom device (as analog button or any other) you must:

  • write your own function in the sketch (the name is up to the user)
  • the function must return one of the 7 values above, depending on the pushed button (or the simulated
    ones)
  • the function must be declared to MENWIZ with the method addUsrNav

How to save your MENWIZ variables to EEPROM (writeEeprom and
readEeprom)

WARNING: the user defined function simulating buttons have to return pushed button codes just once
(that is the function must “clear” the internal status) same as with standard digital buttons! otherwise
the library assumes multiple button pushes, one for each user function call....

Acá te encontre un ejemplo que usa la librería y el rotary encoder todo junto.
Esta hecho con libreria lcd común pero sabes que no hay problema para cambiarla.

Code: [Select]

/* Sketch for Arduino/IDE 1.x (quick_tour_rotEnc.ino). Based on MENWIZ quick_tour.ino
   Detent rotary encoder with two buttons and 16x2 LCD example.
   Input signal using interrupts on pin A0/1 for encoder and A2/3 for buttons.
   Based on BenF forum sketch 25may2011 and debounce from delphino-999 forum sketch 19oct2012.
   HW: Roboduino (http://arduino-direct.com/sunshop) and rotary encoder with pushbutton (Panasonic 30 PPR, audiosector, www.ebay.com)
   Desember 2012, Hans Fredrik Sandberg
 Pin allocation on Uno
  D4      LCD DB4
  D5      LCD DB5
  D6      LCD DB6
  D7      LCD DB7
  D8      LCD RS  
  D9      LCD Enable
  D10     LCD backlit control
  A0 D14  Rotary A left 1
  A1 D15  Rotary B right 2
  A2 D16  Button 1 confirm 6
  A3 D17  Button 2 escape 5
*/
#include <Wire.h>
#include <LiquidCrystal.h>
#include <buttons.h>
#include <MENWIZ.h>
#include <EEPROM.h>

volatile byte virtualButton = 0;     // which button was pressed
volatile int push[2] = {0,0};        // Variable to pass button press back to main loop
long debouncing_time = 40;           // Debouncing Time in Milliseconds
volatile unsigned long last_micros;  // Variable to keep time while debounce

menwiz menu;
LiquidCrystal lcd( 8,  9, 4, 5, 6, 7, 10, POSITIVE );
//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
extern byte MW_navbtn;        // needed to run the software key navigation in Menwiz
int  list,setp=110;

void setup()
{
  Serial.begin(9600);
  Serial.println("Start");
  PORTC |= _BV(PORTC0) | _BV(PORTC1) | _BV(PORTC2) | _BV(PORTC3);   // enable pullup for pins
  PCMSK1 = _BV(PCINT8) | _BV(PCINT9) | _BV(PCINT10) | _BV(PCINT11); // enable button pin change interrupt A0 A1 A2 A3
  PCICR = _BV(PCIE1);                                               // C-port interrupt enable

  _menu *r,*s1,*s2;
  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;

  r=menu.addMenu(MW_ROOT,NULL,F("Root"));
    s1=menu.addMenu(MW_SUBMENU,r, F("Node1-submenu"));
      s2=menu.addMenu(MW_VAR,s1, F("Node3-list"));
        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("Node4-int"));
        s2->addVar(MW_AUTO_INT,&setp,0,120,1);
      s2=menu.addMenu(MW_VAR,s1,F("back"));
        s2->addVar(MW_ACTION,escapeFunct);
        s2->setBehaviour(MW_ACTION_CONFIRM,false);  // MW_ACTION_IMMEDIATE described in MENWIZ_0-6-0_QUICK TOUR.pdf  
    s1=menu.addMenu(MW_VAR,r, F("Node2-action"));
      s1->addVar(MW_ACTION,myfunc);

  sprintf(menu.sbuf,"Test MENWIZ\nRotEnc SwBtn",1);  // Splash screen shown at startup time
  menu.addSplash((char *) menu.sbuf,4000);           // Shown for msecs
  menu.addUsrScreen(msc,3000);                       // Default screen function shown after msecs since last button push
  digitalWrite(10, HIGH);                            // LCD backlit on
}

void loop()     
{
  menu.draw();                    // NAVIGATION MANAGEMENT & DRAWING ON LCD. NOT BLOCKING has to be the first in the void loop
  /*
  put your regular code here
  */
  if ( push [0] > 0 ) { // confirm
    virtualButton = 6;
    push[0] = 0;
  }
  if ( push [1] > 0 ) { // escape
    virtualButton = 5;
    push[1] = 0;
  }
}

ISR(PCINT1_vect) // handle pin change interrupt for A0 to A5  here
{
  static uint8_t AB = 0x03;     //lookup table index
  static long encval = 0;           //encoder value
  static const int8_t enc_states[] =   {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
  static uint8_t btn = _BV(PINC2) | _BV(PINC3);
  uint8_t t = PINC;  // read port status

  // check for rotary2 state change on pin A0 A1
  AB <<= 2;                  // save previous state
  AB |= ( t & 0x03 );       // add current state, from lower port pin pair
  encval += enc_states[AB & 0x0f];
  if( encval > 1 ) {         // step forward
    virtualButton = 2; encval = 0;
  }
  else if( encval < -1 ) {   // step backwards
    virtualButton = 1; encval = 0;
  }

  // check if buttons are pushed
  t &= _BV(PINC2) | _BV(PINC3); // A2 A3
  if (t != btn) {  // activity on pins, we're only interested in high to low transitions
    if((long)(micros() - last_micros) >= debouncing_time * 1000) {  
      push[0] |= !(t & _BV(PINC2));
      push[1] |= !(t & _BV(PINC3));
      btn = t;
      last_micros = micros();  // start/restart bounce guard timer (covers make and break)
    }
 }
}

void myfunc(){Serial.println("ACTION FIRED");}

int navMenu() // called from menu.draw 
{ 
  switch (virtualButton) 
  {
  case 5: // Escape
    virtualButton = 0;
    return MW_BTE;
    break;
  case 6: // Confirm
    virtualButton = 0;
    return MW_BTC;
    break;
  case 1: // Up
    virtualButton = 0;
    return MW_BTU;
    break; 
  case 2: // Down
    virtualButton = 0;
    return MW_BTD;
    break;
  case 0: // no button
    return MW_BTNULL;
    break;
  }
}

void escapeFunct() {
  Serial.println("Back Called");
  virtualButton = 5;  //simulate escape button press, for use in some menus
}

// user defined default screen.
void msc()
{
  sprintf(menu.sbuf,"Proc.time:%ld\nFr.mem:%d\n",millis()/1000,(int)menu.freeRam());
  menu.drawUsrScreen(menu.sbuf);
}

Muchas gracias!
Este parece prometedor, incluso trae su instructivo en PDF...
de cualquier manera le doy una investigada y si no entiendo algo regreso a preguntar !!!

Gracias.
-Alex 8)

Si no entiendes quemate las neuronas que preguntar es facil, si cada vez que tienes un problema preguntas... no te esfuerzas Alex, vamos que estas haciendo buenas cosas pero ponle un poco mas de ganas!! Dicho con humor!!

@Surbyte
Bueno, al fin tuve algo de tiempo para revisar un poco mas esta libreria, y debo decir que es absolutamente FANTASTICA... Permite crear un menu, variables, grabar en EPPROM y funciona las librerías nuevas.

De momento y ya que soy nuevo en la libreria la tengo conectada a seis botones en pines digitales... ya que funcione adecaudamente... agregare el rotary encoder.

pero como siempre hay algo que se me escapa...

Cree el menú y algo raro pasa, me explico;

En lugar de:
Menu
Ajuste de Termostato
Modo Nocturno
Deshielo
Activar
Cantidad de Deshielos
Tiempo deshielo
Alarma x temp.
Activar
Limite Vitrina
Limite Bodega

Obtengo algo asi;
Menu
Ajuste de Termostato
Modo Nocturno
Deshielo
Activar
Cantidad de Deshielos

Revise y todas la variables estan bien declaradas, intente cambiar los valores de máximos valores permitidos de menus y submenus;
#define MAX_MENU 25
#define MAX_OPTXMENU 15
y no funciona...

El tamaño del sketch es;
----Tamaño binario del Sketch: 19,568 bytes (de un máximo de 32,256 bytes)----

Intente usar la funcion de debugging pero al parecer la estoy usando mal, ya busque en el foro especial de MENWIZ... y no pude encontrar un ejemplo que la usara, para poder copiar ese fragmento, si alguíen sabe como usar el debug... o a que se pueda deber esto... se los agradeceria.

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

// DEFINE ARDUINO PINS FOR THE NAVIGATION BUTTONS
#define UP_BOTTON_PIN       9
#define DOWN_BOTTON_PIN     10
#define LEFT_BOTTON_PIN     7 
#define RIGHT_BOTTON_PIN    8
#define CONFIRM_BOTTON_PIN  12
#define ESCAPE_BOTTON_PIN   11
#define MAX_MENU 25
#define MAX_OPTXMENU 15

menwiz tree;
// create lcd obj using LiquidCrystal lib
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

int  list,sp=110;
float temInicioBodega,  tib=0; 
float temInicioVitrina, tiv=0; 
float temFinalBodega,   tfb=0; 
float temFinalVitrina,  tfv=0; 
boolean mn = false; //modo nocturno 
int himn = 0; //hr de inicio modo nocturno  
int mimn = 0; //min de inicio modo nocturno
int hfmn = 0; //hr final modo nocturno
int mfmn = 0; //min final modo nocturno
boolean des = false; // deshielos 
int cd = 0; //candidad de deshielos 
int td = 0; //tiempo de deshielo 
boolean axt = false; //alarma por temperatura 
int axtv = 6; //limite para alam temp vitrina 
int axtb = 6; // limite alam temp bodega 
boolean fl = true; 

void setup(){
  _menu *r,*s1,*s2;

  Serial.begin(19200);    
  tree.begin(&lcd,16,2); //declare lcd object and screen size to menwiz lib

  r=tree.addMenu(MW_ROOT,NULL,F("MENU"));
    s1=tree.addMenu(MW_SUBMENU,r, F("AJUSTE TERMOST"));
      s2=tree.addMenu(MW_VAR,s1, F("TEMP INICIO BODEGA"));
        s2->addVar(MW_AUTO_FLOAT,&tib,-10,10,0.5);      
      s2=tree.addMenu(MW_VAR,s1, F("TEMP FINAL BODEGA"));
        s2->addVar(MW_AUTO_FLOAT,&tfb,-10,10,0.5);  
      s2=tree.addMenu(MW_VAR,s1, F("TEMP INICIO VITRINA"));
        s2->addVar(MW_AUTO_FLOAT,&tiv,-2,10,0.5);  
      s2=tree.addMenu(MW_VAR,s1, F("TEMP FINAL VITRINA"));
        s2->addVar(MW_AUTO_FLOAT,&tfv,-2,10,0.5);  
        
    s1=tree.addMenu(MW_SUBMENU,r, F("MODO NOCTURNO"));
      s2=tree.addMenu(MW_VAR,s1, F("ACTIVAR ?"));
        s2->addVar(MW_BOOLEAN,&mn);      
      s2=tree.addMenu(MW_VAR,s1, F("HORA DE INICIO"));
        s2->addVar(MW_AUTO_INT,&himn, 0,24,1);  
      s2=tree.addMenu(MW_VAR,s1, F("MINUTO DE INICIO"));
        s2->addVar(MW_AUTO_INT,&mimn, 0,59,1);  
      s2=tree.addMenu(MW_VAR,s1, F("HORA FINAL"));
        s2->addVar(MW_AUTO_INT,&hfmn, 0,24,1);  
      s2=tree.addMenu(MW_VAR,s1, F("MINUTO FINAL"));
        s2->addVar(MW_AUTO_INT,&mfmn,0,59,1);  
    
    s1=tree.addMenu(MW_SUBMENU,r, F("DESHIELO"));
      s2=tree.addMenu(MW_VAR,s1, F("ACTIVAR ?"));
        s2->addVar(MW_BOOLEAN,&des);      
      s2=tree.addMenu(MW_VAR,s1, F("CANT. DESHIELOS"));
        s2->addVar(MW_AUTO_INT,&cd, 0,10,1);  
      s2=tree.addMenu(MW_VAR,s1, F("TIEMPO DESHIELO"));
        s2->addVar(MW_AUTO_INT,&td, 0,10,1);  

    s1=tree.addMenu(MW_SUBMENU,r, F("ALARMA TEMP"));
      s2=tree.addMenu(MW_VAR,s1, F("ACTIVAR ?"));
        s2->addVar(MW_BOOLEAN,&axt);      
      s2=tree.addMenu(MW_VAR,s1, F("LIMITE VITRINA"));
        s2->addVar(MW_AUTO_INT,&axtv, 0,10,1);  
      s2=tree.addMenu(MW_VAR,s1, F("LIMITE BODEGA"));
        s2->addVar(MW_AUTO_INT,&axtb, 0,10,1);   
    //  s1->addVar(MW_ACTION,myfunc);
 tree.navButtons(UP_BOTTON_PIN,DOWN_BOTTON_PIN,LEFT_BOTTON_PIN,RIGHT_BOTTON_PIN,ESCAPE_BOTTON_PIN,CONFIRM_BOTTON_PIN);
}

 
void loop(){
  tree.draw(); 
  int getErrorMessage(boolean fl);
  }

void myfunc(){
  Serial.println("ACTION FIRED");
  }

Gracias.
De cualquier modo sigo buscando!

Bueno... ya encontre como usar el error debug en MENWIZ, algo realmente sencillo, solo;

s1=tree.addMenu(MW_SUBMENU,r, F("DESHIELO"));
      s2=tree.addMenu(MW_VAR,s1, F("ACTIVAR ?"));
        s2->addVar(MW_BOOLEAN,&des);      
      s2=tree.addMenu(MW_VAR,s1, F("CANT. DESHIELOS"));
        s2->addVar(MW_AUTO_INT,&cd, 0,10,1);  
      s2=tree.addMenu(MW_VAR,s1, F("TIEMPO DESHIELO"));
        s2->addVar(MW_AUTO_INT,&td, 0,10,1);  
       →→→→tree.getErrorMessage(true);←←←←

    s1=tree.addMenu(MW_SUBMENU,r, F("ALARMA TEMP"));
      s2=tree.addMenu(MW_VAR,s1, F("ACTIVAR ?"));
        s2->addVar(MW_BOOLEAN,&axt);      
      s2=tree.addMenu(MW_VAR,s1, F("LIMITE VITRINA"));
        s2->addVar(MW_AUTO_INT,&atv, 0,10,1);  
      s2=tree.addMenu(MW_VAR,s1, F("LIMITE BODEGA"));
        s2->addVar(MW_AUTO_INT,&atb, 0,10,1);   
      →→→→tree.getErrorMessage(true);←←←←

Al agregar esas instrucciones, cargar el programa y correrlo debe aparecer algo en el monitor serial como;
ERROR 0
ERROR 0
ERROR 110
ERROR 110
En mi caso tengo 4 sub-menus los ultimos dos me tiran error, me dice que se necesita un
" MW_VAR menu type required" .... lo estoy revisando...