Error al cambiar de menu en una pantalla ili9486

Hola, soy nuevo en esto de los foros pido perdon si he cometido algun fallo a la hora de escribir esta publicación.
Estoy desarrollando un proyecto en el que uso una pantalla Ili9486 y un Arduino Mega.
El código funciona de la siguiente manera: al iniciar el código muestra un gráfico circular con valores prefijados hasta que me lleguen los sensores.
El tema es que cuando le doy al botón que sale en la esquina en vez de cambiar a la siguiente pantalla, se queda con la pantalla en blanco, en vez de mostrar una pantalla en la que se configuren cinco parámetros.

Por último, uso la versión de Adafruit GFX 1.11.10 y de MCUFRIEND la 3.0.0-release.

Muchas gracias de antemano.

#include <MCUFRIEND_kbv.h>  // Biblioteca para la pantalla
#include <Adafruit_GFX.h>   // Biblioteca para gráficos
#include <TouchScreen.h>    // Biblioteca para pantalla táctil

MCUFRIEND_kbv tft;

int ancho = 480;            // Ancho de la pantalla (en píxeles)
int alto = 320;             // Alto de la pantalla (en píxeles)

// Simulación de datos de temperatura y humedad
float tempAgua = 25.0;
float tempSecaCaliente = 30.0;
float tempSeca = 22.0;
float humedadSecaCaliente = 55.0;
float humedadSeca = 45.0;

// Pines del touch (ajusta según tu configuración)
const int XP = 8, XM = A2, YP = A3, YM = 9;  // Pines de control táctil

// Calibración del touchscreen (valores proporcionados)
const int TS_TOP = 951, TS_BOT = 85;     // Valores eje Y táctil
const int TS_LEFT = 920, TS_RT = 122;    // Valores eje X táctil

// Crear objeto de la pantalla táctil
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define MINPRESSURE 10
#define MAXPRESSURE 1000

// Variable para controlar el estado de la pantalla (1: gráfico circular, 2: menú de configuración)
int pantallaActual = 1;
bool pantallaInicializada = false; // Nueva bandera para evitar refrescos innecesarios

// Variables de temporización para controlar la actualización
unsigned long tiempoAnterior = 0;  // Almacena el último tiempo de actualización
const unsigned long intervaloActualizacion = 15000;  // Intervalo de actualización en milisegundos (15 segundos)

// Prototipos de las funciones
void pantallaPrincipal();
void pantallaMenuConfiguracion();
void limpiarPantallaCompleta();

// Variables globales para los parámetros configurables
int parametro1 = 10;
int parametro2 = 20;
int parametro3 = 30;
int parametro4 = 40;
int parametro5 = 50;

void setup() {
  Serial.begin(9600);

  // Inicializar pantalla con ID específico
  uint16_t id = tft.readID();

  // Forzar ID si no se detecta correctamente
  if (id == 0xD3D3 || id == 0xFFFF) {
    id = 0x9486;  // ID para ILI9486
  }

  tft.begin(id);
  tft.setRotation(1);        // Modo horizontal
  delay(500);                // Dar tiempo a la pantalla para estabilizarse

  // Limpiar pantalla solo si no ha sido inicializada aún
  if (!pantallaInicializada) {
    tft.fillScreen(TFT_BLACK); // Fondo negro
    pantallaPrincipal();       // Dibujar la primera pantalla (gráfico circular)
    pantallaInicializada = true; // Marcar que ya está inicializada
  }
}

void loop() {
  // Leer el touch
  TSPoint p = ts.getPoint();  // Leer los datos táctiles

  // Verificar si hay presión en la pantalla táctil
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
    // Mapear las coordenadas del touch a las de la pantalla
    int x = map(p.y, 951, 85, 0, ancho);  // Ajusta según la calibración
    int y = map(p.x, 920, 122, 0, alto);  // Ajusta según la calibración

    // Verificar en qué pantalla estamos y ejecutar la lógica correspondiente
    if (pantallaActual == 1) {
      // Pantalla principal - verificar si se presionó el botón de configuración
      if (x >= (ancho - 70) && y < 40) {
        pantallaActual = 2;  // Cambiar a la pantalla de configuración
        limpiarPantallaCompleta();  // Limpiar la pantalla completamente
        pantallaMenuConfiguracion();  // Mostrar la pantalla de configuración
      }
    } 
    else if (pantallaActual == 2) {
      // Pantalla de configuración - verificar botones de parámetros y retroceso
      if (x < 70 && y < 40) {  // Botón de retroceso en la esquina superior izquierda
        pantallaActual = 1;  // Cambiar a la pantalla principal
        limpiarPantallaCompleta();  // Limpiar la pantalla completamente
        pantallaPrincipal(); // Mostrar la pantalla principal
      } else {
        verificarToqueBotonesConfiguracion(x, y);  // Detectar interacción con parámetros (debes agregar esta función)
      }
    }
  }

  delay(50);  // Pequeña pausa para evitar saturar el microcontrolador
}

// Función para limpiar la pantalla antes de cambiar de pantalla
void limpiarPantallaCompleta() {
  // Llenar toda la pantalla con un color negro antes de dibujar cualquier otra pantalla
  tft.fillScreen(TFT_BLACK);
  delay(100);  // Pequeña pausa para asegurar que se actualice correctamente
}

// Función para dibujar la pantalla principal
void pantallaPrincipal() {
  tft.fillScreen(TFT_BLACK);  // Limpiar la pantalla
  // Aquí va el código para dibujar el gráfico circular o la pantalla principal
  mostrarGraficoCircular(tempAgua, tempSecaCaliente, tempSeca, humedadSecaCaliente, humedadSeca);
  mostrarLeyendaInferior();  // Dibujar la leyenda
  dibujarBotonConfiguracion();  // Dibujar el botón de configuración
}

// Función para dibujar la pantalla de menú de configuración
void pantallaMenuConfiguracion() {
  tft.fillScreen(TFT_BLACK);  // Limpiar la pantalla antes de dibujar el menú de configuración
  tft.setTextColor(TFT_WHITE);  // Color de texto blanco
  tft.setTextSize(2);  // Tamaño del texto

  // Etiquetas y valores iniciales de los parámetros
  dibujarParametro(1, "Parametro 1", parametro1);
  dibujarParametro(2, "Parametro 2", parametro2);
  dibujarParametro(3, "Parametro 3", parametro3);
  dibujarParametro(4, "Parametro 4", parametro4);
  dibujarParametro(5, "Parametro 5", parametro5);

  // Dibujar el botón de retroceso
  dibujarBotonRetroceso();
}

// Dibujar parámetro y botones de cambio
void dibujarParametro(int numero, const char* nombre, int valor) {
  int margenIzquierdo = 20;
  int margenSuperior = 50 + (numero - 1) * 50;

  // Dibujar fondo negro para cada parámetro
  tft.fillRect(margenIzquierdo, margenSuperior - 5, 300, 30, TFT_BLACK);

  // Etiqueta del parámetro
  tft.setCursor(margenIzquierdo, margenSuperior);
  tft.print(nombre);

  // Valor del parámetro
  tft.setCursor(margenIzquierdo + 160, margenSuperior);
  tft.print(valor);

  // Dibujar botones con colores visibles
  int botonAncho = 30;
  int botonAlto = 30;

  tft.fillRect(margenIzquierdo + 220, margenSuperior - 5, botonAncho, botonAlto, TFT_GREEN);  // Botón "+"
  tft.fillRect(margenIzquierdo + 260, margenSuperior - 5, botonAncho, botonAlto, TFT_RED);    // Botón "-"
}

// Verificar la interacción con los botones de parámetros
void verificarToqueBotonesConfiguracion(int x, int y) {
  int margenIzquierdo = 240;  // Posición en X de los botones "+"
  int margenSuperior = 50;    // Posición base en Y de los botones
  int botonAncho = 30;
  int botonAlto = 30;
  int espaciadoVertical = 50;  // Espaciado entre los botones de cada parámetro

  // Verificar cada parámetro
  for (int i = 1; i <= 5; i++) {
    int yPos = margenSuperior + (i - 1) * espaciadoVertical;

    // Botón "+" del parámetro
    if (x >= margenIzquierdo && x <= (margenIzquierdo + botonAncho) && y >= yPos && y <= (yPos + botonAlto)) {
      switch (i) {
        case 1: parametro1++; break;
        case 2: parametro2++; break;
        case 3: parametro3++; break;
        case 4: parametro4++; break;
        case 5: parametro5++; break;
      }
      actualizarPantallaParametros();
    }

    // Botón "-" del parámetro
    if (x >= (margenIzquierdo + 40) && x <= (margenIzquierdo + 40 + botonAncho) && y >= yPos && y <= (yPos + botonAlto)) {
      switch (i) {
        case 1: parametro1--; break;
        case 2: parametro2--; break;
        case 3: parametro3--; break;
        case 4: parametro4--; break;
        case 5: parametro5--; break;
      }
      actualizarPantallaParametros();
    }
  }
}

// Actualizar los parámetros en pantalla
void actualizarPantallaParametros() {
  dibujarParametro(1, "Parametro 1", parametro1);
  dibujarParametro(2, "Parametro 2", parametro2);
  dibujarParametro(3, "Parametro 3", parametro3);
  dibujarParametro(4, "Parametro 4", parametro4);
  dibujarParametro(5, "Parametro 5", parametro5);
}




// Función para dibujar el botón de configuración en la esquina superior derecha
void dibujarBotonConfiguracion() {
  int botonAncho = 40;  // Ancho del botón
  int botonAlto = 40;   // Alto del botón
  int margen = 10;      // Margen desde el borde de la pantalla

  int xPos = ancho - botonAncho - margen;  // Coordenada X para la esquina superior derecha
  int yPos = margen;  // Coordenada Y para la esquina superior derecha

  tft.fillRect(xPos, yPos, botonAncho, botonAlto, 0xF800);  // Dibujar botón rojo
  tft.drawRect(xPos, yPos, botonAncho, botonAlto, 0xFFFF);  // Borde blanco
  tft.fillTriangle(xPos + 10, yPos + 10, xPos + 10, yPos + 30, xPos + 30, yPos + 20, 0xFFFF);  // Flecha blanca
}

// Función para dibujar el botón de retroceso en la esquina superior izquierda
void dibujarBotonRetroceso() {
  int anchoBoton = 60;
  int altoBoton = 30;
  tft.fillRect(10, 10, anchoBoton, altoBoton, TFT_RED);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.setCursor(20, 20);
  tft.print("Back");
}



// Función para dibujar la gráfica circular
void mostrarGraficoCircular(float tempAgua, float tempSecaCaliente, float tempSeca, float humSecaCaliente, float humSeca) {
  int centroX = ancho / 2;  // Centrar el gráfico en X (horizontalmente)
  int centroY = alto / 2 - 40;   // Centrar el gráfico en Y, dejando espacio para la leyenda abajo
  int radio = 100;          // Radio exterior del gráfico
  int radioInterior = 50;   // Radio interior (gráfico tipo "doughnut")

  float total = tempAgua + tempSecaCaliente + tempSeca + humSecaCaliente + humSeca;

  // Ángulos para cada segmento
  float anguloTempAgua = 360 * (tempAgua / total);
  float anguloTempSecaCaliente = 360 * (tempSecaCaliente / total);
  float anguloTempSeca = 360 * (tempSeca / total);
  float anguloHumSecaCaliente = 360 * (humSecaCaliente / total);
  float anguloHumSeca = 360 * (humSeca / total);

  // Dibujar cada segmento del gráfico circular
  dibujarSegmento(centroX, centroY, radio, radioInterior, 0, anguloTempAgua, TFT_BLUE);
  dibujarSegmento(centroX, centroY, radio, radioInterior, anguloTempAgua, anguloTempAgua + anguloTempSecaCaliente, TFT_RED);
  dibujarSegmento(centroX, centroY, radio, radioInterior, anguloTempAgua + anguloTempSecaCaliente, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca, TFT_GREEN);
  dibujarSegmento(centroX, centroY, radio, radioInterior, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca + anguloHumSecaCaliente, TFT_YELLOW);
  dibujarSegmento(centroX, centroY, radio, radioInterior, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca + anguloHumSecaCaliente, 360, TFT_ORANGE);

  // Dibujar flechas y valores para cada segmento
  dibujarFlechaYValor(centroX, centroY, radio, anguloTempAgua / 2, TFT_BLUE, tempAgua);
  dibujarFlechaYValor(centroX, centroY, radio, anguloTempAgua + anguloTempSecaCaliente / 2, TFT_RED, tempSecaCaliente);
  dibujarFlechaYValor(centroX, centroY, radio, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca / 2, TFT_GREEN, tempSeca);
  dibujarFlechaYValor(centroX, centroY, radio, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca + anguloHumSecaCaliente / 2, TFT_YELLOW, humSecaCaliente);
  dibujarFlechaYValor(centroX, centroY, radio, anguloTempAgua + anguloTempSecaCaliente + anguloTempSeca + anguloHumSecaCaliente + anguloHumSeca / 2, TFT_ORANGE, humSeca);
}

// Función para dibujar segmentos circulares
void dibujarSegmento(int cx, int cy, int radioExterno, int radioInterior, float angInicio, float angFin, uint16_t color) {
  for (float ang = angInicio; ang < angFin; ang++) {
    for (int r = radioInterior; r < radioExterno; r++) {
      int x = cx + r * cos(ang * PI / 180);
      int y = cy + r * sin(ang * PI / 180);
      tft.drawPixel(x, y, color);
    }
  }
}

// Función para dibujar flechas y mostrar valores
void dibujarFlechaYValor(int cx, int cy, int radio, float angulo, uint16_t color, float valor) {
  int xInicio = cx + radio * cos(angulo * PI / 180);
  int yInicio = cy + radio * sin(angulo * PI / 180);
  int radioFlecha = radio + 20;
  int xFin = cx + radioFlecha * cos(angulo * PI / 180);
  int yFin = cy + radioFlecha * sin(angulo * PI / 180);

  // Dibujar flecha
  tft.drawLine(xInicio, yInicio, xFin, yFin, color);

  // Mostrar el valor al final de la flecha
  tft.setTextSize(2);
  tft.setTextColor(color);

  if (angulo >= 0 && angulo <= 90) {
    tft.setCursor(xFin + 10, yFin + 5);
  } else if (angulo > 90 && angulo <= 180) {
    tft.setCursor(xFin - 40, yFin + 5);
  } else if (angulo > 180 && angulo <= 270) {
    tft.setCursor(xFin - 40, yFin - 15);
  } else {
    tft.setCursor(xFin + 10, yFin - 15);
  }

  tft.print(valor, 1);
}

// Función para mostrar la leyenda en la parte inferior con mejor espaciado
void mostrarLeyendaInferior() {
  tft.setTextSize(1);
  tft.setTextColor(TFT_WHITE);

  // Coordenadas de la leyenda
  int yPosSuperior = alto - 30;  // Posición Y de la fila superior
  int yPosInferior = alto - 15;  // Posición Y de la fila inferior
  int xPos = 10;                 // Posición inicial en X

  // Espacio entre elementos en X e Y
  int espaciadoX = 130;  // Espaciado horizontal mayor para evitar solapamiento
  int espaciadoY = 18;   // Espaciado vertical entre filas

  // Dibujar la primera fila de la leyenda
  tft.fillCircle(xPos, yPosSuperior, 5, TFT_BLUE);
  tft.setCursor(xPos + 10, yPosSuperior - 5);
  tft.print("Temperatura Agua");

  xPos += espaciadoX;  // Incrementar posición en X para el siguiente elemento
  tft.fillCircle(xPos, yPosSuperior, 5, TFT_RED);
  tft.setCursor(xPos + 10, yPosSuperior - 5);
  tft.print("Temperatura zona 1");

  xPos += espaciadoX;  // Incrementar posición en X para el siguiente elemento
  tft.fillCircle(xPos, yPosSuperior, 5, TFT_GREEN);
  tft.setCursor(xPos + 10, yPosSuperior - 5);
  tft.print("Temperatura zona 2");

  // Resetear posición en X para la segunda fila
  xPos = 10;  
  yPosSuperior += espaciadoY;  // Bajar la fila para los siguientes elementos

  // Dibujar la segunda fila de la leyenda
  tft.fillCircle(xPos, yPosSuperior, 5, TFT_YELLOW);
  tft.setCursor(xPos + 10, yPosSuperior - 5);
  tft.print("Humedad zona 1");

  xPos += espaciadoX;  // Incrementar posición en X para el siguiente elemento
  tft.fillCircle(xPos, yPosSuperior, 5, TFT_ORANGE);
  tft.setCursor(xPos + 10, yPosSuperior - 5);
  tft.print("Humedad zona 2");
}

Para ir corrigiendo

  // Limpiar pantalla solo si no ha sido inicializada aún
  if (!pantallaInicializada) {
    tft.fillScreen(TFT_BLACK); // Fondo negro
    pantallaPrincipal();       // Dibujar la primera pantalla (gráfico circular)
    pantallaInicializada = true; // Marcar que ya está inicializada
  }

En setup() no hay manera de que la pantalla ya se haya inicializado, no tiene sentido usar la variable pantallaInicializada ya que al ejecutar la comparación siempre va a contener false (o sea que siempre se va a cumplir la condición) y además no se usa para otro propósito, cambiarle el valor a true es irrelevante.


  int x = map(p.y, 951, 85, 0, ancho);  // Ajusta según la calibración
  int y = map(p.x, 920, 122, 0, alto);  // Ajusta según la calibración

Están cambiadas las variables usadas en ambas instrucciones map().
Debería ser

  int x = map(p.x, 951, 85, 0, ancho); // ...
  int y = map(p.y, 920, 122, 0, alto);  // ...

Si pantallaActual solo puede contener los valores 1 ó 2 entonces

if (pantallaActual == 1) {
// ...
}
else if (pantallaActual == 2) {
// ...
}

no tiene sentido, alcanza solo con

if (pantallaActual == 1) {
// ...
}
else {  // entonces pantallaActual == 2
// ...
}

Y si planeas agregar más pantallas, es mejor usar switch()

Hola, aplique los cambios que sugeriste y el primero el de eliminar el if, no permitia que la pantalla cargase si lo eliminaba por lo que lo tuve que revertir y los demás sí que funcionaron, pero el problema que explique que tengo persiste, que es que una vez que carga la pantalla principal por completo y le doy al botón que aparece en ella, la pantalla se queda en blanco en vez de cambiar y mostrarme la pantalla de menú de configuración.