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
}
}