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");
}