Was not declared in this scope

Hola.
Dos cosas como preambulo:

  • Este es mi primer post, asi que empiezo pidiendo excusas si no lo hago bien del todo.
  • Soy totalmente autodidacta en programacion, eso si....desde hace mas de 40 años con Basic, TurboBasic y Turbo Pacal. Con Arduino llevo como 4 años tomandolo y dejandol.

Obtengo ese error al compilar. Se trata de una llamada a una funcion que me permite modificar los colores en un TFT girando un codificador rotativo. Todo funcionaba perfectamente hasta que he creado la funcion y he hecho la llamada.
Hay 5 colores a modificar en la aplicacion y cada uno con su funcion y con esta nueva funcion quiero poderlos modificar todos pasandole los prametros correspondientes.

La funcion:

void modificaVariableAspecto(String titulo,                    //titulo del menu
                             unsigned short *variableAspecto,  //variable cuyo valor se va a modificar
                             String nombreColor[],             //nombres de los colores
                             unsigned short claveColor[],      //valores de color
                             unsigned short dirEEPROM)         //direccion EEPROM donde se almcena la variable
{

  pulse = LOW;
  int numIndice;

  int POSICIONActual = 0;
  int r;

  for (r = 0; r < 104; r++) {
    if (claveColor[r] == *variableAspecto) {
      numIndice = r;
      r = 104;
    }
  }

  String opciones[] = { "  ", "  ", "Seleccione Color...." };
  int maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
  dibujaPantalla(titulo, opciones, maxOpciones);
  marcoSeleccion(opciones[2], 2, 3);

  POSICION = numIndice;
  POSICIONActual = numIndice;
  tft.setTextColor(txtMenu, fondoPantalla);
  tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
  do {
    if (POSICION != POSICIONActual) {
      if (POSICION > POSICIONActual) { numIndice++; }
      if (POSICION < POSICIONActual) { numIndice--; }
      if (POSICION > 104) { POSICION = 0; }
      if (POSICION < 0) { POSICION = 104; }

      POSICIONActual = POSICION;
      *variableAspecto = claveColor[POSICION];

      String opciones[] = { "  ", "  ", "Seleccione Color...." };
      maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
      dibujaPantalla(titulo, opciones, maxOpciones);
      tft.setTextColor(txtMenu, TFT_BLACK);
      tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
      tft.setTextColor(txtMenu, fondoPantalla);
      marcoSeleccion(opciones[2], 2, 3);
    }
  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir

  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  EEPROM.writeUShort(dirEEPROM, fondoTitMenu);
  EEPROM.commit();
}

Y la llamada donde da el error:

case 2:  //FONDO PANTALLA
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          modificaVariableAspecto("FONDO PANTALLA",      //titulo del menu
                                  &fondoPantalla,        //puntero a variable cuyo valor se va a modificar
                                  nombreColor,           //nombres de los colores
                                  claveColor,            //valores de color
                                  dirMemFondoPantalla);  //direccion EEPROM del vaalor para color fondo de pantaalla
        }
        break;

Y el mensaje de error:

C:\Users\phent\OneDrive\Documentos\Arduino\SPI_ESP32_Master_copy_20250201192029\SPI_ESP32_Master_copy_20250201192029.ino: In function 'void menuAspecto()':
C:\Users\phent\OneDrive\Documentos\Arduino\SPI_ESP32_Master_copy_20250201192029\SPI_ESP32_Master_copy_20250201192029.ino:263:11: error: 'modificaVariableAspecto' was not declared in this scope
  263 | 
      |           ^                      

exit status 1

Compilation error: 'modificaVariableAspecto' was not declared in this scope

Error editado por Moderador

Gracias anticipadas. Por la ayuda y la paciencia.

Esto dice "el error está en este archivo (.INO), en esta línea (263), a partir de este carácter (11)"

Deberá mostrar el boceto completo.

No has publicado todo el código, solo has publicado la rutina modificaVariableAspecto.

Moderador
Cuando publicas el error debe ir tambien con etiquetas de código, asi que edita por favor.
Por lo demás bien.
SIempre publica todo el código no lo que tu crees que es responsable del problema, porque si fuera eso lo hubieras resuelto por tu cuenta no?
Nosotros tenemos que ver todo lo que estas usando y haciendo.
Gracias.

El codigo completo:

#include <SoftwareSerial.h>
#include <EEPROM.h>
#include <ESP32Servo.h>

#include "Free_Fonts.h"  // Include the header file attached to this sketch
#include "TFT_eSPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

//#define anchoTFT ILI9341_TFTWIDTH  //240  ///< ILI9341 max TFT width
//#define altoTFT ILI9341_TFTHEIGHT  //320 ///< ILI9341 max TFT height
//#define centroXTFT anchoTFT / 2
//#define centroYTFT altoTFT / 2

#define TFT_DC 26
#define TFT_CS 5
#define pinBrilloTFT 22  //pin control iluminacion posterior display TFT

#define pinServoAlabeo 13
#define pinServoDireccion 2
#define pinServoRadiador 4

#define DTencoder 33   //variable DTencoder a pin digital 33 (DT en codificador rotativo)
#define CLKencoder 25  //variable CLKencoder a pin digital 25 (CLK en codificador rotativo)
#define pinButton 32   //boton codificador rotativ

#define TXpin 17  //para comunicacion serie
#define RXpin 16
SoftwareSerial miSerial1(RXpin, TXpin);

volatile int pulse = 0;  //varible controlada por la interrupcion 3

//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
TFT_eSPI tft = TFT_eSPI();

Servo servoAlabeo, servoDireccion, servoRadiador;

//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);


int POSservoAlabeo = 94;  //valor de servoAlabeo en posicion neutra
int POSservoDireccion = 90;
int POSservoRadiador = 40;  //40 es cerrado y 180 abierto

int ANTERIOR = 92;  // almacena valor anterior de la variable POSICION

volatile int POSICION = 4;  // variable POSICION con valor inicial de 4 y definida como global al ser usada en loop e ISR (encoder)

int guardaANTERIOR;
int guardaPOSICION;

int datoSerie1;
int valorActual;

bool blancasF = LOW,  //interruptor para blancas fijas
  blancasI = LOW,     //interruptor para blancas intermitentes
  blancasA = LOW,     //interruptor para blancas alternas
  navF = LOW,         //interruptor para luces navegacion fijas
  navA = LOW;         //interruptor para luces navegacion intermitentes
                      //provBool=LOW;

//String comando;
int comandoLuces = 0;
/*
#define BF "1"       //clave blancas fijs
#define BI "2"       //clave blancas intermitentes
#define BA "3"       //clave blancas alternas
#define BDON "4"     //clave blanca derechaencendida
#define BDOF "5"     //clave blanca derecha apagada
#define BION "6"     //clave blanca izquierda encendida
#define BIOF "7"     //clave blanca izquierda apagada
#define NF "8"       //clave navegacion fijas
#define NI "9"       //clave navegacion intermitentes
#define VON "10"     //clave verde encendida
#define VOF "11"     //clave verde apgadaa
#define RON "12"     //clave roja encendida
#define ROF "13"     //clave roja apgadaa 
*/
/*
const int BDON= 1;     //clave blanca derechaencendida
const int BDOF= 2;     //clave blanca derecha apagada
const int BION= 3;     //clave blanca izquierda encendida
const int BIOF= 4;     //clave blanca izquierda apagada

const int VON= 5;     //clave verde encendida
const int VOF= 6;     //clave verde apgadaa
const int RON= 7;     //clave roja encendida
const int ROF= 8;     //clave roja apgadaa 
*/

#define dirMemBrillo 0  //DIRECCION DE MEMORIA DONDE SE GUARDA EL BRILLO DE PANTALLA
byte brillo;
#define dirMemFondoPantalla 1  //DIRECCION DE MEMORIA DONDE SE GUARDA EL COLOR DE FONDO DE PANTALLA (2 bytes)
unsigned short fondoPantalla;
#define dirMemTituloMenu 3  //DIRECCION DE MEMORIA DONDE SE GUARDA EL COLOR DEL TITULO DE LOS MENUS (2 bytes)
unsigned short tituloMenu;
#define dirMemFondoTitMenu 5  //DIRECCION DE MEMORIA DONDE SE GUARDA EL COLOR DE FONDO DEl TITULO DE LOS MENUS (2 bytes)
unsigned short fondoTitMenu;
#define dirMemTxtMenu 7  //DIRECCION DE MEMORIA DONDE SE GUARDA EL COLOR DEL TEXTO DE LAS OPCIONES DE LOS MENUS (2 bytes)
unsigned short txtMenu;
#define dirMemFondoBarraEstado 9  //DIRECCION DE MEMORIA DONDE SE GUARDA EL COLOR DE FONDO DE LA BARRA DE ESTADO (2 bytes)
unsigned short fondoBarraEstado;
#define dirMemPrimerInicio 11
bool primerInicio = false;

void setup() {

  Serial.begin(38400);
  miSerial1.begin(74880);  //Puerto Comunicacion con Esclavo.
  EEPROM.begin(512);
  SPI.begin();
  tft.begin();

  pinMode(DTencoder, INPUT);   // A como entrada
  pinMode(CLKencoder, INPUT);  // B como entrada
  pinMode(pinButton, INPUT);

  pinMode(RXpin, INPUT);
  pinMode(TXpin, OUTPUT);

  pinMode(pinBrilloTFT, OUTPUT);

  //inicializa servos

  servoAlabeo.attach(pinServoAlabeo);        // attaches the servo Alabeo on pin 13 to the servo object
  servoDireccion.attach(pinServoDireccion);  //servoDireccion a pin 26
  servoRadiador.attach(pinServoRadiador);
  delay(50);  //servoRadiador a pin 23
              //posiciona servos dando medio segundo a cada uno para que se posicione
  servoAlabeo.write(POSservoAlabeo);
  delay(50);
  servoDireccion.write(POSservoDireccion);
  delay(500);
  servoRadiador.write(POSservoRadiador);
  delay(50);
  //desconecta servos. Se reconectan individualmente desde las rutinas que los necesitan
  servoAlabeo.detach();
  servoDireccion.detach();
  servoRadiador.detach();

  attachInterrupt(DTencoder, encoder, RISING);    // interrupcion sobre pin DTencoder con funcion ISR encoder y modo RISING
  attachInterrupt(pinButton, swEncoder, RISING);  // interrupcion sobre pin pinButton  con funcion ISR swEncoder y modo RISING

  tft.setRotation(2);
  tft.setTextDatum(TC_DATUM);  // Top centre
  tft.setFreeFont(FF17);       // Select the font

}  //FIN DEL SETUP


/*******************************************************************************************/
void loop() {  //////////////////////////////////////

  //menuLuces();
  //ConfiguracionInicial();

  menuInicial();

}  //fin del loop

/***********************************************************************************/
void ConfiguracionInicial() {

  if (primerInicio == true) {
    EEPROM.writeByte(dirMemBrillo, 66);
    EEPROM.writeUShort(dirMemFondoPantalla, TFT_BLACK);
    EEPROM.writeUShort(dirMemTituloMenu, TFT_BLACK);
    EEPROM.writeUShort(dirMemFondoTitMenu, TFT_GOLD);
    EEPROM.writeUShort(dirMemTxtMenu, TFT_WHITE);
    EEPROM.writeUShort(dirMemFondoBarraEstado, TFT_LIGHTGREY);
    EEPROM.writeBool(dirMemPrimerInicio, false);
    EEPROM.commit();
  }

  brillo = EEPROM.readByte(dirMemBrillo);
  fondoPantalla = EEPROM.readUShort(dirMemFondoPantalla);
  tituloMenu = EEPROM.readUShort(dirMemTituloMenu);
  fondoTitMenu = EEPROM.readUShort(dirMemFondoTitMenu);
  txtMenu = EEPROM.readUShort(dirMemTxtMenu);
  fondoBarraEstado = EEPROM.readUShort(dirMemFondoBarraEstado);
  primerInicio = EEPROM.readBool(dirMemPrimerInicio);
  analogWrite(pinBrilloTFT, brillo);
}

/******************************************************************************/
void menuAspecto() {

  String nombreColor[] = { "TFT_BLACK", "TFT_ORANGE", "TFT_CHOCOLATE", "TFT_SIENNA", "TFT_SADDLEBROWN", "TFT_SANDYBROWN", "TFT_DARKSALMON", "TFT_TAN", "TFT_PERU",
                           "TFT_GOLDENROD", "TFT_DARKGOLDENROD", "TFT_PALEGOLDENROD", "TFT_KHAKI", "TFT_YELLOW", "TFT_GOLD", "TFT_NAVAJOWHITE", "TFT_BURLYWOOD", "TFT_DARKKHAKI", "TFT_GREENYELLOW",
                           "TFT_YELLOWGREEN", "TFT_LIGHTGREEN", "TFT_MEDIUMSPRINGGREEN", "TFT_SPRINGGREEN", "TFT_MEDIUMSEAGREEN", "TFT_PALEGREEN", "TFT_LIMEGREEN", "TFT_LIME", "TFT_DARKSEAGREEN",
                           "TFT_LAWNGREEN", "TFT_OLIVEDRAB", "TFT_OLIVE", "TFT_DARKOLIVEGREEN", "TFT_SEAGREEN", "TFT_FORESTGREEN", "TFT_GREEN", "TFT_DARKGREEN", "TFT_POWDERBLUE", "TFT_LIGHTBLUE", "TFT_SKYBLUE",
                           "TFT_LIGHTSTEELBLUE", "TFT_PALETURQUOISE", "TFT_LIGHTSKYBLUE", "TFT_AQUAMARINE", "TFT_MEDIUMSLATEBLUE", "TFT_LIGHTSLATEGRAY", "TFT_SLATEGRAY", "TFT_SLATEBLUE",
                           "TFT_MEDIUMAQUAMARINE", "TFT_CORNFLOWERBLUE", "TFT_CADETBLUE", "TFT_MEDIUMTURQUOISE", "TFT_DARKSLATEBLUE", "TFT_INDIGO", "TFT_TURQUOISE", "TFT_STEELBLUE",
                           "TFT_ROYALBLUE", "TFT_LIGHTSEAGREEN", "TFT_DODGERBLUE", "TFT_MIDNIGHTBLUE", "TFT_CYAN", "TFT_DARKTURQUOISE", "TFT_DEEPSKYBLUE", "TFT_DARKCYAN", "TFT_TEAL", "TFT_BLUE",
                           "TFT_MEDIUMBLUE", "TFT_DARKBLUE", "TFT_NAVY", "TFT_HOTPINK", "TFT_DEEPPINK", "TFT_DARKMAGENTA", "TFT_MAGENTA", "TFT_PURPLE", "TFT_THISTLE", "TFT_PLUM", "TFT_ORCHID",
                           "TFT_MEDIUMORCHID", "TFT_DARKORCHID", "TFT_MEDIUMPURPLE", "TFT_PALEVIOLETRED", "TFT_MEDIUMVIOLETRED", "TFT_ROSYBROWN", "TFT_DARKGRAY", "TFT_DARKVIOLET",
                           "TFT_BLUEVIOLET", "TFT_PEACHPUFF", "TFT_PINK", "TFT_LIGHTCORAL", "TFT_INDIANRED", "TFT_SALMON", "TFT_CORAL", "TFT_TOMATO", "TFT_RED", "TFT_FIREBRICK", "TFT_BROWN",
                           "TFT_DARKRED", "TFT_MAROON", "TFT_WHITE", "TFT_BISQUE", "TFT_MOCCASIN", "TFT_LIGHTGREY", "TFT_SILVER", "TFT_GRAY", "TFT_DIMGRAY", "TFT_DARKSLATEGRAY" };

  unsigned short claveColor[] = { TFT_BLACK, TFT_ORANGE, TFT_CHOCOLATE, TFT_SIENNA, TFT_SADDLEBROWN, TFT_SANDYBROWN, TFT_DARKSALMON, TFT_TAN, TFT_PERU, TFT_GOLDENROD,
                                  TFT_DARKGOLDENROD, TFT_PALEGOLDENROD, TFT_KHAKI, TFT_YELLOW, TFT_GOLD, TFT_NAVAJOWHITE, TFT_BURLYWOOD, TFT_DARKKHAKI, TFT_GREENYELLOW, TFT_YELLOWGREEN, TFT_LIGHTGREEN,
                                  TFT_MEDIUMSPRINGGREEN, TFT_SPRINGGREEN, TFT_MEDIUMSEAGREEN, TFT_PALEGREEN, TFT_LIMEGREEN, TFT_LIME, TFT_DARKSEAGREEN, TFT_LAWNGREEN, TFT_OLIVEDRAB, TFT_OLIVE,
                                  TFT_DARKOLIVEGREEN, TFT_SEAGREEN, TFT_FORESTGREEN, TFT_GREEN, TFT_DARKGREEN, TFT_POWDERBLUE, TFT_LIGHTBLUE, TFT_SKYBLUE, TFT_LIGHTSTEELBLUE, TFT_PALETURQUOISE,
                                  TFT_LIGHTSKYBLUE, TFT_AQUAMARINE, TFT_MEDIUMSLATEBLUE, TFT_LIGHTSLATEGRAY, TFT_SLATEGRAY, TFT_SLATEBLUE, TFT_MEDIUMAQUAMARINE, TFT_CORNFLOWERBLUE, TFT_CADETBLUE,
                                  TFT_MEDIUMTURQUOISE, TFT_DARKSLATEBLUE, TFT_INDIGO, TFT_TURQUOISE, TFT_STEELBLUE, TFT_ROYALBLUE, TFT_LIGHTSEAGREEN, TFT_DODGERBLUE, TFT_MIDNIGHTBLUE, TFT_CYAN,
                                  TFT_DARKTURQUOISE, TFT_DEEPSKYBLUE, TFT_DARKCYAN, TFT_TEAL, TFT_BLUE, TFT_MEDIUMBLUE, TFT_DARKBLUE, TFT_NAVY, TFT_HOTPINK, TFT_DEEPPINK, TFT_DARKMAGENTA, TFT_MAGENTA,
                                  TFT_PURPLE, TFT_THISTLE, TFT_PLUM, TFT_ORCHID, TFT_MEDIUMORCHID, TFT_DARKORCHID, TFT_MEDIUMPURPLE, TFT_PALEVIOLETRED, TFT_MEDIUMVIOLETRED, TFT_ROSYBROWN, TFT_DARKGRAY,
                                  TFT_DARKVIOLET, TFT_BLUEVIOLET, TFT_PEACHPUFF, TFT_PINK, TFT_LIGHTCORAL, TFT_INDIANRED, TFT_SALMON, TFT_CORAL, TFT_TOMATO, TFT_RED, TFT_FIREBRICK, TFT_BROWN, TFT_DARKRED,
                                  TFT_MAROON, TFT_WHITE, TFT_BISQUE, TFT_MOCCASIN, TFT_LIGHTGREY, TFT_SILVER, TFT_GRAY, TFT_DIMGRAY, TFT_DARKSLATEGRAY };


  pulse = LOW;
  int opcion = 1;
  bool marco;
  int maxOpciones;

  String opcionesMenu[] = { "Brillo", "Fondo Pantalla", "Titulo Menu", "Fondo Titulo", "Texto Menu", "Fondo Barra Estado", "Atras" };
  maxOpciones = sizeof(opcionesMenu) / sizeof(opcionesMenu[0]);

  guardaPOSICION = POSICION;
  POSICION = 1;

  tft.setFreeFont(FF22);
  tft.setTextColor(tituloMenu, fondoTitMenu);

  String titulo = "ASPECTO";
  marco = 1;

  dibujaPantalla(titulo, opcionesMenu, maxOpciones);

  tft.setFreeFont(FF17);
  tft.setTextColor(txtMenu, fondoPantalla);

  dibujaZonaTestigos();
  //testigosLucesOF();

  do {

    if (POSICION > maxOpciones) { POSICION = 1; }
    if (POSICION < 1) { POSICION = maxOpciones; }
    opcion = POSICION;

    switch (opcion) {

      case 1:  //BRILLO
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;

          guardaPOSICION = POSICION;  //guarda valor de POSICION
          configuraBrillo();
          POSICION = guardaPOSICION;
        }
        break;

      case 2:  //FONDO PANTALLA
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          //configuraFondoPantalla();
          modificaVariableAspecto("FONDO PANTALLA",      //titulo del menu
                                  &fondoPantalla,        //puntero a variable cuyo valor se va a modificar
                                  nombreColor,           //nombres de los colores
                                  claveColor,            //valores de color
                                  dirMemFondoPantalla);  //direccion EEPROM del vaalor para color fondo de pantaalla
        }
        break;

      case 3:  //TITULO MENU
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          colorTituloMenu();
        }
        break;

      case 4:  //FONDO TITULO
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          colorFondoTituloMenu();
        }
        break;
      case 5:  // TEXTO MENU
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;

          POSICION = guardaPOSICION;
          menuInicial();
        }
        break;

      case 6:  //FONDO BARRA ESTADO
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;

          POSICION = guardaPOSICION;
          menuInicial();
        }
        break;

      case 7:  // ATRAS
        for (int r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          POSICION = guardaPOSICION;
          menuInicial();
        }
        break;

      default:
        if (POSICION > 8) { POSICION = 1; }
        if (POSICION < 1) { POSICION = 8; }
    }

  } while (pulse == LOW);
}

/******************************************************************************/
unsigned short colorDeContraste(uint16_t colorInicial) {

  uint8_t r = (colorInicial >> 11) & 0x1F;  // Extraer rojo
  uint8_t g = (colorInicial >> 5) & 0x3F;   // Extraer verde
  uint8_t b = colorInicial & 0x1F;          // Extraer azul

  // Convertir a RGB888
  r = (r << 3) | (r >> 2);  // Expandir a 8 bits
  g = (g << 2) | (g >> 4);  // Expandir a 8 bits
  b = (b << 3) | (b >> 2);  // Expandir a 8 bits

  uint8_t contrast_r = 255 - r;
  uint8_t contrast_g = 255 - g;
  uint8_t contrast_b = 255 - b;

  uint16_t contrast_rgb565 = ((contrast_r >> 3) << 11) | ((contrast_g >> 2) << 5) | (contrast_b >> 3);

  return contrast_rgb565;
}

/*******************************************************************************************/
void modificaVariableAspecto(String titulo,                    //titulo del menu
                             unsigned short *variableAspecto,  //variable cuyo valor se va a modificar
                             String nombreColor[],             //nombres de los colores
                             unsigned short claveColor[],      //valores de color
                             unsigned short dirEEPROM)         //direccion EEPROM donde se almcena la variable
{

  pulse = LOW;
  int numIndice;

  int POSICIONActual = 0;
  int r;

  for (r = 0; r < 104; r++) {
    if (claveColor[r] == *variableAspecto) {
      numIndice = r;
      r = 104;
    }
  }

  //String titulo = "FONDO TITULO";
  String opciones[] = { "  ", "  ", "Seleccione Color...." };
  int maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
  dibujaPantalla(titulo, opciones, maxOpciones);
  marcoSeleccion(opciones[2], 2, 3);

  POSICION = numIndice;
  POSICIONActual = numIndice;
  tft.setTextColor(txtMenu, fondoPantalla);
  tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
  do {
    if (POSICION != POSICIONActual) {
      //if (POSICION > POSICIONActual) { fondoTitMenu++; }
      //if (POSICION < POSICIONActual) { fondoTitMenu--; }
      if (POSICION > POSICIONActual) { numIndice++; }
      if (POSICION < POSICIONActual) { numIndice--; }
      if (POSICION > 104) { POSICION = 0; }
      if (POSICION < 0) { POSICION = 104; }

      POSICIONActual = POSICION;
      *variableAspecto = claveColor[POSICION];

      //titulo = "FONDO TITULO";
      String opciones[] = { "  ", "  ", "Seleccione Color...." };
      maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
      dibujaPantalla(titulo, opciones, maxOpciones);
      tft.setTextColor(txtMenu, TFT_BLACK);
      tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
      tft.setTextColor(txtMenu, fondoPantalla);
      marcoSeleccion(opciones[2], 2, 3);
    }
  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir

  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  EEPROM.writeUShort(dirEEPROM, fondoTitMenu);
  EEPROM.commit();
  //menuAspecto();
}


/*******************************************************************************************/
void colorFondoTituloMenu() {

  String nombreColor[] = { "TFT_BLACK", "TFT_ORANGE", "TFT_CHOCOLATE", "TFT_SIENNA", "TFT_SADDLEBROWN", "TFT_SANDYBROWN", "TFT_DARKSALMON", "TFT_TAN", "TFT_PERU",
                           "TFT_GOLDENROD", "TFT_DARKGOLDENROD", "TFT_PALEGOLDENROD", "TFT_KHAKI", "TFT_YELLOW", "TFT_GOLD", "TFT_NAVAJOWHITE", "TFT_BURLYWOOD", "TFT_DARKKHAKI", "TFT_GREENYELLOW",
                           "TFT_YELLOWGREEN", "TFT_LIGHTGREEN", "TFT_MEDIUMSPRINGGREEN", "TFT_SPRINGGREEN", "TFT_MEDIUMSEAGREEN", "TFT_PALEGREEN", "TFT_LIMEGREEN", "TFT_LIME", "TFT_DARKSEAGREEN",
                           "TFT_LAWNGREEN", "TFT_OLIVEDRAB", "TFT_OLIVE", "TFT_DARKOLIVEGREEN", "TFT_SEAGREEN", "TFT_FORESTGREEN", "TFT_GREEN", "TFT_DARKGREEN", "TFT_POWDERBLUE", "TFT_LIGHTBLUE", "TFT_SKYBLUE",
                           "TFT_LIGHTSTEELBLUE", "TFT_PALETURQUOISE", "TFT_LIGHTSKYBLUE", "TFT_AQUAMARINE", "TFT_MEDIUMSLATEBLUE", "TFT_LIGHTSLATEGRAY", "TFT_SLATEGRAY", "TFT_SLATEBLUE",
                           "TFT_MEDIUMAQUAMARINE", "TFT_CORNFLOWERBLUE", "TFT_CADETBLUE", "TFT_MEDIUMTURQUOISE", "TFT_DARKSLATEBLUE", "TFT_INDIGO", "TFT_TURQUOISE", "TFT_STEELBLUE",
                           "TFT_ROYALBLUE", "TFT_LIGHTSEAGREEN", "TFT_DODGERBLUE", "TFT_MIDNIGHTBLUE", "TFT_CYAN", "TFT_DARKTURQUOISE", "TFT_DEEPSKYBLUE", "TFT_DARKCYAN", "TFT_TEAL", "TFT_BLUE",
                           "TFT_MEDIUMBLUE", "TFT_DARKBLUE", "TFT_NAVY", "TFT_HOTPINK", "TFT_DEEPPINK", "TFT_DARKMAGENTA", "TFT_MAGENTA", "TFT_PURPLE", "TFT_THISTLE", "TFT_PLUM", "TFT_ORCHID",
                           "TFT_MEDIUMORCHID", "TFT_DARKORCHID", "TFT_MEDIUMPURPLE", "TFT_PALEVIOLETRED", "TFT_MEDIUMVIOLETRED", "TFT_ROSYBROWN", "TFT_DARKGRAY", "TFT_DARKVIOLET",
                           "TFT_BLUEVIOLET", "TFT_PEACHPUFF", "TFT_PINK", "TFT_LIGHTCORAL", "TFT_INDIANRED", "TFT_SALMON", "TFT_CORAL", "TFT_TOMATO", "TFT_RED", "TFT_FIREBRICK", "TFT_BROWN",
                           "TFT_DARKRED", "TFT_MAROON", "TFT_WHITE", "TFT_BISQUE", "TFT_MOCCASIN", "TFT_LIGHTGREY", "TFT_SILVER", "TFT_GRAY", "TFT_DIMGRAY", "TFT_DARKSLATEGRAY" };

  unsigned short claveColor[] = { TFT_BLACK, TFT_ORANGE, TFT_CHOCOLATE, TFT_SIENNA, TFT_SADDLEBROWN, TFT_SANDYBROWN, TFT_DARKSALMON, TFT_TAN, TFT_PERU, TFT_GOLDENROD,
                                  TFT_DARKGOLDENROD, TFT_PALEGOLDENROD, TFT_KHAKI, TFT_YELLOW, TFT_GOLD, TFT_NAVAJOWHITE, TFT_BURLYWOOD, TFT_DARKKHAKI, TFT_GREENYELLOW, TFT_YELLOWGREEN, TFT_LIGHTGREEN,
                                  TFT_MEDIUMSPRINGGREEN, TFT_SPRINGGREEN, TFT_MEDIUMSEAGREEN, TFT_PALEGREEN, TFT_LIMEGREEN, TFT_LIME, TFT_DARKSEAGREEN, TFT_LAWNGREEN, TFT_OLIVEDRAB, TFT_OLIVE,
                                  TFT_DARKOLIVEGREEN, TFT_SEAGREEN, TFT_FORESTGREEN, TFT_GREEN, TFT_DARKGREEN, TFT_POWDERBLUE, TFT_LIGHTBLUE, TFT_SKYBLUE, TFT_LIGHTSTEELBLUE, TFT_PALETURQUOISE,
                                  TFT_LIGHTSKYBLUE, TFT_AQUAMARINE, TFT_MEDIUMSLATEBLUE, TFT_LIGHTSLATEGRAY, TFT_SLATEGRAY, TFT_SLATEBLUE, TFT_MEDIUMAQUAMARINE, TFT_CORNFLOWERBLUE, TFT_CADETBLUE,
                                  TFT_MEDIUMTURQUOISE, TFT_DARKSLATEBLUE, TFT_INDIGO, TFT_TURQUOISE, TFT_STEELBLUE, TFT_ROYALBLUE, TFT_LIGHTSEAGREEN, TFT_DODGERBLUE, TFT_MIDNIGHTBLUE, TFT_CYAN,
                                  TFT_DARKTURQUOISE, TFT_DEEPSKYBLUE, TFT_DARKCYAN, TFT_TEAL, TFT_BLUE, TFT_MEDIUMBLUE, TFT_DARKBLUE, TFT_NAVY, TFT_HOTPINK, TFT_DEEPPINK, TFT_DARKMAGENTA, TFT_MAGENTA,
                                  TFT_PURPLE, TFT_THISTLE, TFT_PLUM, TFT_ORCHID, TFT_MEDIUMORCHID, TFT_DARKORCHID, TFT_MEDIUMPURPLE, TFT_PALEVIOLETRED, TFT_MEDIUMVIOLETRED, TFT_ROSYBROWN, TFT_DARKGRAY,
                                  TFT_DARKVIOLET, TFT_BLUEVIOLET, TFT_PEACHPUFF, TFT_PINK, TFT_LIGHTCORAL, TFT_INDIANRED, TFT_SALMON, TFT_CORAL, TFT_TOMATO, TFT_RED, TFT_FIREBRICK, TFT_BROWN, TFT_DARKRED,
                                  TFT_MAROON, TFT_WHITE, TFT_BISQUE, TFT_MOCCASIN, TFT_LIGHTGREY, TFT_SILVER, TFT_GRAY, TFT_DIMGRAY, TFT_DARKSLATEGRAY };

  pulse = LOW;
  int numIndice;

  int POSICIONActual = 0;
  int r;
  //tft.setTextColor(TFT_BLACK);
  //tft.setFreeFont(FF17);

  for (r = 0; r < 104; r++) {
    if (claveColor[r] == fondoTitMenu) {
      numIndice = r;
      r = 104;
    }
  }

  String titulo = "FONDO TITULO";
  String opciones[] = { "  ", "  ", "Seleccione Color...." };
  int maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
  dibujaPantalla(titulo, opciones, maxOpciones);
  marcoSeleccion(opciones[2], 2, 3);

  POSICION = numIndice;
  POSICIONActual = numIndice;
  tft.setTextColor(txtMenu, fondoPantalla);
  tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
  do {
    if (POSICION != POSICIONActual) {
      if (POSICION > POSICIONActual) { fondoTitMenu++; }
      if (POSICION < POSICIONActual) { fondoTitMenu--; }
      if (POSICION > 104) { POSICION = 0; }
      if (POSICION < 0) { POSICION = 104; }

      POSICIONActual = POSICION;
      fondoTitMenu = claveColor[POSICION];

      titulo = "FONDO TITULO";
      String opciones[] = { "  ", "  ", "Seleccione Color...." };
      maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
      dibujaPantalla(titulo, opciones, maxOpciones);
      tft.setTextColor(txtMenu, TFT_BLACK);
      tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
      tft.setTextColor(txtMenu, fondoPantalla);
      marcoSeleccion(opciones[2], 2, 3);
    }
  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir

  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  EEPROM.writeUShort(dirMemFondoTitMenu, fondoTitMenu);
  EEPROM.commit();
  menuAspecto();
}

/*******************************************************************************************/
void colorTituloMenu() {

  String nombreColor[] = { "TFT_BLACK", "TFT_ORANGE", "TFT_CHOCOLATE", "TFT_SIENNA", "TFT_SADDLEBROWN", "TFT_SANDYBROWN", "TFT_DARKSALMON", "TFT_TAN", "TFT_PERU",
                           "TFT_GOLDENROD", "TFT_DARKGOLDENROD", "TFT_PALEGOLDENROD", "TFT_KHAKI", "TFT_YELLOW", "TFT_GOLD", "TFT_NAVAJOWHITE", "TFT_BURLYWOOD", "TFT_DARKKHAKI", "TFT_GREENYELLOW",
                           "TFT_YELLOWGREEN", "TFT_LIGHTGREEN", "TFT_MEDIUMSPRINGGREEN", "TFT_SPRINGGREEN", "TFT_MEDIUMSEAGREEN", "TFT_PALEGREEN", "TFT_LIMEGREEN", "TFT_LIME", "TFT_DARKSEAGREEN",
                           "TFT_LAWNGREEN", "TFT_OLIVEDRAB", "TFT_OLIVE", "TFT_DARKOLIVEGREEN", "TFT_SEAGREEN", "TFT_FORESTGREEN", "TFT_GREEN", "TFT_DARKGREEN", "TFT_POWDERBLUE", "TFT_LIGHTBLUE", "TFT_SKYBLUE",
                           "TFT_LIGHTSTEELBLUE", "TFT_PALETURQUOISE", "TFT_LIGHTSKYBLUE", "TFT_AQUAMARINE", "TFT_MEDIUMSLATEBLUE", "TFT_LIGHTSLATEGRAY", "TFT_SLATEGRAY", "TFT_SLATEBLUE",
                           "TFT_MEDIUMAQUAMARINE", "TFT_CORNFLOWERBLUE", "TFT_CADETBLUE", "TFT_MEDIUMTURQUOISE", "TFT_DARKSLATEBLUE", "TFT_INDIGO", "TFT_TURQUOISE", "TFT_STEELBLUE",
                           "TFT_ROYALBLUE", "TFT_LIGHTSEAGREEN", "TFT_DODGERBLUE", "TFT_MIDNIGHTBLUE", "TFT_CYAN", "TFT_DARKTURQUOISE", "TFT_DEEPSKYBLUE", "TFT_DARKCYAN", "TFT_TEAL", "TFT_BLUE",
                           "TFT_MEDIUMBLUE", "TFT_DARKBLUE", "TFT_NAVY", "TFT_HOTPINK", "TFT_DEEPPINK", "TFT_DARKMAGENTA", "TFT_MAGENTA", "TFT_PURPLE", "TFT_THISTLE", "TFT_PLUM", "TFT_ORCHID",
                           "TFT_MEDIUMORCHID", "TFT_DARKORCHID", "TFT_MEDIUMPURPLE", "TFT_PALEVIOLETRED", "TFT_MEDIUMVIOLETRED", "TFT_ROSYBROWN", "TFT_DARKGRAY", "TFT_DARKVIOLET",
                           "TFT_BLUEVIOLET", "TFT_PEACHPUFF", "TFT_PINK", "TFT_LIGHTCORAL", "TFT_INDIANRED", "TFT_SALMON", "TFT_CORAL", "TFT_TOMATO", "TFT_RED", "TFT_FIREBRICK", "TFT_BROWN",
                           "TFT_DARKRED", "TFT_MAROON", "TFT_WHITE", "TFT_BISQUE", "TFT_MOCCASIN", "TFT_LIGHTGREY", "TFT_SILVER", "TFT_GRAY", "TFT_DIMGRAY", "TFT_DARKSLATEGRAY" };

  unsigned short claveColor[] = { TFT_BLACK, TFT_ORANGE, TFT_CHOCOLATE, TFT_SIENNA, TFT_SADDLEBROWN, TFT_SANDYBROWN, TFT_DARKSALMON, TFT_TAN, TFT_PERU, TFT_GOLDENROD,
                                  TFT_DARKGOLDENROD, TFT_PALEGOLDENROD, TFT_KHAKI, TFT_YELLOW, TFT_GOLD, TFT_NAVAJOWHITE, TFT_BURLYWOOD, TFT_DARKKHAKI, TFT_GREENYELLOW, TFT_YELLOWGREEN, TFT_LIGHTGREEN,
                                  TFT_MEDIUMSPRINGGREEN, TFT_SPRINGGREEN, TFT_MEDIUMSEAGREEN, TFT_PALEGREEN, TFT_LIMEGREEN, TFT_LIME, TFT_DARKSEAGREEN, TFT_LAWNGREEN, TFT_OLIVEDRAB, TFT_OLIVE,
                                  TFT_DARKOLIVEGREEN, TFT_SEAGREEN, TFT_FORESTGREEN, TFT_GREEN, TFT_DARKGREEN, TFT_POWDERBLUE, TFT_LIGHTBLUE, TFT_SKYBLUE, TFT_LIGHTSTEELBLUE, TFT_PALETURQUOISE,
                                  TFT_LIGHTSKYBLUE, TFT_AQUAMARINE, TFT_MEDIUMSLATEBLUE, TFT_LIGHTSLATEGRAY, TFT_SLATEGRAY, TFT_SLATEBLUE, TFT_MEDIUMAQUAMARINE, TFT_CORNFLOWERBLUE, TFT_CADETBLUE,
                                  TFT_MEDIUMTURQUOISE, TFT_DARKSLATEBLUE, TFT_INDIGO, TFT_TURQUOISE, TFT_STEELBLUE, TFT_ROYALBLUE, TFT_LIGHTSEAGREEN, TFT_DODGERBLUE, TFT_MIDNIGHTBLUE, TFT_CYAN,
                                  TFT_DARKTURQUOISE, TFT_DEEPSKYBLUE, TFT_DARKCYAN, TFT_TEAL, TFT_BLUE, TFT_MEDIUMBLUE, TFT_DARKBLUE, TFT_NAVY, TFT_HOTPINK, TFT_DEEPPINK, TFT_DARKMAGENTA, TFT_MAGENTA,
                                  TFT_PURPLE, TFT_THISTLE, TFT_PLUM, TFT_ORCHID, TFT_MEDIUMORCHID, TFT_DARKORCHID, TFT_MEDIUMPURPLE, TFT_PALEVIOLETRED, TFT_MEDIUMVIOLETRED, TFT_ROSYBROWN, TFT_DARKGRAY,
                                  TFT_DARKVIOLET, TFT_BLUEVIOLET, TFT_PEACHPUFF, TFT_PINK, TFT_LIGHTCORAL, TFT_INDIANRED, TFT_SALMON, TFT_CORAL, TFT_TOMATO, TFT_RED, TFT_FIREBRICK, TFT_BROWN, TFT_DARKRED,
                                  TFT_MAROON, TFT_WHITE, TFT_BISQUE, TFT_MOCCASIN, TFT_LIGHTGREY, TFT_SILVER, TFT_GRAY, TFT_DIMGRAY, TFT_DARKSLATEGRAY };

  pulse = LOW;
  int numIndice;

  int POSICIONActual = 0;
  int r;
  tft.setTextColor(TFT_BLACK);
  tft.setFreeFont(FF21);

  for (r = 0; r < 104; r++) {
    if (claveColor[r] == tituloMenu) {
      numIndice = r;
      r = 104;
    }
  }

  String titulo = "COLOR TITULO";
  String opciones[] = { "  ", "  ", "Seleccione Color...." };
  int maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
  dibujaPantalla(titulo, opciones, maxOpciones);
  marcoSeleccion(opciones[2], 2, 3);

  POSICION = numIndice;
  POSICIONActual = numIndice;
  tft.setTextColor(txtMenu, fondoPantalla);
  tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
  do {
    if (POSICION != POSICIONActual) {
      if (POSICION > POSICIONActual) { tituloMenu++; }
      if (POSICION < POSICIONActual) { tituloMenu--; }
      if (POSICION > 104) { POSICION = 0; }
      if (POSICION < 0) { POSICION = 104; }

      POSICIONActual = POSICION;
      tituloMenu = claveColor[POSICION];

      titulo = "COLOR TITULO";
      String opciones[] = { "  ", "  ", "Seleccione Color...." };
      maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
      dibujaPantalla(titulo, opciones, maxOpciones);
      tft.setTextColor(txtMenu, TFT_BLACK);
      tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
      tft.setTextColor(txtMenu, fondoPantalla);
      marcoSeleccion(opciones[2], 2, 3);
    }
  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir

  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  EEPROM.writeUShort(dirMemTituloMenu, tituloMenu);
  EEPROM.commit();
  menuAspecto();
}

/***********************************************************************************************/
void dibujaPantalla(String titulo, String cadena[], int maxOpciones) {

  int marco = 0;
  tft.fillRoundRect(0, 0, TFT_WIDTH, ILI9341_TFTHEIGHT, 5, TFT_WHITE);  //dibuja lienzo blanco

  int x = 2;
  uint16_t fila = 2;  //   FILA DEL RECTANGULO DEL TITULO DEL MENU

  tft.setFreeFont(FF22);
  tft.setTextColor(tituloMenu, fondoTitMenu);

  tft.fillRoundRect(2, fila, TFT_WIDTH - 4, tft.fontHeight(GFXFF) - 1, 5, fondoTitMenu);
  fila = 7;  //   FILA DEL TEXTO DEL TITULO DEL MENU (LINEA SUPERIOR)
  centraTexto(titulo, fila, marco, fondoTitMenu);

  fila = 32;
  tft.fillRoundRect(x, fila, TFT_WIDTH - 4, 257, 5, fondoPantalla);  //dibuja fondo de zona opciones

  tft.setFreeFont(FF17);
  tft.setTextColor(txtMenu, fondoPantalla);
  for (int r = 0; r < maxOpciones; r++) {
    fila = 40 + (tft.fontHeight(GFXFF) * r) + r * 9;
    centraTexto(cadena[r], fila, marco, fondoPantalla);
  }
  dibujaZonaTestigos();
  testigosLucesOF();
}

/*******************************************************************************************/
void configuraFondoPantalla() {

  String nombreColor[] = { "TFT_BLACK", "TFT_ORANGE", "TFT_CHOCOLATE", "TFT_SIENNA", "TFT_SADDLEBROWN", "TFT_SANDYBROWN", "TFT_DARKSALMON", "TFT_TAN", "TFT_PERU",
                           "TFT_GOLDENROD", "TFT_DARKGOLDENROD", "TFT_PALEGOLDENROD", "TFT_KHAKI", "TFT_YELLOW", "TFT_GOLD", "TFT_NAVAJOWHITE", "TFT_BURLYWOOD", "TFT_DARKKHAKI", "TFT_GREENYELLOW",
                           "TFT_YELLOWGREEN", "TFT_LIGHTGREEN", "TFT_MEDIUMSPRINGGREEN", "TFT_SPRINGGREEN", "TFT_MEDIUMSEAGREEN", "TFT_PALEGREEN", "TFT_LIMEGREEN", "TFT_LIME", "TFT_DARKSEAGREEN",
                           "TFT_LAWNGREEN", "TFT_OLIVEDRAB", "TFT_OLIVE", "TFT_DARKOLIVEGREEN", "TFT_SEAGREEN", "TFT_FORESTGREEN", "TFT_GREEN", "TFT_DARKGREEN", "TFT_POWDERBLUE", "TFT_LIGHTBLUE", "TFT_SKYBLUE",
                           "TFT_LIGHTSTEELBLUE", "TFT_PALETURQUOISE", "TFT_LIGHTSKYBLUE", "TFT_AQUAMARINE", "TFT_MEDIUMSLATEBLUE", "TFT_LIGHTSLATEGRAY", "TFT_SLATEGRAY", "TFT_SLATEBLUE",
                           "TFT_MEDIUMAQUAMARINE", "TFT_CORNFLOWERBLUE", "TFT_CADETBLUE", "TFT_MEDIUMTURQUOISE", "TFT_DARKSLATEBLUE", "TFT_INDIGO", "TFT_TURQUOISE", "TFT_STEELBLUE",
                           "TFT_ROYALBLUE", "TFT_LIGHTSEAGREEN", "TFT_DODGERBLUE", "TFT_MIDNIGHTBLUE", "TFT_CYAN", "TFT_DARKTURQUOISE", "TFT_DEEPSKYBLUE", "TFT_DARKCYAN", "TFT_TEAL", "TFT_BLUE",
                           "TFT_MEDIUMBLUE", "TFT_DARKBLUE", "TFT_NAVY", "TFT_HOTPINK", "TFT_DEEPPINK", "TFT_DARKMAGENTA", "TFT_MAGENTA", "TFT_PURPLE", "TFT_THISTLE", "TFT_PLUM", "TFT_ORCHID",
                           "TFT_MEDIUMORCHID", "TFT_DARKORCHID", "TFT_MEDIUMPURPLE", "TFT_PALEVIOLETRED", "TFT_MEDIUMVIOLETRED", "TFT_ROSYBROWN", "TFT_DARKGRAY", "TFT_DARKVIOLET",
                           "TFT_BLUEVIOLET", "TFT_PEACHPUFF", "TFT_PINK", "TFT_LIGHTCORAL", "TFT_INDIANRED", "TFT_SALMON", "TFT_CORAL", "TFT_TOMATO", "TFT_RED", "TFT_FIREBRICK", "TFT_BROWN",
                           "TFT_DARKRED", "TFT_MAROON", "TFT_WHITE", "TFT_BISQUE", "TFT_MOCCASIN", "TFT_LIGHTGREY", "TFT_SILVER", "TFT_GRAY", "TFT_DIMGRAY", "TFT_DARKSLATEGRAY" };

  unsigned short claveColor[] = { TFT_BLACK, TFT_ORANGE, TFT_CHOCOLATE, TFT_SIENNA, TFT_SADDLEBROWN, TFT_SANDYBROWN, TFT_DARKSALMON, TFT_TAN, TFT_PERU, TFT_GOLDENROD,
                                  TFT_DARKGOLDENROD, TFT_PALEGOLDENROD, TFT_KHAKI, TFT_YELLOW, TFT_GOLD, TFT_NAVAJOWHITE, TFT_BURLYWOOD, TFT_DARKKHAKI, TFT_GREENYELLOW, TFT_YELLOWGREEN, TFT_LIGHTGREEN,
                                  TFT_MEDIUMSPRINGGREEN, TFT_SPRINGGREEN, TFT_MEDIUMSEAGREEN, TFT_PALEGREEN, TFT_LIMEGREEN, TFT_LIME, TFT_DARKSEAGREEN, TFT_LAWNGREEN, TFT_OLIVEDRAB, TFT_OLIVE,
                                  TFT_DARKOLIVEGREEN, TFT_SEAGREEN, TFT_FORESTGREEN, TFT_GREEN, TFT_DARKGREEN, TFT_POWDERBLUE, TFT_LIGHTBLUE, TFT_SKYBLUE, TFT_LIGHTSTEELBLUE, TFT_PALETURQUOISE,
                                  TFT_LIGHTSKYBLUE, TFT_AQUAMARINE, TFT_MEDIUMSLATEBLUE, TFT_LIGHTSLATEGRAY, TFT_SLATEGRAY, TFT_SLATEBLUE, TFT_MEDIUMAQUAMARINE, TFT_CORNFLOWERBLUE, TFT_CADETBLUE,
                                  TFT_MEDIUMTURQUOISE, TFT_DARKSLATEBLUE, TFT_INDIGO, TFT_TURQUOISE, TFT_STEELBLUE, TFT_ROYALBLUE, TFT_LIGHTSEAGREEN, TFT_DODGERBLUE, TFT_MIDNIGHTBLUE, TFT_CYAN,
                                  TFT_DARKTURQUOISE, TFT_DEEPSKYBLUE, TFT_DARKCYAN, TFT_TEAL, TFT_BLUE, TFT_MEDIUMBLUE, TFT_DARKBLUE, TFT_NAVY, TFT_HOTPINK, TFT_DEEPPINK, TFT_DARKMAGENTA, TFT_MAGENTA,
                                  TFT_PURPLE, TFT_THISTLE, TFT_PLUM, TFT_ORCHID, TFT_MEDIUMORCHID, TFT_DARKORCHID, TFT_MEDIUMPURPLE, TFT_PALEVIOLETRED, TFT_MEDIUMVIOLETRED, TFT_ROSYBROWN, TFT_DARKGRAY,
                                  TFT_DARKVIOLET, TFT_BLUEVIOLET, TFT_PEACHPUFF, TFT_PINK, TFT_LIGHTCORAL, TFT_INDIANRED, TFT_SALMON, TFT_CORAL, TFT_TOMATO, TFT_RED, TFT_FIREBRICK, TFT_BROWN, TFT_DARKRED,
                                  TFT_MAROON, TFT_WHITE, TFT_BISQUE, TFT_MOCCASIN, TFT_LIGHTGREY, TFT_SILVER, TFT_GRAY, TFT_DIMGRAY, TFT_DARKSLATEGRAY };

  pulse = LOW;
  int numIndice;

  int POSICIONActual = 0;
  int r;
  tft.setTextColor(TFT_BLACK);
  tft.setFreeFont(FF21);

  for (r = 0; r < 104; r++) {
    if (claveColor[r] == fondoPantalla) {
      numIndice = r;
      r = 104;
    }
  }

  String titulo = "FONDO PANTALLA";
  String opciones[] = { "  ", "  ", "Seleccione Color...." };
  int maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
  dibujaPantalla(titulo, opciones, maxOpciones);
  marcoSeleccion(opciones[2], 2, 3);

  POSICION = numIndice;
  POSICIONActual = numIndice;
  tft.setTextColor(txtMenu, fondoPantalla);
  tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
  do {
    if (POSICION != POSICIONActual) {
      if (POSICION > POSICIONActual) { fondoPantalla++; }
      if (POSICION < POSICIONActual) { fondoPantalla--; }
      if (POSICION > 104) { POSICION = 0; }
      if (POSICION < 0) { POSICION = 104; }

      POSICIONActual = POSICION;
      fondoPantalla = claveColor[POSICION];

      titulo = "FONDO PANTALLA";
      String opciones[] = { "  ", "  ", "Seleccione Color...." };
      maxOpciones = sizeof(opciones) / sizeof(opciones[0]);
      dibujaPantalla(titulo, opciones, maxOpciones);
      tft.setTextColor(txtMenu, TFT_BLACK);
      tft.drawString(nombreColor[POSICION].substring(4, nombreColor[POSICION].length()), 120, 175, GFXFF);
      tft.setTextColor(txtMenu, fondoPantalla);
      marcoSeleccion(opciones[2], 2, 3);
    }
  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir

  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  EEPROM.writeUShort(dirMemFondoPantalla, fondoPantalla);
  EEPROM.commit();
  menuAspecto();
}

/****************************************************************************************/
void marcoSeleccion(String& texto, int r, int opcion) {

  int largoTxt = tft.textWidth(texto);
  int x = (TFT_WIDTH - largoTxt) / 2;
  int colorMarco;
  colorMarco = fondoPantalla;
  uint16_t fila;

  if (r == opcion - 1) { colorMarco = txtMenu; }
  fila = 37 + (tft.fontHeight(GFXFF) * r) + r * 9;

  tft.drawRoundRect(x - 3, fila, largoTxt + 8, tft.fontHeight(GFXFF) + 1, 5, colorMarco);
  tft.drawRoundRect(x - 4, fila - 1, largoTxt + 10, tft.fontHeight(GFXFF) + 3, 5, colorMarco);
  yield();
}

/************************************************************************************************/
void centraTexto(String& texto, uint16_t fila, bool marco, uint32_t colorFondo) {  //////////////   CENTRA TEXTO

  tft.drawString(texto, TFT_WIDTH / 2, fila, GFXFF);
  if (marco) {  ////enmarca el rotulo si la variable marco esta a 1
    tft.drawRect(0, fila - 4, TFT_WIDTH, tft.fontHeight(GFXFF), TFT_WHITE);
  }
}

/****************************************************************************************/
void configuraBrillo() {

  int POSICIONActual = 0;
  unsigned long t0, t1;

  int brillo = EEPROM.readByte(dirMemBrillo);
  t0 = millis();

  tft.setTextColor(TFT_BLACK);
  tft.setFreeFont(FF21);

  do {
    if (POSICION > POSICIONActual) { brillo = brillo + 3; }
    if (POSICION < POSICIONActual) { brillo = brillo - 3; }
    POSICIONActual = POSICION;
    if (brillo > 255) { brillo = 255; }
    if (brillo < 1) { brillo = 1; }
    t1 = millis();
    if (t1 - t0 > 1) {
      tft.fillRoundRect(155, 38, 40, 20, 3, TFT_GOLD);
      tft.setCursor(190 - tft.textWidth(String(brillo)), 53);
      tft.print(brillo);
      t0 = millis();
    }
    analogWrite(pinBrilloTFT, brillo);
  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir
  tft.setTextColor(TFT_WHITE);
  tft.setFreeFont(FF17);
  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  tft.fillRoundRect(155, 38, 40, 20, 3, fondoPantalla);
  EEPROM.writeByte(dirMemBrillo, brillo - 2);
  EEPROM.commit();
}

/*******************************************************************************************/
void menuServos() {

  tft.fillScreen(ILI9341_BLACK);


  int colorTxt = TFT_WHITE;
  int colorFondo = TFT_BLACK;
  int colorMarco = TFT_BLACK;

  pulse = LOW;
  int opcion = 1;
  bool marco;
  int maxOpciones;
  int r, x;
  String opcionesMenu[] = { "Alabeo", "Direccion", "Radiador", "Atras" };
  maxOpciones = sizeof(opcionesMenu) / sizeof(opcionesMenu[0]);
  int largoTxt;
  POSICION = 1;
  tft.setFreeFont(FF22);
  tft.setTextColor(TFT_BLACK, TFT_GOLD);

  String titulo = "MENU SERVOS";
  marco = 1;
  centraTexto(titulo, 0, marco, TFT_GOLD);

  tft.setFreeFont(FF17);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  marco = 0;

  for (r = 0; r < maxOpciones; r++) {
    centraTexto(opcionesMenu[r], 10 + ((r + 1) * 30), marco, TFT_BLACK);
  }
  dibujaZonaTestigos();
  testigosLucesOF();
  do {

    if (POSICION > 4) { POSICION = 1; }
    if (POSICION < 1) { POSICION = 4; }
    opcion = POSICION;

    switch (opcion) {

      case 1:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          guardaPOSICION = POSICION;  //guarda valor de POSICION
          POSICION = POSservoAlabeo;
          menuTrimAlabeo();
          POSservoAlabeo = POSICION;
          POSICION = guardaPOSICION;
        }
        break;

      case 2:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          guardaPOSICION = POSICION;  //guarda valor de POSICION
          POSICION = POSservoDireccion;
          menuTrimDireccion();
          POSservoDireccion = POSICION;
          POSICION = guardaPOSICION;
        }
        break;

      case 3:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          guardaPOSICION = POSICION;  //guarda valor de POSICION
          POSICION = POSservoRadiador;
          trimRadiador();
          POSservoRadiador = POSICION;
          POSICION = guardaPOSICION;
        }
        break;

      case 4:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          POSICION = guardaPOSICION;
          menuInicial();
        }
        break;

      default:
        if (POSICION > 4) { POSICION = 1; }
        if (POSICION < 1) { POSICION = 4; }
    }

  } while (pulse == LOW);
}

/**********************************************************************************************/
void barraEstado(int comandoLuces) {

  //  valor=miSerial1.read();
  if (valorActual != comandoLuces) {
    if (comandoLuces >= 1 & comandoLuces <= 8) {
      valorActual = comandoLuces;

      switch (valorActual) {

        case 1:  //BLANCA DERECHA ON (BDON)
          bDerON();
          break;
        case 2:  //BLNCA DERECHA OFF (BDOF)
          bDerOF();
          break;
        case 3:  //BLANCA IZQUIERDA ON (BION)
          bIzqON();
          break;
        case 4:  //BLANCA IZQUIERDA OFF (BIOF)
          bIzqOF();
          break;
        case 5:  //VERDE ON (VON)
          verdeON();
          break;
        case 6:  //VERDE ON (VON)
          verdeOF();
          break;
        case 7:  //VERDE ON (VON)
          rojaON();
          break;
        case 8:  //VERDE ON (VON)
          rojaOF();
          break;
      }
    }
  }
}

/**************************************************************************************/
void menuInicial() {

  ConfiguracionInicial();
  pulse = LOW;
  int opcion = 1;
  bool marco = 1;
  int maxOpciones;
  int r;  //, x;
  String opcionesMenuPrincipal[] = { "Control Servos", "Configuracion" };
  maxOpciones = sizeof(opcionesMenuPrincipal) / sizeof(opcionesMenuPrincipal[0]);
  POSICION = 1;

  String titulo = "MENU INICIAL";
  fondoTitMenu = colorDeContraste(tituloMenu);
  tft.setTextColor(tituloMenu, fondoTitMenu);

  dibujaPantalla(titulo, opcionesMenuPrincipal, maxOpciones);

  dibujaZonaTestigos();
  testigosLucesOF();

  do {
    barraEstado(comandoLuces);
    if (POSICION > 2) { POSICION = 1; }
    if (POSICION < 1) { POSICION = 2; }
    opcion = POSICION;
    switch (opcion) {

      case 1:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenuPrincipal[r], r, opcion); }
        if (pulse == HIGH) {
          pulse = LOW;
          menuServos();
        }
        break;

      case 2:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenuPrincipal[r], r, opcion); }
        if (pulse == HIGH) {
          pulse = LOW;
          menuConfiguracion();
        }
        break;

      default:
        if (POSICION > 2) { POSICION = 1; }
        if (POSICION < 1) { POSICION = 2; }
    }

  } while (pulse == 0);
}

/******************************************************************************************/
void menuLuces() {  /////////////////////////////////////////////////MENU LUCES

  tft.fillScreen(fondoPantalla);

  int colorTxt = txtMenu;
  int colorFondo = fondoPantalla;
  int colorMarco = fondoPantalla;

  pulse = LOW;
  int opcion = 1;
  bool marco;
  int maxOpciones;
  int r, x;
  String opcionesMenu[] = { "Blancas Fijas",
                            "Blancas Intermitentes",
                            "Blancas Alternas",
                            "Navegacion Fijas",
                            "Navegacion Alternas",
                            "Apagar Blancas",
                            "Apagar Navegacion",
                            "Menu Inicio" };
  maxOpciones = sizeof(opcionesMenu) / sizeof(opcionesMenu[0]);
  int largoTxt;
  POSICION = 1;
  tft.setFreeFont(FF22);
  tft.setTextColor(tituloMenu, fondoTitMenu);

  String titulo = "MENU LUCES";
  marco = 1;
  centraTexto(titulo, 0, marco, fondoTitMenu);

  tft.setFreeFont(FF17);
  tft.setTextColor(txtMenu, fondoPantalla);
  marco = 0;

  for (r = 0; r < maxOpciones; r++) {
    centraTexto(opcionesMenu[r], 10 + ((r + 1) * 30), marco, TFT_BLACK);
  }
  dibujaZonaTestigos();
  testigosLucesOF();

  do {

    if (POSICION > 8) { POSICION = 0; }
    if (POSICION < 1) { POSICION = 8; }

    opcion = POSICION;

    comandoLuces = opcion;
    barraEstado(comandoLuces);

    switch (opcion) {

      case 1:  //BLANCAS FIJAS
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          blancasF = HIGH;
          blancasA = LOW;
          blancasI = LOW;
          if (navF == HIGH) { opcion = 8; }   //si blancas estan fijas manda 10
          if (navA == HIGH) { opcion = 11; }  //si blancas estan inter manda 9
          miSerial1.write(opcion);
          //Envia clave Blancas Fijas al esclavo por puerto serie 1
        }
        break;

      case 2:  //BLANCAS INTERMITENTES
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          blancasF = LOW;
          blancasA = LOW;
          blancasI = HIGH;
          if (navF == HIGH) { opcion = 9; }
          if (navA == HIGH) { opcion = 12; }
          miSerial1.write(opcion);  //Envia clave Blancas Fijas al esclavo por puerto serie 1
        }
        break;

      case 3:  //BLANCAS ALTERNAS
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          blancasF = LOW;
          blancasA = HIGH;
          blancasI = LOW;
          if (navF == HIGH) { opcion = 10; }  //si blancas estan fijas manda 8
          if (navA == HIGH) { opcion = 15; }  //si blancas estan inter manda 9          miSerial1.write(opcion);     //Envia clave Blancas Fijas al esclavo por puerto serie 1
          miSerial1.write(opcion);            //...ni no manda 4
        }
        break;

      case 4:  //NAVEGACION FIJAS
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          if (blancasF == HIGH) { opcion = 8; }   //si blancas estan fijas manda 8
          if (blancasI == HIGH) { opcion = 9; }   //si blancas estan inter manda 9
          if (blancasA == HIGH) { opcion = 10; }  //si blancas estan alter manda 10
          navA = LOW;
          navF = HIGH;
          miSerial1.write(opcion);  //...ni no manda 4

          //Envia clave Blancas Fijas al esclavo por puerto serie 1
        }
        break;

      case 5:  //NAVEGACION ALTERNAS
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }
        if (pulse == HIGH) {
          pulse = LOW;
          if (blancasF == HIGH) { opcion = 11; }  //si blancas estan fijas manda 8
          if (blancasI == HIGH) { opcion = 12; }  //si blancas estan inter manda 9
          if (blancasA == HIGH) { opcion = 15; }  //si blancas estan alter manda 10
          navA = HIGH;
          navF = LOW;
          miSerial1.write(opcion);  //Envia clave Blancas Fijas al esclavo por puerto serie 1
        }
        break;

      case 6:  //APAGAR BLANCAS
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }
        if (pulse == HIGH) {
          pulse = LOW;
          blancasA = LOW;
          blancasI = LOW;
          blancasF = LOW;
          if (navF == HIGH) { opcion = 13; }  //si navFijas manda 13
          if (navA == HIGH) { opcion = 14; }  //si navAlternas manda 14
          miSerial1.write(opcion);            //Envia clave Blancas Fijas al esclavo por puerto serie 1
        }
        break;

      case 7:  //APAGAR NAVEGACION
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }
        if (pulse == HIGH) {
          pulse = LOW;
          navF = LOW;
          navA = LOW;
          if (blancasF == HIGH) { opcion = 16; }  //si blancas estan fijas manda 8
          if (blancasI == HIGH) { opcion = 17; }  //si blancas estan inter manda 9
          if (blancasA == HIGH) { opcion = 18; }  //si blancas estan alter manda 10
          miSerial1.write(opcion);                //Envia clave Blancas Fijas al esclavo por puerto serie 1
        }
        break;

      case 8:  /////Vuelve a inicio
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }
        if (pulse == HIGH) {
          pulse = LOW;
          menuInicial();
        }

        break;

      default:
        if (POSICION > 8) { POSICION = 1; }
        if (POSICION < 1) { POSICION = 8; }
    }

  } while (pulse == LOW);

  tft.setFreeFont(FF17);
}

/******************************************************************************************/
void menuConfiguracion() {  //////////////////////////////////////////////////////////////////////    MENU CONFIGURACION
  pulse = LOW;
  int opcion = 1;
  bool marco;
  int maxOpciones;
  int r;
  String opcionesMenu[] = { "Aspecto", "Fecha/hora", "Luces", "Atras" };
  maxOpciones = sizeof(opcionesMenu) / sizeof(opcionesMenu[0]);
  int largoTxt;
  POSICION = 1;

  String titulo = "CONFIGURACION";
  marco = 1;

  dibujaPantalla(titulo, opcionesMenu, maxOpciones);

  dibujaZonaTestigos();
  testigosLucesOF();

  do {

    barraEstado(comandoLuces);

    if (POSICION > 4) { POSICION = 1; }
    if (POSICION < 1) { POSICION = 4; }
    opcion = POSICION;

    switch (opcion) {

      case 1:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          guardaPOSICION = POSICION;  //guarda valor de POSICION
          POSICION = POSservoAlabeo;
          menuAspecto();
          POSservoAlabeo = POSICION;
          POSICION = guardaPOSICION;
        }
        break;

      case 2:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          guardaPOSICION = POSICION;  //guarda valor de POSICION
          POSICION = POSservoDireccion;
          //fechaHora();
          POSservoDireccion = POSICION;
          POSICION = guardaPOSICION;
        }
        break;

      case 3:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          guardaPOSICION = POSICION;  //guarda valor de POSICION
          POSICION = POSservoRadiador;
          menuLuces();
          POSservoRadiador = POSICION;
          POSICION = guardaPOSICION;
        }
        break;

      case 4:
        for (r = 0; r < maxOpciones; r++) { marcoSeleccion(opcionesMenu[r], r, opcion); }

        if (pulse == HIGH) {
          pulse = LOW;
          POSICION = guardaPOSICION;
          menuInicial();
        }
        break;

      default:
        if (POSICION > 4) { POSICION = 1; }
        if (POSICION < 1) { POSICION = 4; }
    }

  } while (pulse == LOW);
}

/*********************************************************************************************/
void dibujaZonaTestigos() {
  tft.fillRoundRect(2, ILI9341_TFTHEIGHT - 29, ILI9341_TFTWIDTH - 3, 27, 5, fondoBarraEstado);  //dibuja fondo area testigos

  /*tft.fillRect(0, ILI9341_TFTHEIGHT-22, ILI9341_TFTWIDTH, 25, TFT_DARKGREY);
  tft.drawRect(0, ILI9341_TFTHEIGHT-23, ILI9341_TFTWIDTH, 23, TFT_WHITE);
  tft.drawRect(0, 0,240,320, TFT_WHITE);*/
}

/*********************************************************************************************/
void bIzqOF() {
  tft.fillCircle(10, 307, 5, TFT_DARKGREY);
  tft.drawCircle(10, 307, 5, TFT_LIGHTGREY);
}

/*********************************************************************************************/
void bDerOF() {
  tft.fillCircle(230, 307, 5, TFT_DARKGREY);
  tft.drawCircle(230, 307, 5, TFT_LIGHTGREY);
}

/*********************************************************************************************/
void bIzqON() {
  tft.fillCircle(10, 307, 5, TFT_WHITE);
}

/*********************************************************************************************/
void bDerON() {
  tft.fillCircle(230, 307, 5, TFT_WHITE);
}

/*********************************************************************************************/
void verdeON() {
  tft.fillCircle(218, 307, 5, TFT_GREEN);
}

/*********************************************************************************************/
void verdeOF() {
  tft.fillCircle(218, 307, 5, TFT_DARKGREY);
  tft.drawCircle(218, 307, 5, TFT_GREEN);
}

/*********************************************************************************************/
void rojaON() {
  tft.fillCircle(22, 307, 5, ILI9341_RED);
}

/*********************************************************************************************/
void rojaOF() {
  tft.fillCircle(22, 307, 5, TFT_DARKGREY);
  tft.drawCircle(22, 307, 5, ILI9341_RED);
}

/*********************************************************************************************/
void testigosLucesOF() {
  bDerOF();
  bIzqOF();
  verdeOF();
  rojaOF();
}

/*******************************************************************************************/
void menuTrimAlabeo() {  //////////////////////////////////////////////////////////////////////////////////    MENU TRIM ALABEO

  int x, valor;
  pulse = LOW;

  unsigned long t0, t1;

  servoAlabeo.attach(pinServoAlabeo);
  POSICION = POSservoAlabeo;

  do {

    if (POSICION < 0) { POSICION = 0; }
    if (POSICION > 180) { POSICION = 180; }
    valor = 180 - POSICION;
    servoAlabeo.write(valor);  // sets the servo position according to the scaled value
    delay(30);
    t1 = millis();
    if (t0 - t1 >> 10) { tft.fillRoundRect(195, 40, 40, 23, 3, TFT_WHITE); }  //ventana indicadora valor servo
    tft.setTextColor(TFT_BLACK, TFT_WHITE);

    switch (String(POSICION).length()) {
      case 1:
        x = 220;
        break;
      case 2:
        x = 210;
        break;
      case 3:
        x = 200;
        break;
    }

    tft.setCursor(x, 57);
    tft.setFreeFont(FF21);  // Select the font
    if (t0 - t1 >> 5) {
      tft.print(POSICION);
    }
    t0 = millis();
    tft.setFreeFont(FF17);  // Select the font

  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir
  POSservoAlabeo = POSICION;

  pulse = LOW;                                       //se ha pulsado el switch y restauramos la variable de control a 0
  tft.fillRoundRect(195, 40, 40, 23, 3, TFT_BLACK);  //borra ventana con valor servo
  servoAlabeo.detach();
}

/*********************************************************************************************/
void menuTrimDireccion() {  ////////////////////////////////////////////////////////////////////////    MENU TRIM DIRECION

  int x;
  pulse = LOW;

  unsigned long t0, t1;  //controlando tiempo impresion en ventana valor servo evita parpadeo

  servoDireccion.attach(pinServoDireccion);
  POSICION = POSservoDireccion;

  do {

    if (POSICION < 0) { POSICION = 0; }
    if (POSICION > 180) { POSICION = 180; }
    servoDireccion.write(POSICION);  // sets the servo position according to the scaled value
    delay(30);
    t1 = millis();                                     //momento en que dibujamos ventana vacia
    tft.fillRoundRect(195, 70, 40, 24, 3, TFT_WHITE);  //borra ventana con valor servo si han pasado mas de 10 millis
    tft.setTextColor(ILI9341_BLACK, TFT_WHITE);

    switch (String(POSICION).length()) {
      case 1:
        x = 220;
        break;
      case 2:
        x = 210;
        break;
      case 3:
        x = 200;
        break;
    }

    tft.setCursor(x, 87);
    tft.setFreeFont(FF21);  // Select the font
    if (t0 - t1 >> 10) { tft.print(POSICION); }
    t0 = millis();
    tft.setFreeFont(FF17);  // Select the font

  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir

  pulse = LOW;  //se ha pulsado el switch y restauramos la variable de control a 0
  POSservoDireccion = POSICION;
  tft.fillRoundRect(195, 70, 40, 24, 3, TFT_BLACK);  //elimina ventana indicadora valor servo

  servoDireccion.detach();
}

/*********************************************************************************************/
void trimRadiador() {  //////////////////////////////////////////////////////////////////////////////////        MENU RADIADOR

  int x;
  pulse = LOW;

  unsigned long t0, t1;  //controlando tiempo impresion en ventana valor servo evita parpadeo

  servoRadiador.attach(pinServoRadiador);
  POSICION = POSservoRadiador;

  do {

    if (POSICION < 40) { POSICION = 40; }
    if (POSICION > 130) { POSICION = 130; }

    servoRadiador.write(POSICION);  // sets the servo position according to the scaled value
    delay(30);
    t1 = millis();                                      //momento en que dibujamos ventana vacia
    tft.fillRoundRect(195, 100, 40, 23, 3, TFT_WHITE);  //borra ventana con valor servo si han pasado mas de 10 millis
    tft.setTextColor(TFT_BLACK, TFT_WHITE);

    switch (String(POSICION).length()) {
      case 1:
        x = 220;
        break;
      case 2:
        x = 210;
        break;
      case 3:
        x = 200;
        break;
    }

    (FF21);  // Select the font
    tft.setCursor(x, 117);
    if (t0 - t1 >> 10) { tft.print(POSICION); }
    t0 = millis();
    tft.setFreeFont(FF17);  // Select the font

  } while (pulse == LOW);  //nos quedamos aqui hasta que se pulse el switch del codificador rotativo (pulse=1) para salir
  POSservoRadiador = POSICION;

  pulse = LOW;                                        //se ha pulsado el switch y restauramos la variable de control a 0
  tft.fillRoundRect(195, 100, 40, 23, 3, TFT_BLACK);  //borra ventana con valor servo
  servoRadiador.detach();
}

/*********************************************************************************************/
void swEncoder() {  /////////////////////////////////////////////////////////////////////////////////   SW ENCODER

  static unsigned long ultimaInterrupcion = 0;  // variable static con ultimo valor de tiempo de interrupcion
  unsigned long tiempoInterrupcion = millis();  // variable almacena valor de func. millis
  if (tiempoInterrupcion - ultimaInterrupcion > 2) {
    pulse = 1;
    ultimaInterrupcion = tiempoInterrupcion;  // guarda valor actualizado del tiempo de la interrupcion en variable static
  }
}

/*********************************************************************************************/
void encoder() {
  static unsigned long ultimaInterrupcion = 0;  // variable static con ultimo valor de tiempo de interrupcion
  unsigned long tiempoInterrupcion = millis();  // variable almacena valor de func. millis

  if (tiempoInterrupcion - ultimaInterrupcion > 1) {  // rutina antirebote desestima pulsos menores a 5 mseg.
    if (digitalRead(CLKencoder) == HIGH)              // si CLKencoder es HIGH, sentido horario
    {
      POSICION++;  // decrementa POSICION en 1
    } else {       // si CLKencoder es LOW, sentido anti horario
      POSICION--;  // incrementa POSICION en 1
    }

    ultimaInterrupcion = tiempoInterrupcion;  // guarda valor actualizado del tiempo de la interrupcion en variable static
  }
}
/*******************************************************************************************/

Y el mensaje de error:

C:\Users\phent\OneDrive\Documentos\Arduino\SPI_ESP32_Master_copy_20250201192029\SPI_ESP32_Master_copy_20250201192029.ino: In function 'void menuAspecto()':
C:\Users\phent\OneDrive\Documentos\Arduino\SPI_ESP32_Master_copy_20250201192029\SPI_ESP32_Master_copy_20250201192029.ino:263:11: error: 'modificaVariableAspecto' was not declared in this scope
  263 | 
      |           ^                      

exit status 1

Compilation error: 'modificaVariableAspecto' was not declared in this scope

Se me pasado decir que la placa es un ESP32.
Sorry. Es la edad......

Intenta mover la definición de la función por encima del lugar que la llama.

Solucionaaado..

Gracias. Pero no entiendo el porque. En Pascal si que debe ser como dices siempre. Pero en Arduino no y la prueba es que hay muchas llamadas a funciones definidas mas abajo en el boceto. Por ejemplo CentraTexto() y dibujaPantalla().
No se porque con esta funcion no es asi.
¿Alguien que me lo explique?.

Hola @phentium ,

Yo diría que tienes un error de falta de prototipo (prototype).

Si bien es cierto que la definición de una función puede estar después de ser llamada, al momento de compilar el compilador debe saber que al menos esa llamada es correcta. Es por eso que antes de la primera llamada se avisa al compilador que "si te encuentras con esto, después te cuento de qué se trata".

Al principio de tu programa, antes de la primera llamada a función pon los datos de la función sín el código de ejecución:
tipoDevuelto nombreDeFunción(parametros);

Eso debería resolver el problema.

Buena Suerte!

Gaby.//

Es cierto, generalmente no hace falta definir la función antes, pero es una buena practica o como dice gabygold declararla primero y luego definirla. En el compilado Arduino basado en ATmega no hace falta. Supongo que el compilador para ESP32 no esta tan afinado.

Pero para otras funciones no ocurre igual. Están definidas después de ser llamadas y nunca me ha dado ningún error. Eso es lo que me confunde.
Pero gracias.

Qué versión de IDE estás utilizando?

Pues yo diría que la última. 2 y algo.

2.3.4

Puedes subir el archivo Free_Font.h?

Hola @phentium ,

Las cuestiones relacionadas con el orden de declaración de funciones y la necesidad de prototipos están relacionadas con la compilación: compilador y versión, opciones de compilación y nivel de tolerancia configurable. En ambientes de desarrollo como el Arduino IDE en general ni te enteras de la configuración de esas opciones a menos que las busques.

Uno de los motivos por los que se configura la exigencia (o no) del prototipo es la verificación de los tipos en los parámetros de una función. Llegas al uso de una función que no ha sido declarada anteriormente y el compilador no puede hacer el chequeo de los tipos de datos que le estás pasando hasta no haber visto la función. Por configuración el compilador puede esperar a tener todos el código revisado y luego verificar si están correctos los tipos de los parámetros pasados. Para los códigos muy largos eso implica pasar un largo tiempo esperando la compilación para que falle por algo que se podía evitar desde el principio!! Por eso se puede configurar el compilador para que cancele la compilación y marque el error antes de seguir adelante.

El otro motivo totalmente relacionado con el anterior pero que es aún más importante en lenguajes como el C++ es el siguiente: la firma de la función. Puedes tener dos funciones, con el mismo nombre, y que devuelvan tipos distintos, pero cuyos parámetros sean distintos, y ejecuten códigos totalmente distintos según los tipos de los parámetros que se les pase. El compilador llega al punto en que se utiliza la función y se pregunta: esta función es una para la cual tengo indicado el código que voy a tener que ejecutar? Esta "Firma" de función está contemplada?.... de nuevo, compilar todo para encontrarse que se trata sólo de un error en el cual el desarrollador puso uint en lugar de int... es evitable.

Por último tienes cuestiones como los #include xxx donde es posible que la función ya esté declarada o prototipada. Tu no lo ves a simple vista, pero el prototipo ya ha sido presentado.

Buena suerte!
Gaby.//

Github: /GabyGold67
bool supercalifragilisticexpialidocious{true}: error - wrong variable name
bool superCaliFragilisticExpialiDocious{true}: 0 errors - 0 warnings

Please and thank you, they're the magic words

¡¡¡ Valiosa informacion ¡¡¡
Muchisims gracis ¡¡¡.

Cada día me amargo mas con algunas nuevas personas del foro a quien uno quiere ayudar.

Gracias por la respuesta, en su momento simulé todo, busqué por varios minutos archivos parecidos sin resultados, todo para que la persona a la que quiero ayudar me ignore y solo debe mirar una simple respuesta publicada hace 11dias de 2 nuevas que tenía.
Aclaro, ahora no hace falta.

Non calentarum largo vivirem. :wink:

Hola @Surbyte ,

Yo soy bastante nuevo en este foro (y tú tienes mucha experiencia) y no quiero derivar en temas filosóficos, pero una de las pocas formas que he encontrado para no amargarme es pensar que lo que hago lo hago por mi voluntad y placer. El resto, si viene, es extra.

Eso sí, hay días que la filosofía Zen se me va de paséo y...

Buena Suerte!

Gaby.//

Lamento mucho no haberte contestado en su momento. No te he ignorado, simplemente no he visto ese post tuyo hasta hace 10 minutos.
Soy muy nuevo en este foro y no me aclaro demasiado. A eso súmale 70 años y quizás lo entiendas.
He estado muchos años en otros foros que nada tienen que ver con Arduino y se el esfuerzo que significa para el moderador. Tiempo, formación y paciencia. Puedes estar bien seguro que merecen todos mis respetos.
Lo de que el archivo FreeFonts.h ya no te interesa no sé si es que ya lo has encontrado o que realmente has perdido el interés. Ahora no puedo, pero está noche o mañana intento enviarlo.
Reitero mis excusas.