Leer y escribir EEPROM

Hola bien:

Aún así, este código no está completo para Arduino ya que lo estoy adaptando de C#. Creé un archivo de texto tipo .txt donde almacene los nombres de los relés que puede ingresar con los botones.

En Arduino quiero usar la EEPROM interna donde guarda y lee datos, en este caso los nombres de los relés. Cuando tengo los nombres en memoria los guardo en la EEPROM, cuando arranco el Arduino, los lee automáticamente.

Aquí hay un ejemplo de una pieza de código.

Menú 04

Code Arduino.

// Variables.
int coordenadaX = 0;          // Coordenada X del textBox del nombre del Relé.
int index = 0;                // Índice de ATRAS y GUARDAR.
int 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.
char roALFANUMERICO[] =
{
  '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.
int roINDICE_ARRAY[][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 }
};

char roNUMERICO[] = { '1', '2', '3', '4', '5', '6', '7', '8' };
int roINDICE_NUMERICO = 0;

void MostrarLineaNombre()
{
  lcd.setCursor(4, 1);
  for (int a = 0; a < 16; a++)
  {
    lcd.print(roALFANUMERICO[roINDICE_ARRAY[roINDICE_NUMERICO][a]]);
  }
}

void Inicio()
{
  //Console.SetWindowSize(20, 5);                   // Establece el ancho y alto de la ventana.
  lcd.clear();                                // Limpiar ventana.
  lcd.setCursor(2, 0);                // Posición del cursor.
  lcd.print("Nombre de Reles:    ");
  lcd.setCursor(0, 3);
  lcd.print("  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] != roALFANUMERICO[c]; c++)
            {
              ;
            }
            roINDICE_ARRAY[a][b] = c;
          }
        }
      }
      cargado = true;
    }
  */
  //#########################################################################################

  MostrarLineaNombre();
  lcd.setCursor(2, 1);
  lcd.print(roNUMERICO[roINDICE_NUMERICO]);
  if (textBox == 0)
  {
    lcd.setCursor(2, 1);
  }
  else
  {
    lcd.setCursor(4 + coordenadaX, 1);
  }
}

void NombreReles_Principal()
{
//  ConsoleKey tecla, tecla2;
  int 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)
      {
        roINDICE_NUMERICO--;
        if (roINDICE_NUMERICO < 0)
        {
          roINDICE_NUMERICO = 7;
        }
        lcd.setCursor(2, 1);
        lcd.print(roNUMERICO[roINDICE_NUMERICO]);
        MostrarLineaNombre();
        lcd.setCursor(2, 1);
      }
      else // textBox == 1
      {
        roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX]--;
        if (roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX] < 0)
        {
          roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX] = 85;
        }
        lcd.print(roALFANUMERICO[roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX]]);
        lcd.setCursor(4 + coordenadaX, 1);
      }
    }
    // Entonces. ¿Haz pulsado flecha arriba?
    else if (HIGH == digitalRead(A1)) // Sí.
    {
      if (textBox == 0)
      {
        roINDICE_NUMERICO++;
        if (roINDICE_NUMERICO >= 8)
        {
          roINDICE_NUMERICO = 0;
        }
        lcd.setCursor(2, 1);
        lcd.print(roNUMERICO[roINDICE_NUMERICO]);
        MostrarLineaNombre();
        lcd.setCursor(2, 1);
      }
      else // textBox == 1
      {
        roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX]++;
        if (roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX] > 85)  // Aquí es > 85 (o >= 86) porque 86 es la cantidad
        {                                                         // total y al alcanzarla ahí paso al comienzo (0).
          roINDICE_ARRAY[roINDICE_NUMERICO][coordenadaX] = 0;
        }
        lcd.print(roALFANUMERICO[roINDICE_ARRAY[roINDICE_NUMERICO][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("> ATRAS     GUARDAR ");
          }
          else
          {
            lcd.print("  ATRAS   > GUARDAR ");
          }
        }
      }
      if (index == 1)  // Se pulsó Enter en Guardar.
      {
        nombresDeLosReles[8];
        for (int a = 0; a < 8; a++)
        {
          for (int b = 0; b < 16; b++)
          {
//            nombresDeLosReles[a] += roALFANUMERICO[roINDICE_ARRAY[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("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;
      }
    }
  }
}

Uy, @metaconta, hoy te has levantado con el chip torcido o es la costumbre, ¿postear en ingles en el foro español?

Código revisado del primer post.

¿Será ese el motivo, tras ser traducido, por el cual yo no encuentro la duda o pregunta? Pero si me apego al título, si la pregunta es cómo guardar y leer en la EEPROM ¿No es cosa de ver un tutorial o ejercicio? O si la duda es más concreta escrita no está.

Buenas camepones:

En el programa escrito en C#, en la consola con el teclado puedes escribir nombres de 16 caracteres de cada relé, son 8 relés en total. Se guarda en un archivo .txt, también se puede hacer en Arduino con la tarjeta SD pero lo haré con la EERPOM interna. No se hacer la mejor forma.

Lo que hace.

Escribes uno a uno el nombre de los relés con los pulsadores indicado aquí.

Por ejemplo, si pulsas guardar, se graba así los datos en txt.

Luz 1           
Luz 2           
Motor           
Ventilador      
Persiana 1      
Persiana 2      
Ventana 1       
Venanta 2       

Así quiero decir que que cada nombre guardado, automáticamente también se guarda los espacios en blanco, si elijes Motor, como son de 16 caracteres a guardar, también se guarda y lee los espacios en blanco, que contaría "Motor ". Tiene 5 letras más 11 espacios en blanco.

Es lo que no se hacer la mejor manera posible, que se guarde los datos y se recupere al iniciar.

Saludos.

Seguimos en lo de siempre, esto no es una duda concreta. Para guardar una variable se usa EEPROM.put() y para leerla EEPROM.get() y ambas funciones tienen dos parámetros.
El primero es el indice o posición de memoria donde se va a guardar el valor y el segundo es el tamaño ( sizeof() ) de dicho valor.

:slight_smile: Entiendo que cada cual programa cómo quiere, pero hablando sobre la mejor forma de hacer las cosas. Si necesitamos un listado de caracteres alfanuméricos con algunos símbolos y teniendo una tabla ASCII ¿Necesitas tres array y uno que incluya todo el abecedario en minúscula y mayúscula más números?

¿Y por qué tienen que ocupar paquetes de memoria de 16? ¿Por comodidad? No lo dices.

void setup(
{
  for( int i = 0 ; i< EEPROM.length() ; i++ ){
    //¿Pretendes leer paquetes cada X posiciones?
  } 
} 

Otra cuestión, olvídate de la 'Ñ' cómo char. Esto no es C#. Si quieres mostrar caracteres diferentes a los anglosajones en un display tienes que "dibujarlo"

pero repito, no hace falta meter el listado con cada caracter del alfabeto, sólo necesitamos los números de los rangos ASCII

Ejemplo de lo que digo:

void setup()
{
  Serial.begin(9600);
  byte alphanum[3][2] = {
    {48,57}, //números
    {65,90}, //letras mayus
    {97,122}, //letras min 
  };
  for(byte i = 0; i < ( sizeof(alphanum) / sizeof(alphanum[0]) ); i++){
    for( byte j = alphanum[i][0]; j < alphanum[i][1] ; j++){
    	Serial.println((char) j);
    }
  }
}

void loop(){}

Buenas camarada:

Frente a la pregunta:

¿Y por qué tienen que ocupar paquetes de memoria de 16? ¿Por comodidad? No lo dices.

Porque es lo máximo que cabe en el display de 20x4, es decir.
Menú 04

El primer díigo del LCD 20x4 el caracter es un espacio en blanco, luego está el 4, que es el nombre del relé número 4 y se selecciona pulsado ARRIBA y ABAJO, luego otro espacio en blanco y después los nombres que quieras añadir a los relés que son 16 caracteres como máximo respetando su espacio en blanco en lo demás que queda.

No sabía que Arduino también tiene la tabla ASCII para detectarlo, me habían dicho en otro sitio alguien por Internet que no se podía hacer y tube que hacerlo enC# como puse en el array. Bueno, ya está hecho y no importa.

En cuanto al código:

void setup(
{
  for( int i = 0 ; i< EEPROM.length() ; i++ ){
    //¿Pretendes leer paquetes cada X posiciones?
  } 
}

Me da que necesitas algo así como en C#, ya que tienes que leer 16 caracteres por 8 relés que hay.

Algo así:

                    // 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] != roALFANUMERICO[c]; c++)
                            {
                                ;
                            }
                            roINDICE_ARRAY[a][b] = c;
                        }
                    }

Voy a probar tus ideas haber que tal y si me sale.

Gracias por tu tiempo compañero.

PD: Puedo pasar la versión hecha hasta ahora y funcional en C# .Net 4.2 por si lo quieres probar.

lo suyo sería añadir los espacios extras obtenido el dato, no guardar espacios blancos en las variables y gastar más memoria ¿No?

No has entendido, el código que pongo es sólo un recorrido por la memoria de EEPROM y pregunto si quieres separar esta memoria en paquetes de 16.

De poco sirve C# para Arduino. El Entorno de C sharp, cómo .NET que es ,está más próximo a cualquier visual cómo aspx, etc, que a C++.
Es cómo si yo quisiera extrapolar un código de PHP OO y con array asociativos o un código en Phyton a un código hecho en Arduino. No será una simple modificación pese a la ¿"similitud"? en la sintaxis.

Para progresar en tu pregunta sólo estoy/estamos queriendo ver cómo planteas las cosas.
No hay nada sobre la EEPROM en el código. Tienes que tener la parte donde guardas los valores por defecto, la parte donde compruebas que exista esa información en la memoria, y el update de dicha memoria con cada pulsador.

Edito:
https://programarfacil.com/blog/arduino-blog/eeprom-arduino/

https://www.luisllamas.es/guardar-variables-entre-reinicios-con-arduino-y-la-memoria-no-volatil-eeprom/

Bueno, ahí va mi consejo.
Haz un struct

struct elementos{
  char nombre[15]; // ventana
  byte indice;            // 2
  bool estado;          //HIGH - LOW
};

De tal manera que tengas los nombres de los elementos; Ventana, persiana, motor... y luego el índice, aparte si van a ser Relés añades el estado.
Tienes un ejemplo de struct en EEPROM en el enlace de luisllamas.

Una vez hecho podrás ir de punto a punto en la memoria revisando cada "nombre" "índice" y "estado". Sigues sin necesitar rellenar espacios para escribir en un display, pero si tanto quieres esto tienes sprintf() o rellenar con un bucle...

Sé que estás obcecado con el array bidimensional porque en el ejercicio que tienes de C# concatenas la cadena en base a la lectura del fichero cómo si de un String se tratase, pero esto es Arduino con EEPROM y no C#

Se supone que una TFT o LCD con su correspondiente librería no vas a tener que añadir caracter a caracter. Repito, lo estás viendo desde el punto de vista de C#, no de un Arduino.

Quiero recordarles a todos aquellos que usan la EEPROM de sus arduinos que esta memoria tiene un límite de escrituras. Si tu proyecto va a requerir de estar constantemente modificando la EEPROM debes ser consciente que en algún punto se puede dañar y por tanto tu proyecto dejará de funcionar.

Si tu proyecto requiere un uso reiterado de sobreescrituras en una memoria, usa una memoria externa, por ejemplo con un módulo de tarjeta SD o microSD, pero no la EEPROM

Buenas.

La EERPOM no estará constantemente usándose en escritura, solo se usa guardar cuando escriba los nombres, al iniciar Arduino si es verdad que se lee la EEPROM. Lo de guardar datos es solo cuando uses oombre. Así no se gastará la EEPROM con el tiempo, en el sentido que dejará de funcionar como dices.

Saludos.

yo supongo que tu idea es que el sistema "recuerde" cómo deben estar los relés aunque el Arduino se apague o reinicie. Si fuese el caso sí que estarías sobreescribiendo la memoria.
En caso contrario, si sólo vas a guardar los nombres ¿Por qué usar la memoria EEPROM y no variables? Bueno si el ejercicio plantea hacerlo con EEPROM pues vale, pero es un poco extraño.

Buenas.

¿Qué tal?

Nunca se guarda los estados de los relés en la EEPROM. Solo los nombres de los relés. Ahí está el truco.

Como tiene mucha entradas y salidas, al final quitaré ARduino UNO y meteré otro, ya que necesito como mínimo 8 entradas digitales y 8 salidas digitales que son los relés. Tanto uno como en otro en digitales, no se guarda nada en la EEPROM, solo al introducir GUARDAR, donde se almacenan 8 nombres de los relés y 8 sensores como entrada.

Saludos.

Saludos.

Optimizado que antes me quitaba en la RAM 997 / 2048, ahora 671 / 2048.

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

Y la ventaja de poner algo asi en PROGMEM cual es?
Digo porque definir como const ocupa RAM pero al punto que esto valga la pena? Es mucho mas lento.

Falta la librería lcd. Este código no compila Metaconta.
Borro los errores porque no sumaba ponerlos.

Buenas:

Si no pongo const, me sale este error.

variable 'NUMERICO' must be const in order to be put into read-only section by means of 'attribute((progmem))'

const solo sin el PROGMEM, saldría en la RAM, con el PROGMEM, se va hacia la memoria Flash y ahorras RAM. Es más lento, para lo que lo uso, ni lo notas, en este caso, no molesta ni se siente.

No te compila porque solo puse el código o archivo .h.

Dejo el código completo.

*Archivo .ino:

// 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.
  pinMode(ABAJO, INPUT); // Abajo.
  pinMode(IZQUIERDA, INPUT); // Izquierda.
  pinMode(DERECHA, INPUT); // Derecha.
  pinMode(ENTER, INPUT); // Ok / Enter.

  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:

#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

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

Códigos hecho hasta ahora.

Me falta que me cuadre lo de guadar nombres y leerlo en la EEPROM. Solo falta ese código haber como lo cuajo. No olvidar que nada más encender Arduino, lo primero que lee es si hay algo escrito o guardado para poder mostralo en pantalla. Si no, hay que escribir mediante pulsadores los nombres, al menos un relé para hacer pruebas, los demás se guardan en espacios en blanco.

En Arduino hay dos problemas, todavía no he hecho lo de guardar la EERPOM ni leerlo. El mayor problema, cuando entro al menú principal en NOMBRE RELÉS, automáticamente sale a la pantalla principal del menú, antes eso hay que corregirlo y estoy en el limbo averiguando el motivo.

El ejemplo en C# y el esquema en Proteus lo puedo subir si lo desean.

Saludos.

No fue lo que te pregunté o mi pregunta fue mal formulada.
Yo pregunté para que una arreglo de números tan pequeño lo guardas en la flash frente a definirlo como constante usando RAM?

Este

const char NUMERICO[] PROGMEM = { '1', '2', '3', '4', '5', '6', '7', '8' };

frente a este

const char NUMERICO[] = { '1', '2', '3', '4', '5', '6', '7', '8' };

No te había entendido bien.

Lo hago así porque se la que me espera en el consumo de la RAM, el menú y submenú es un poco grande que todavía aquí no lo he mostrado, poco a poco lo haré. Así que ahorraré RAM a toda costa.

2048 Bytes parece mucho, para lo queyo lo quiero no. O usas otro microcontrolador con más RAM o usas SRAM externa.

Una cosa que no me trago, es si declaro esto en el archivo principal de ARduino.

HIGH == digitalRead(ABAJO);

¿Por qué en otros archivos .h no me funciona como el código de arriba y tengo que ponerlo como indica abajo?

HIGH == digitalRead(A2)