#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <SPI.h>
// --- Pines de la pantalla TFT ---
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
// --- Pines para los Pulsadores ---
#define BTN1_PIN 32 // Pulsador 1: +5
#define BTN2_PIN 33 // Pulsador 2: -10
#define BTN3_PIN 34 // Pulsador 3: -15
#define BTN4_PIN 35 // Pulsador 4: +20
// Instancia de la pantalla TFT
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// --- Variables para las Interrupciones ---
volatile int counter = 1821;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
// Variables para el anti-rebote (debounce)
volatile unsigned long last_btn1_time = 0;
volatile unsigned long last_btn2_time = 0;
volatile unsigned long last_btn3_time = 0;
volatile unsigned long last_btn4_time = 0;
#define DEBOUNCE_TIME 200 // 200ms de anti-rebote
// --- Funciones de Interrupción (ISR) ---
// ISR para G32 (+5)
void IRAM_ATTR isr_Button1() {
unsigned long interrupt_time = millis();
if (interrupt_time - last_btn1_time > DEBOUNCE_TIME) {
portENTER_CRITICAL_ISR(&timerMux);
counter += 5;
portEXIT_CRITICAL_ISR(&timerMux);
last_btn1_time = interrupt_time;
}
}
// ISR para G33 (-10)
void IRAM_ATTR isr_Button2() {
unsigned long interrupt_time = millis();
if (interrupt_time - last_btn2_time > DEBOUNCE_TIME) {
portENTER_CRITICAL_ISR(&timerMux);
counter -= 10;
portEXIT_CRITICAL_ISR(&timerMux);
last_btn2_time = interrupt_time;
}
}
// ISR para G34 (-15)
void IRAM_ATTR isr_Button3() {
unsigned long interrupt_time = millis();
if (interrupt_time - last_btn3_time > DEBOUNCE_TIME) {
portENTER_CRITICAL_ISR(&timerMux);
counter -= 15;
portEXIT_CRITICAL_ISR(&timerMux);
last_btn3_time = interrupt_time;
}
}
// ISR para G35 (+20)
void IRAM_ATTR isr_Button4() {
unsigned long interrupt_time = millis();
if (interrupt_time - last_btn4_time > DEBOUNCE_TIME) {
portENTER_CRITICAL_ISR(&timerMux);
counter += 20;
portEXIT_CRITICAL_ISR(&timerMux);
last_btn4_time = interrupt_time;
}
}
// --- Configuración Inicial ---
void setup() {
Serial.begin(115200);
// --- Configurar Pines de Pulsadores ---
pinMode(BTN1_PIN, INPUT_PULLUP);
pinMode(BTN2_PIN, INPUT_PULLUP);
pinMode(BTN3_PIN, INPUT); // Requiere PULL-UP EXTERNA
pinMode(BTN4_PIN, INPUT); // Requiere PULL-UP EXTERNA
// Inicializar la pantalla TFT
tft.begin();
tft.fillScreen(ILI9341_BLACK);
tft.setRotation(1); // Orientación horizontal (320x240)
// Dibujar la interfaz estática
drawUIFrame();
// Dibujar el valor inicial del contador
updateCounter(counter);
// --- Configurar las Interrupciones ---
attachInterrupt(digitalPinToInterrupt(BTN1_PIN), isr_Button1, FALLING);
attachInterrupt(digitalPinToInterrupt(BTN2_PIN), isr_Button2, FALLING);
attachInterrupt(digitalPinToInterrupt(BTN3_PIN), isr_Button3, FALLING);
attachInterrupt(digitalPinToInterrupt(BTN4_PIN), isr_Button4, FALLING);
}
// Variable para el Bucle Principal
int lastCounter = 1821;
// --- Bucle Principal ---
void loop() {
// Copia segura de la variable volátil
int currentCounter;
portENTER_CRITICAL(&timerMux);
currentCounter = counter;
portEXIT_CRITICAL(&timerMux);
// --- Lógica de la Pantalla TFT ---
// Solo actualizamos la TFT si el contador ha cambiado
if (currentCounter != lastCounter) {
updateCounter(currentCounter); // Actualiza la HMI
lastCounter = currentCounter; // Guardamos el nuevo valor
}
delay(10);
}
// --- Funciones de la Interfaz Gráfica (HMI) ---
/**
* Dibuja el marco estático de la interfaz.
*/
void drawUIFrame() {
// Encabezado
tft.fillRect(0, 0, tft.width(), 40, ILI9341_BLUE);
tft.drawFastHLine(0, 40, tft.width(), ILI9341_WHITE);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.setCursor(20, 12);
tft.print("Ejercicio 3: Contador");
// Etiqueta para el Contador
tft.setTextColor(ILI9341_CYAN);
tft.setTextSize(2);
tft.setCursor(20, 70);
tft.print("Valor Actual:");
// --- INICIO DE CÓDIGO AÑADIDO ---
// Dibuja el nombre del autor en la parte inferior
tft.setTextColor(ILI9341_YELLOW); // Un color diferente para el autor
tft.setTextSize(1); // Un tamaño de texto más pequeño
// Posiciona el cursor en la esquina inferior izquierda (con un pequeño margen)
// La pantalla mide 240 de alto (en rotación 1), así que 230 está abajo.
tft.setCursor(10, 230);
tft.print("Autor: JOSUE CARDENAS AGUIRRE");
// --- FIN DE CÓDIGO AÑADIDO ---
}
/**
* Actualiza SOLO el valor del contador en la pantalla.
*/
void updateCounter(int value) {
// Dibuja un rectángulo negro para borrar el número anterior
tft.fillRect(20, 100, 280, 80, ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(7); // Fuente grande
tft.setCursor(20, 110);
tft.print(value);
}