
Buenas:
He adaptado el código a Arduino y compila.
Tratando con el lenguaje Arduino. Ejecuta bien. Tiene comportamientos no deseado. Si pulsas el Botón Enter, todo bien. Luego al seleccionar un menú e incluso antes, la flecha indicadora parpadea, como que hay un bucle y se refresca una y otra vez.
Si entras al submenú llamado > NOMBRE RELES, directamente se pone en > ATRÁS y sale del submenú y vuelve al menú principal.
Quiero averiguar o corregir este motivo.
Códigos en Arduino.
LCD_Menu_y_Submenu.ino:
Código: Seleccionar todo
// Include el código de la librería.
#include <LiquidCrystal.h>
// Inicializa la librería con sus pines indicados.
// RS, RW, Enable, D4, D5, D6, D7.
//LiquidCrystal lcd(8, NULL, 9, 4, 5, 6, 7);
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// Declarar a partir de aquí el lcd.
#include "MenuPrincipal.h"
// Pin 10 para saber que es luz de fondo.
//const byte LuzFondo = 10;
// Variables.
// Declarado pulsadores.
const byte ARRIBA PROGMEM = A1;
const byte ABAJO PROGMEM = A2;
const byte IZQUIERDA PROGMEM = A3;
const byte DERECHA PROGMEM = A4;
const byte ENTER PROGMEM = A5;
byte estadoBotonArriba = 0;
byte estadoBotonAbajo = 0;
byte estadoBotonIzquierda = 0;
byte estadoBotonDerecha = 0;
byte estadoBotonEnter = 0;
void setup()
{
Serial.begin(115200); // 115200
// La pantalla es de 20 caracteres y 4 filas.
lcd.begin(20, 4);
// Indicar luz de fondo como salida.
// pinMode(LuzFondo, OUTPUT);
// Configuración de pines como salidas digitales.
pinMode(13, OUTPUT);
// Configuración de pines como entradas digitales.
pinMode(ARRIBA, INPUT); // Arriba. A1.
pinMode(ABAJO, INPUT); // Abajo. A2.
pinMode(IZQUIERDA, INPUT); // Izquierda. A3.
pinMode(DERECHA, INPUT); // Derecha. A4.
pinMode(ENTER, INPUT); // Ok / Enter. A5.
lcd.clear(); // Borra la pantalla y su posición superior izquierda.
lcd.setCursor(0, 1); // Línea 2 del LCD.
lcd.print(F(" Pantalla principal ")); // Muestra título en la LCD.
}
void loop()
{
estadoBotonEnter = digitalRead(ENTER);
if (estadoBotonEnter == HIGH)
{
lcd.noCursor(); // Oculat cursor.
lcd.noBlink(); // Cursor no parpadeando.
Menu_Principal();
Serial.println(estadoBotonEnter);
}
delay(50); // Para mayor estabilidad entre lecturas.
}
MenuPrincipal.h:
Código: Seleccionar todo
#include "NombreReles.h"
void Menu_Principal()
{
// Contador de teclas y navegador.
byte opcion = 0;
bool salir = false;
const byte seleccionMenu PROGMEM = 8;
// Oculat cursor.
lcd.noCursor();
// Cursor no parpadeando.
lcd.noBlink();
// Limpiar pantalla.
lcd.clear();
do
{
//******************************************************************
// Dibujo el menú principal.
const String MENSAJES[] PROGMEM =
{
"** MENU PRINCIPAL **", // Posición 0.
" ESTADO PRINCIPAL ", // 1
" NOMBRE RELES ", // 2
" NOMBRE SENSORES ", // 3
" ENTRADA ANALOGICA ", // 4
" CONFIGURACION ", // 5
" ACERCA DE... ", // 6
" AYUDA ", // 7
" EXTRA ", // 8
" INICIO ", // 9
" ", // 10
">" // 11
};
switch (opcion)
{
case 0:
lcd.setCursor(0, 0); // Línea 1 del LCD.
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[1]); // > ESTADO PRINCIPAL
lcd.setCursor(0, 1);
lcd.print(MENSAJES[11]); // >
lcd.setCursor(0, 2);
lcd.print(MENSAJES[2]); // NOMBRE RELÉS
lcd.setCursor(0, 3);
lcd.print(MENSAJES[3]); // NOMBRE SENSORES
break;
case 1:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[1]); // ESTADO PRINCIPAL
lcd.setCursor(0, 2);
lcd.print(MENSAJES[2]); // > NOMBRE RELÉS
lcd.setCursor(0, 2);
lcd.print(MENSAJES[11]); // >
lcd.setCursor(0, 3);
lcd.print(MENSAJES[3]); // NOMBRE SENSORES
break;
case 2:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[1]); // ESTADO PRINCIPAL
lcd.setCursor(0, 2);
lcd.print(MENSAJES[2]); // NOMBRE RELÉS
lcd.setCursor(0, 3);
lcd.print(MENSAJES[3]); // > NOMBRE SENSORES
lcd.setCursor(0, 3);
lcd.print(MENSAJES[11]); // >
break;
case 3:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[4]); // > ENTRADA ANALÓGICA
lcd.setCursor(0, 1);
lcd.print(MENSAJES[11]); // >
lcd.setCursor(0, 2);
lcd.print(MENSAJES[5]); // CONFIGURACIÓN
lcd.setCursor(0, 3);
lcd.print(MENSAJES[6]); // ACERCA DE...
break;
case 4:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[4]); // ENTRADA ANALÓGICA
lcd.setCursor(0, 2);
lcd.print(MENSAJES[5]); // > CONFIGURACIÓN
lcd.setCursor(0, 2);
lcd.print(MENSAJES[11]); // >
lcd.setCursor(0, 3);
lcd.print(MENSAJES[6]); // ACERCA DE...
break;
case 5:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[4]); // ENTRADA ANALÓGICA
lcd.setCursor(0, 2);
lcd.print(MENSAJES[5]); // CONFIGURACIÓN
lcd.setCursor(0, 3);
lcd.print(MENSAJES[6]); // > ACERCA DE...
lcd.setCursor(0, 3);
lcd.print(MENSAJES[11]); // >
break;
case 6:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[7]); // > AYUDA
lcd.setCursor(0, 1);
lcd.print(MENSAJES[11]); // >
lcd.setCursor(0, 2);
lcd.print(MENSAJES[8]); // EXTRA
lcd.setCursor(0, 3);
lcd.print(MENSAJES[9]); // INICIO
break;
case 7:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[7]); // AYUDA
lcd.setCursor(0, 2);
lcd.print(MENSAJES[8]); // > EXTRA
lcd.setCursor(0, 2);
lcd.print(MENSAJES[11]); // >
lcd.setCursor(0, 3);
lcd.print(MENSAJES[9]); // INICIO
break;
case 8:
lcd.setCursor(0, 0);
lcd.print(MENSAJES[0]); // ** MENÚ PRINCIPAL **
lcd.setCursor(0, 1);
lcd.print(MENSAJES[7]); // AYUDA
lcd.setCursor(0, 2);
lcd.print(MENSAJES[8]); // EXTRA
lcd.setCursor(0, 3);
lcd.print(MENSAJES[9]); // > INICIO
lcd.setCursor(0, 3);
lcd.print(MENSAJES[11]); // >
break;
default:
Serial.print(F("Fuera de rango"));
break;
}
// Fin de pintar el menú principal.
//******************************************************************
// Leer pulsador ingresada por el usuario.
// Validar el tipo de pulsador.
if (digitalRead(A5) == HIGH)
{
switch (opcion)
{
case 0:
//
break;
case 1:
NombreReles_Principal();
break;
case 2:
//OpcionC();
break;
case 3:
//
break;
case 4:
//
break;
case 5:
//
break;
case 6:
//
break;
case 7:
//
break;
case 8:
return;
salir = true;
break;
default:
lcd.print(F("Fuera de rango. "));
break;
}
}
delay(50);
// Entonces si pulsas pulsador Abajo.
if (digitalRead(A2) == HIGH)
{
opcion++;
}
delay(50);
// Entonces si pulsas pulsador Arriba.
if (digitalRead(A1) == HIGH)
{
opcion--;
}
delay(50);
// Si está en la última opción, salta a la primera.
if (opcion > seleccionMenu)
{
opcion = 0;
}
// Si está en la primera posición, salta a la última.
if (opcion < 0)
{
opcion = seleccionMenu;
}
// Uso la tecla escape como salida.
} while (salir == false);
}
NombreReles.h:
Código: Seleccionar todo
// Variables.
byte coordenadaX = 0; // Coordenada X del textBox del nombre del Relé.
byte index = 0; // Índice de ATRAS y GUARDAR.
byte textBox = 0; // 0 para el número de Relé (de 1 al 8) y 1 para el texto del Relé (16 char).
String nombresDeLosReles[8]; // Líneas que al final se van a guardar en Archivo.txt.
bool cargado = false; // Vale false si todavía no se cargaron los nombres del Archivo, si no true, para no repetir.
// Caracteres alfanuméricos en el array.
const char ALFANUMERICO[] PROGMEM =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'ñ', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '-', '_', ':', ';', '¿',
'?', '(', ')', '[', ']', '{', '}', '<', '>', '=', '$', '&', '@', '\\', '/', '\"', ' '
};
// Índices de los caracteres de los 8 Relés para el array alfanumérico.
// Hay un total de 86 caracteres. Se cuenta desde el 0 al 85.
byte indiceArray[][16] =
{
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 },
{ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85 }
};
const char NUMERICO[] PROGMEM = { '1', '2', '3', '4', '5', '6', '7', '8' };
byte indiceNumerico = 0;
void MostrarLineaNombre()
{
lcd.setCursor(4, 1);
for (byte a = 0; a < 16; a++)
{
lcd.print(ALFANUMERICO[indiceArray[indiceNumerico][a]]);
}
}
void Inicio()
{
lcd.clear(); // Limpiar ventana.
lcd.setCursor(2, 0); // Posición del cursor.
lcd.print(F("Nombre de Reles: "));
lcd.setCursor(0, 3);
lcd.print(F(" ATRAS GUARDAR "));
//#########################################################################################
// Este código es de C#, ya lo pasaré a Arduino con su EEPROM interna o una tarjeta SD
// que también se puede leer archivo de texto tipo *.txt.
/*
if (cargado == false)
{
// ¿Existe el archivo de texto?
if (File.Exists("NombresReles.txt"))
{
// Supone un archivo con 8 lineas de 16 char completas aunque sea con espacios.
nombresDeLosReles = File.ReadAllLines("NombresReles.txt");
int a, b, c;
for (a = 0; a < 8; a++)
{
for (b = 0; b < 16; b++)
{
for (c = 0; nombresDeLosReles[a][b] != ALFANUMERICO[c]; c++)
{
;
}
indiceArray[a][b] = c;
}
}
}
cargado = true;
}
*/
if (cargado == false)
{
// Supone un archivo con 8 lineas de 16 char completas aunque sea con espacios.
// nombresDeLosReles = File.ReadAllLines("NombresReles.txt");
byte a, b, c;
for (a = 0; a < 8; a++)
{
for (b = 0; b < 16; b++)
{
for (c = 0; nombresDeLosReles[a][b] != ALFANUMERICO[c]; c++)
{
;
}
indiceArray[a][b] = c;
}
}
cargado = true;
}
//#########################################################################################
MostrarLineaNombre();
lcd.setCursor(2, 1);
lcd.print(NUMERICO[indiceNumerico]);
if (textBox == 0)
{
lcd.setCursor(2, 1);
}
else
{
lcd.setCursor(4 + coordenadaX, 1);
}
}
void NombreReles_Principal()
{
// ConsoleKey tecla, tecla2;
byte indice = 0;
Inicio();
while (true)
{
lcd.cursor(); // Mostrar cursor.
lcd.blink(); // Cursosr parpadeando.
//tecla = Console.ReadKey(true).Key;
// ¿Has pulsado tecla flecha arriba?
if (HIGH == digitalRead(A1)) // Sí.
{
if (textBox == 0)
{
lcd.setCursor(4, 1);
textBox = 1;
}
else // textBox == 1
{
if (coordenadaX < 15)
{
coordenadaX++;
lcd.setCursor(4 + coordenadaX, 1);
}
}
}
// Entonces. ¿Haz pulsado flecha izquierda?
else if (HIGH == digitalRead(A3)) // Sí.
{
if (textBox == 1)
{
if (coordenadaX > 0)
{
coordenadaX--;
lcd.setCursor(4 + coordenadaX, 1);
}
else
{
lcd.setCursor(2, 1);
textBox = 0;
}
}
}
// Entonces. ¿Haz pulsado flecha abajo?
else if (HIGH == digitalRead(A2)) // Sí.
{
if (textBox == 0)
{
indiceNumerico--;
if (indiceNumerico < 0)
{
indiceNumerico = 7;
}
lcd.setCursor(2, 1);
lcd.print(NUMERICO[indiceNumerico]);
MostrarLineaNombre();
lcd.setCursor(2, 1);
}
else // textBox == 1
{
indiceArray[indiceNumerico][coordenadaX]--;
if (indiceArray[indiceNumerico][coordenadaX] < 0)
{
indiceArray[indiceNumerico][coordenadaX] = 85;
}
lcd.print(ALFANUMERICO[indiceArray[indiceNumerico][coordenadaX]]);
lcd.setCursor(4 + coordenadaX, 1);
}
}
// Entonces. ¿Haz pulsado flecha arriba?
else if (HIGH == digitalRead(A1)) // Sí.
{
if (textBox == 0)
{
indiceNumerico++;
if (indiceNumerico >= 8)
{
indiceNumerico = 0;
}
lcd.setCursor(2, 1);
lcd.print(NUMERICO[indiceNumerico]);
MostrarLineaNombre();
lcd.setCursor(2, 1);
}
else // textBox == 1
{
indiceArray[indiceNumerico][coordenadaX]++;
if (indiceArray[indiceNumerico][coordenadaX] > 85) // Aquí es > 85 (o >= 86) porque 86 es la cantidad
{ // total y al alcanzarla ahí paso al comienzo (0).
indiceArray[indiceNumerico][coordenadaX] = 0;
}
lcd.print(ALFANUMERICO[indiceArray[indiceNumerico][coordenadaX]]);
lcd.setCursor(4 + coordenadaX, 1);
}
}
// Entonces. ¿Haz pulsado la tecla Enter?
else if (HIGH == digitalRead(A5)) // Sí.
{
lcd.cursor(); // Ocultar cursor.
lcd.noBlink(); // Sin parpadeos el cursor.
lcd.setCursor(0, 3);
lcd.print("> ATRAS GUARDAR ");
index = 0;
while (digitalRead(A5))
{
if ((HIGH == digitalRead(A4)) || (HIGH == digitalRead(A3)))
{
index = 1 - index; // Si vale 0 valdrá 1, si vale 1 valdrá 0.
lcd.setCursor(0, 3);
if (index == 0)
{
lcd.print(F("> ATRAS GUARDAR "));
}
else
{
lcd.print(F(" ATRAS > GUARDAR "));
}
}
}
if (index == 1) // Se pulsó Enter en Guardar.
{
nombresDeLosReles[8];
for (byte a = 0; a < 8; a++)
{
for (byte b = 0; b < 16; b++)
{
// nombresDeLosReles[a] += ALFANUMERICO[indiceArray[a][b]];
}
}
// Guardar archivo de texto con los nombres de los relés.
//File.WriteAllLines("NombresReles.txt", nombresDeLosReles);
// En esta parte, justo arriba se hace con el lenguaje de C#, aquí hay que usar la
// EEPROM interna de Arduino que haré más adelante.
// Puede que los nombres contengan espacios al final, que no se verán pero no
// hay que borrarlos porque al principio leerá 16 char y si faltan, fallará.
lcd.clear();
lcd.setCursor(2, 1);
lcd.print(F("Haz guardado:"));
lcd.setCursor(2, 3);
lcd.print((indice + 1));
lcd.setCursor(4, 3);
//lcd.print(nombresDeLosReles[indice]);
// Mientras no pulses la tecla Enter, sigue las demás intrucciones.
while (HIGH == digitalRead(A5))
{
// ¿Haz pulsado flecha arriba?
if (HIGH == digitalRead(A1)) // Sí. Ejecuta código dentro de ella.
{
indice--; // Decrementa la variable indice.
// ¿indice es menor que 0?
if (indice < 0) // Sí.
{
indice = 7;
}
}
// Entonces. ¿Haz pulsado flecha abajo?
else if (HIGH == digitalRead(A2)) // Sí.
{
indice++; // Incrementa la variable indice.
// ¿indice es mayor o igual que 8?
if (indice >= 8) // Sí.
{
indice = 0;
}
}
lcd.setCursor(2, 3);
lcd.print((indice + 1));
lcd.setCursor(4, 3);
lcd.print(nombresDeLosReles[indice]);
}
Inicio();
}
else if (index == 0)
{
break;
}
}
}
}
Compilar, compila bien.
¿Alguna idea?
Saludos.