// =========================================================================
// == PROYECTO TAREA 5: SECUENCIA DE CARGA Y DESCARGA DE LEDs ==
// =========================================================================
// Autor: Josue Cardenas Aguirre (Adaptado por Gemini)
// Descripción: Simulación de 16 LEDs que se encienden secuencialmente de
// izquierda a derecha y se apagan de derecha a izquierda.
// =========================================================================
// --- LIBRERÍAS ---
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_SSD1306.h>
// =========================================================================
// == CONFIGURACIÓN GENERAL ==
// =========================================================================
// --- PINES DE CONEXIÓN ---
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
#define POT_PIN 34
// --- CONFIGURACIÓN OLED ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
// --- CONFIGURACIÓN DE LA ANIMACIÓN ---
const int NUM_LEDS = 16;
const int SPEED_MIN = 20;
const int SPEED_MAX = 250;
const int PAUSE_FACTOR = 4; // Pausa al estar lleno o vacío
// --- CONFIGURACIÓN VISUAL (TFT) ---
#define FOOTER_HEIGHT 40
#define COLOR_BACKGROUND 0xCE79 // Azul claro/grisáceo
#define COLOR_FOOTER 0x2104 // Azul oscuro
#define COLOR_TEXT_TITLE ILI9341_WHITE
#define COLOR_TEXT_AUTHOR ILI9341_LIGHTGREY
#define COLOR_LED_ON ILI9341_RED
#define COLOR_LED_OFF ILI9341_WHITE
#define COLOR_BORDER 0x4A49
const int LED_WIDTH = 12; // LEDs rectangulares
const int LED_HEIGHT = 12;
const int LED_SPACING = 4;
// =========================================================================
// == INSTANCIAS Y VARIABLES ==
// =========================================================================
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
enum AnimationState { LOADING, PAUSE_FULL, UNLOADING, PAUSE_EMPTY };
AnimationState currentState = LOADING;
const char* statusMessage = "Cargando...";
unsigned long lastUpdateTime = 0;
int animationStep = 0; // Representa el número de LEDs encendidos/apagados
long cycleCount = 0;
int startX, startY;
// =========================================================================
// == FUNCIONES DE VISUALIZACIÓN ==
// =========================================================================
void drawTFTFooter() {
tft.fillRect(0, tft.height() - FOOTER_HEIGHT, tft.width(), FOOTER_HEIGHT, COLOR_FOOTER);
tft.setTextSize(2);
tft.setTextColor(COLOR_TEXT_TITLE);
tft.setCursor(25, tft.height() - 28);
tft.print("Control secuencial 16 leds");
tft.setTextSize(1);
tft.setTextColor(COLOR_TEXT_AUTHOR);
tft.setCursor(80, tft.height() - 12);
tft.print("JOSUE CARDENAS AGUIRRE");
}
void updateOLED(long speed_ms) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
int speedPercent = map(speed_ms, SPEED_MAX, SPEED_MIN, 0, 100);
display.setCursor(0, 2);
display.print("Velocidad: ");
display.print(speedPercent);
display.print("% (");
display.print(speed_ms);
display.print("ms)");
int barWidth = map(speedPercent, 0, 100, 0, 100);
display.drawRect(14, 15, 102, 8, SSD1306_WHITE);
display.fillRect(15, 16, barWidth, 6, SSD1306_WHITE);
display.setCursor(0, 32);
display.print("Estado: ");
display.print(statusMessage);
display.setCursor(0, 48);
display.print("LEDs Encendidos: ");
// Mostrar el conteo correcto según la fase
int ledsOn = (currentState == LOADING) ? animationStep : (NUM_LEDS - animationStep);
if (currentState == PAUSE_FULL) ledsOn = NUM_LEDS;
if (currentState == PAUSE_EMPTY) ledsOn = 0;
display.print(ledsOn);
display.display();
}
void drawLed(int index, uint16_t fillColor) {
int ledX = startX + index * (LED_WIDTH + LED_SPACING);
tft.fillRect(ledX, startY, LED_WIDTH, LED_HEIGHT, fillColor);
tft.drawRect(ledX, startY, LED_WIDTH, LED_HEIGHT, COLOR_BORDER);
}
// =========================================================================
// == PROGRAMA PRINCIPAL ==
// =========================================================================
void setup() {
tft.begin();
tft.setRotation(1);
tft.fillScreen(COLOR_BACKGROUND);
drawTFTFooter();
int totalLedsWidth = NUM_LEDS * LED_WIDTH + (NUM_LEDS - 1) * LED_SPACING;
int drawingAreaHeight = tft.height() - FOOTER_HEIGHT;
startX = (tft.width() - totalLedsWidth) / 2;
startY = (drawingAreaHeight / 2) - (LED_HEIGHT / 2);
for (int i = 0; i < NUM_LEDS; i++) {
drawLed(i, COLOR_LED_OFF);
}
Wire.begin();
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { for(;;); }
}
void loop() {
long animationInterval = map(analogRead(POT_PIN), 0, 4095, SPEED_MAX, SPEED_MIN);
updateOLED(animationInterval);
unsigned long interval = (currentState == PAUSE_FULL || currentState == PAUSE_EMPTY) ? (animationInterval * PAUSE_FACTOR) : animationInterval;
if (millis() - lastUpdateTime < interval) return;
lastUpdateTime = millis();
switch (currentState) {
case LOADING: {
statusMessage = "Cargando...";
// Encender el LED correspondiente al paso actual
drawLed(animationStep, COLOR_LED_ON);
animationStep++;
if (animationStep >= NUM_LEDS) {
animationStep = 0;
currentState = PAUSE_FULL;
}
break;
}
case PAUSE_FULL:
statusMessage = "Pausa (Lleno)";
currentState = UNLOADING;
break;
case UNLOADING: {
statusMessage = "Descargando...";
// Apagar el LED desde la derecha. Índice es (15 - paso)
drawLed(NUM_LEDS - 1 - animationStep, COLOR_LED_OFF);
animationStep++;
if (animationStep >= NUM_LEDS) {
animationStep = 0;
currentState = PAUSE_EMPTY;
}
break;
}
case PAUSE_EMPTY:
statusMessage = "Pausa (Vacio)";
cycleCount++;
currentState = LOADING;
break;
}
}