LiquidMenu show array data by screen

Hi. The following code works reasonably well, with some debugging to do (the return of some menus mainly). However, I am unable to get to display on screen the change of the estado_carga variables, I am always shown the values corresponding to carga = 0. To decide which values to display, I consult the focused line in the submenu_cargas, just before entering the submenu_configurar_encendido, and I display the data of one carga or another according to the focused line; however, I am always shown the same data of carga 0 (which I can change and manipulate).

If I make a change and show in submenu_configurar_encendido value carga when I access the submenu, it shows 0 or 1 according to the focused line from which I access (Carga 1 or Carga 2), so the program works well to determine the variableI work with, but not in the visualization.

/* En "root/Arduino/libreries/LiquidMenu-master/src/LiquidMenu_config.h" hay que comentar tres lineas correspondientes a 
 * LiquidCrystal y descomentar tres lineas correspondientes a LiquidCrystal I2C para la conexión del LCD via I2C
 *  
 * MUY IMPORTANTE: en LiquidMenu_config.h he tenido que cambiar número máximo de pantallas por menú a 50

 * CONEXIÓN DEL RELOJ a través del protocolo IC2: SCL -> A5, SDA -> A4, VCC -> 3,3 V, GND -> GND, SQW -> Pin interrupción (pin 2 de las entradas digitales)

 * MEJORAS: Estimar coste energia
            Tiempo funcionando a la semana, mes, año...
            Indicar fecha
            En los cambios de hora y día creo que se puede confundir y mantenerse encendido
  */

#include "Sodaq_DS3231.h"
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>

int hora = 23, minuto = 59, posicion_texto_hora = 7;  //Posición de hora en la pantalla LCD dependiendo de la hora actual
char *texto_hora[2] = {":",":0"};                     //Necesario para que la impresión de hora por pantalla tenga un formato correcto
char texto_h = texto_hora[0];
bool actualizar_hora = true;
unsigned long tiempo_orden_teclado, espera_6s = 6000, espera_180s = 180000;
bool volver = false;
int numero_cargas = 2;
int variables_sistema = 12;                            //Número de variables; 12 por carga
int carga;                                             //Carga seleccionada
struct variable_sistema {
  bool seEnciende;            // false = no se enciende, true = se enciende
  byte encendidosDia;         // Número que representa días encendidos, por ejemplo, 1010000, indica riego lunes y miércoles. Hay 128 combinaciones (2x7), y byte llega a 128
  int segundosEncendido;      // Segundos encendido
  int diasEncendidoSemana;    // Días de riego a la semana
  byte horaEncendido[4];      // Hora de encendido (hasta 4 veces al día)
  byte minutoEncendido[4];    // Minuto de encendido (hasta 4 veces al día)
};
variable_sistema estado_cargas[2] = {   //Para controlar dos cargas
    {false, 2, 4, 6, {8, 10, 12, 14}, {16, 18, 20, 22}},
    {false, 1, 3, 5, {7, 9, 11, 13}, {15, 17, 19, 21}},
};
const char si[] PROGMEM = "Si";
const char no[] PROGMEM = "No";
char monosilabo[2];                                     //Para mostrar por LCD
char dias_encendido = "LMXJVSD";

byte flecha[8] = {
  0b00000,
  0b00100,
  0b00010,
  0b11111,
  0b00010,
  0b00100,
  0b00000,
  0b00000
};

LiquidCrystal_I2C lcd(0x27, 20, 4);

LiquidLine menu_principal2_linea1(8, 1, "Hora");
LiquidLine menu_principal2_linea2(posicion_texto_hora, 2, hora, texto_h, minuto);
LiquidScreen menu_principal2(menu_principal2_linea1,menu_principal2_linea2);

LiquidLine menu_secundario_linea1(1, 0, "Config. encendidos");
LiquidLine menu_secundario_linea2(1, 1, "Config hora");
//LiquidLine menu_secundario_linea3(1, 2, "Guardar en EEPROM");
LiquidScreen menu_secundario;

LiquidLine submenu_cargas_linea1(1, 0, "Carga 1: ");
LiquidLine submenu_cargas_linea2(1, 1, "Carga 2: ");
LiquidScreen submenu_cargas;

LiquidLine submenu_configurar_hora1(1, 0, "Hora:            ", hora);
LiquidLine submenu_configurar_minutos1(1, 1, "Minutos:         ", minuto);
LiquidScreen submenu_configurar_hora;

LiquidLine submenu_configurar_encendidos1(1, 0, "Carga programada:", estado_cargas[carga].seEnciende);  //monosilabo es texto
LiquidLine submenu_configurar_encendidos2(1, 1, "Encendidos al dia:", estado_cargas[carga].encendidosDia);
LiquidLine submenu_configurar_encendidos3(1, 2, "Seg. encendido: ", estado_cargas[carga].segundosEncendido);
LiquidLine submenu_configurar_encendidos4(1, 3, "Dias encendido: ", estado_cargas[carga].diasEncendidoSemana);
LiquidLine submenu_configurar_encendidos5(1, 4, "Hora encendido1: ", estado_cargas[carga].horaEncendido[0]);
LiquidLine submenu_configurar_encendidos6(1, 5, "Min. encendido1: ", estado_cargas[carga].minutoEncendido[0]);
LiquidLine submenu_configurar_encendidos7(1, 6, "Hora encendido2: ", estado_cargas[carga].horaEncendido[1]);
LiquidLine submenu_configurar_encendidos8(1, 7, "Min. encendido2: ", estado_cargas[carga].minutoEncendido[1]);
LiquidLine submenu_configurar_encendidos9(1, 8, "Hora encendido3: ", estado_cargas[carga].horaEncendido[2]);
LiquidLine submenu_configurar_encendidos10(1, 9, "Min. encendido3: ", estado_cargas[carga].minutoEncendido[2]);
LiquidLine submenu_configurar_encendidos11(1, 10, "Hora encendido4: ", estado_cargas[carga].horaEncendido[3]);
LiquidLine submenu_configurar_encendidos12(1, 11, "Min. encendido4: ", estado_cargas[carga].minutoEncendido[3]);
LiquidScreen submenu_configurar_encendidos;

LiquidMenu menu(lcd);

void cambiar_pantalla_inferior() {
  if ((menu.get_focusedLine() == 0) && (menu.get_currentScreen() == &menu_secundario)) {
    menu.change_screen(&submenu_cargas); 
  }
  else if ((menu.get_focusedLine() == 1) && (menu.get_currentScreen() == &menu_secundario)) {
    menu.change_screen(&submenu_configurar_hora); 
  }
  else if (menu.get_currentScreen() == &submenu_cargas) {
    carga = menu.get_focusedLine();
    menu.change_screen(&submenu_configurar_encendidos);
  }
  else if (menu.get_currentScreen() == &menu_principal2) {
    menu.change_screen(&menu_secundario); 
  }
}

void cambiar_pantalla_superior() {                     //previus.screen no me sirve porque quiero volver a menús superiores, y previus puede ser un menú superior o inferior
  if ((menu.get_currentScreen() == &submenu_cargas)) {
    menu.change_screen(&menu_secundario);
  }
  else if ((menu.get_currentScreen() == &submenu_configurar_hora)) {
    menu.change_screen(&menu_secundario);
  }
  else if ((menu.get_currentScreen() == &submenu_configurar_encendidos)) {
    menu.change_screen(&submenu_cargas);
  }
  else if ((menu.get_currentScreen() == &menu_secundario)) {
    volver = true;
    menu.change_screen(&menu_principal2);
  }
}

void orden_por_teclado() {                          //Sólo hacen falta cuatro botones
  int boton;                                        //Botón pulsado                                                                                                                                                                                    
    
  tiempo_orden_teclado = millis();                  //Capturo el momento en el que entro a configurar variables
  
  do{
    delay(200);                                     //Para evitar rebotes
    boton = analogRead (A0);

    if ((boton > 700) && (boton <= 900)){           //Navegar en el menú hacia abajo
      menu.switch_focus(true);
    }
    else if (boton < 100){                          //Navegar en el menú hacia arriba
      menu.switch_focus(false);                     //Pasa foco a la linea anterior
    }
    else if ((boton >= 100) && (boton <= 300)){     /*Seleccionar la opción remarcada del menú. Botón derecho. El funcionamiento es complejo, porque es una llamada
                                                    recursiva a la misma función orden_por_teclado, y continuaría la función a partir de aquí después de esta llamada.
                                                    Tengo que forzar la salida del bucle con volver = true*/
      cambiar_pantalla_inferior();
      menu.call_function(1);
      volver = true;
    }    
    else if ((boton > 400) && (boton <= 600)){      //Volver al menú anterior. Botón izquierdo
      if ((menu.get_currentScreen() == &menu_secundario)) {
        volver = true;
      }
      cambiar_pantalla_superior();
    }
    boton = 1023;

    /*Esta condición e IF a continuación necesarios para que no haya un error y se pulse una tecla y el programa se quede aqui 
    indefinidamente. Después de 5 minutos volveria al menú principal cortando la configuración de menús*/          
    
    if (millis() >= (tiempo_orden_teclado + espera_180s)) {
      menu.change_screen(&menu_principal2);
      volver = true;
    }
  } while (volver == false);

  volver = false;
}

void seleccionar_numero() {
  int boton, A;                               //Botón pulsado
  
  tiempo_orden_teclado = millis();            //Capturo el momento en el que entro a configurar variables

  lcd.setCursor(0,0);                         //Para simular que es una linea enfocada, sino confunde un poco al navegar por los menús
  lcd.write(byte(0));                         //Representa la flecha

  do{
    delay(200);                               //Para evitar rebotes
    boton = analogRead (A0);
 
    if (((boton > 700) && (boton <= 900)) || (boton < 100)) {
      if (boton > 700){                                                    //Baja numeración
        A = - 1;
      }
      else if (boton < 100) {                                              //Sube numeración
        A = 1;
      }     
      if ((menu.get_focusedLine() == 0) && (menu.get_currentScreen() == &submenu_configurar_hora)) {
        hora = hora + A;
        if (hora == -1){
          hora = 23;
        }
        else if (hora == 24){
          hora = 0;
          menu.update();
        }
        DateTime dt(2011, 11, 10, hora, minuto, 0, 5);
        rtc.setDateTime(dt); //Adjust date-time as defined 'dt' above
      }
      else if ((menu.get_focusedLine() == 1) && (menu.get_currentScreen() == &submenu_configurar_hora)) {
        minuto = minuto + A;
        if (minuto == -1){
          minuto = 59;
        }
        else if (minuto == 60){
          minuto = 0;
          menu.update();
        }
        DateTime dt(2011, 11, 10, hora, minuto, 0, 5);
        rtc.setDateTime(dt); //Adjust date-time as defined 'dt' above
      }
      else if ((menu.get_focusedLine() == 1) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].encendidosDia = estado_cargas[carga].encendidosDia + A;
        if (estado_cargas[carga].encendidosDia == -1){
          estado_cargas[carga].encendidosDia = 4;
        }
        else if (estado_cargas[carga].encendidosDia == 5){
          estado_cargas[carga].encendidosDia = 0;
        }
      }
      else if ((menu.get_focusedLine() == 2) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].segundosEncendido = estado_cargas[carga].segundosEncendido + A;
        if (estado_cargas[carga].segundosEncendido == -1){
          estado_cargas[carga].segundosEncendido = 0;
        }
      }
      else if ((menu.get_focusedLine() == 4) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].horaEncendido[0] = estado_cargas[carga].horaEncendido[0] + A;
        if (estado_cargas[carga].horaEncendido[0] == -1){
          estado_cargas[carga].horaEncendido[0] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 5) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].minutoEncendido[0] = estado_cargas[carga].minutoEncendido[0] + A;
        if (estado_cargas[carga].minutoEncendido[0] == -1){
          estado_cargas[carga].minutoEncendido[0] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 6) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].horaEncendido[1] = estado_cargas[carga].horaEncendido[1] + A;
        if (estado_cargas[carga].horaEncendido[1] == -1){
          estado_cargas[carga].horaEncendido[1] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 7) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].minutoEncendido[1] = estado_cargas[carga].minutoEncendido[1] + A;
        if (estado_cargas[carga].minutoEncendido[1] == -1){
          estado_cargas[carga].minutoEncendido[1] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 8) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].horaEncendido[2] = estado_cargas[carga].horaEncendido[2] + A;
        if (estado_cargas[carga].horaEncendido[2] == -1){
          estado_cargas[carga].horaEncendido[2] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 9) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].minutoEncendido[2] = estado_cargas[carga].minutoEncendido[2] + A;
        if (estado_cargas[carga].minutoEncendido[2] == -1){
          estado_cargas[carga].minutoEncendido[2] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 10) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].horaEncendido[3] = estado_cargas[carga].horaEncendido[3] + A;
        if (estado_cargas[carga].horaEncendido[3] == -1){
          estado_cargas[carga].horaEncendido[3] = 0;
        }
      }
      else if ((menu.get_focusedLine() == 11) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        estado_cargas[carga].minutoEncendido[3] = estado_cargas[carga].minutoEncendido[3] + A;
        if (estado_cargas[carga].minutoEncendido[3] == -1){
          estado_cargas[carga].minutoEncendido[3] = 0;
        }
      } 

      menu.softUpdate();                            //Si voy a volver no tengo que actualizar, actualizo sólo aqui dentro

    }
    else if ((boton > 400) && (boton <= 600)) {     //Vuelve
      volver = true;
      if (menu.get_currentScreen() == &submenu_configurar_hora) {
        menu.change_screen(&menu_secundario);
      }
      else if (menu.get_currentScreen() == &submenu_configurar_encendidos) {
        menu.change_screen(&submenu_cargas);
      }
    }
    
    boton = 1023;

    /*Esta condición e IF a continuación necesarios para que no haya un error y se pulse una tecla y el programa se quede aqui 
    indefinidamente. Después de 5 minutos volveria al menú principal cortando la configuración de menús*/          
    
    if (millis() >= (tiempo_orden_teclado + espera_180s)) {
      volver = true;
    }
  
  } while (volver == false);

  volver = false;
}

void seleccionar_mono() {
  int boton;                              //Botón pulsado
  tiempo_orden_teclado = millis();        //Capturo el momento en el que entro a configurar variables
 
  lcd.setCursor(0,0);                     //Para simular que es una linea enfocada, sino confunde un poco al navegar por los menús
  lcd.write(byte(0));                     //Representa la flecha

  do{
    delay(200);               //Para evitar rebotes
    boton = analogRead (A0); 
    
    if ((boton > 700) && (boton <= 900) || (boton < 100)) {          //Si subo o bajo con la botonera hará lo mismo, cambiar de Sí a No
      if ((menu.get_focusedLine() == 0) && (menu.get_currentScreen() == &submenu_configurar_encendidos)) {
        if (estado_cargas[carga].seEnciende) {
          estado_cargas[carga].seEnciende = false;
          strcpy_P(monosilabo, no);
        }
        else {
          estado_cargas[carga].seEnciende = true;
          strcpy_P(monosilabo, si); 
        }
      }
      menu.softUpdate();                           //Si voy a volver no tengo que actualizar, actualizo sólo aqui dentro
    }
    else if ((boton > 400) && (boton <= 600)){     //Vuelve
      volver = true;                                  
    }

    boton = 1023;

    /*Esta condición e IF a continuación necesarios para que no haya un error y se pulse una tecla y el programa se quede aqui 
    indefinidamente. Después de 5 minutos volveria al menú principal cortando la configuración de menús*/    
    
    if (millis() >= (tiempo_orden_teclado + espera_180s)) {
      volver = true;
    }  
  } while (volver == false);

  volver = false;
}

void imprimir_hora(){
  int hora_anterior, minuto_anterior, segundo;
  
  DateTime now = rtc.now(); //get the current date-time
  hora_anterior = hora;
  minuto_anterior = minuto;
  hora = now.hour();
  minuto = now.minute();
  segundo = now.second();
  
  if (hora < 10) {
    posicion_texto_hora = 8;
  }
  else {
    posicion_texto_hora = 7;
  }
  if (minuto < 10) {
    texto_h = *texto_hora[1];
  }
  else {
    texto_h = *texto_hora[0];
  }
  if (((hora_anterior == 23) && (hora == 0)) || ((minuto_anterior == 59) && (minuto == 0)) || ((minuto_anterior == 9) && (minuto == 10))){
    menu.update();                              //Sólo actualizo la pantalla en estos casos
    //actualizar_hora = false;
  }/*
  if ((hora == 30) && (segundo == 0)) {
    actualizar_hora == true;                    //Cada media hora reseteo el valor para que se pueda actualizar la hora
  }*/
}

void setup() {
  
  //Serial.begin(9600);
  rtc.begin();
  lcd.init();
  lcd.backlight();
  strcpy_P(monosilabo, no);                    //Inicializo monosílabo

  /*PANTALLAS DEL MENÚ*/

  menu.add_screen(menu_principal2);
  menu.add_screen(menu_secundario);
  menu.add_screen(submenu_cargas);
  menu.add_screen(submenu_configurar_hora);
  menu.add_screen(submenu_configurar_encendidos);

  menu_secundario.add_line(menu_secundario_linea1);
  menu_secundario.add_line(menu_secundario_linea2);
  submenu_cargas.add_line(submenu_cargas_linea1);
  submenu_cargas.add_line(submenu_cargas_linea2);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos1);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos2);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos3);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos4);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos5);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos6);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos7);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos8);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos9);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos10);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos11);
  submenu_configurar_encendidos.add_line(submenu_configurar_encendidos12);
  submenu_configurar_hora.add_line(submenu_configurar_hora1);
  submenu_configurar_hora.add_line(submenu_configurar_minutos1);

  /*FUNCIONES EN LOS MENÚS*/

  menu_secundario_linea1.attach_function(1, orden_por_teclado);
  menu_secundario_linea2.attach_function(1, orden_por_teclado);
  submenu_cargas_linea1.attach_function(1, orden_por_teclado);
  submenu_cargas_linea2.attach_function(1, orden_por_teclado);
  submenu_configurar_encendidos1.attach_function(1, seleccionar_mono);
  submenu_configurar_encendidos2.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos3.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos4.attach_function(1, orden_por_teclado);
  submenu_configurar_encendidos5.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos6.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos7.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos8.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos9.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos10.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos11.attach_function(1, seleccionar_numero);
  submenu_configurar_encendidos12.attach_function(1, seleccionar_numero);
  submenu_configurar_hora1.attach_function(1, seleccionar_numero);
  submenu_configurar_minutos1.attach_function(1, seleccionar_numero);

  menu_secundario.set_focusPosition(Position::LEFT);
  submenu_cargas.set_focusPosition(Position::LEFT);
  submenu_configurar_encendidos.set_focusPosition(Position::LEFT);
  submenu_configurar_hora.set_focusPosition(Position::LEFT);

  submenu_configurar_hora1.set_decimalPlaces(0);
  submenu_configurar_minutos1.set_decimalPlaces(0);

  submenu_configurar_encendidos.set_displayLineCount(4);        //Número de líneas a mostrar del menú
  
  DateTime dt(2011, 11, 10, hora, minuto, 0, 5);
  rtc.setDateTime(dt); //Adjust date-time as defined 'dt' above
  menu.update();       //Presento la primera pantalla del menú
}

void loop() {
   
  imprimir_hora();

  menu.softUpdate();

  if (analogRead (A0) < 900){              //Si se pulsa cualquier tecla
    cambiar_pantalla_inferior();
    orden_por_teclado();                   //Se queda hasta que la configuración haya acabado y tenga orden de volver al menú principal
  }
}

Possibly over-writing changed information with original information. Only when the 0 or 1 changes, update the submenu information.

menu are something like:

submenu_cargas:
-> Cargas 1
Cargas 2

submenu_configurar_encendidos:
-> Carga programada: 1
Encendidos al dia: 2
Seg. encendido: 4
Dias encendido: 6
Hora encendido1: 8
Min. encendido1: 10
Hora encendido2: 12
Min. encendido2: 14
Hora encendido3: 16
Min. encendido3: 18
Hora encendido4: 20
Min. encendido4: 22

Depending on what carga / load I pick up, the values shown in submenu_configurar_encendido change (Cargas 1 is initialized with odd numbers, and Cargas 2 with even numbers), and once inside submenu_configurar_encendido the values in each line change dynamically, I can see how they increase or decrease according to the keyboard commands. Therefore, the screen must be updated if I want to see the change in the variables selected through the keyboard, for the same carga.

Something that this program has and that I don't like, is that it is called recursively to the function orden_por_teclado. Inside submenu_cargas I call the function orden_por_teclado and wait for an order by keyboard; when I receive it, I go to submenu_configurar_encendidos and enter again in orden_por_teclado to wait for the order, without having left the previous function, but I don't see another way to do it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.