Descripción General: Este proyecto integra múltiples periféricos sobre una placa Arduino (Mega 2560): una barra de 9 diodos LED con diversos patrones de animación, 4 pulsadores físicos y un teclado matricial 4x4 como dispositivos de entrada, un sensor ambiental DHT11 (temperatura y humedad), y una pantalla gráfica GLCD ST7920 (128x64 píxeles) orientada a 180° (U8G2_R2) controlada por Software SPI mediante la librería U8g2. La conversión de valores decimales para la pantalla se realiza mediante dtostrf para garantizar la compatibilidad con microcontroladores AVR.
Distribución de entradas, salidas y líneas de comunicación con el microcontrolador:
| Módulo / Dispositivo | Pines en Arduino | Tipo / Señal | Modo / Configuración |
|---|---|---|---|
| Barra de 9 LEDs | 13, 12, 11, 10, 9, 8, 7, 6, 5 | Salidas Digitales | OUTPUT (Nivel HIGH enciende el LED) |
| 4 Pulsadores Físicos | 28, 26, 24, 22 | Entradas Digitales | INPUT_PULLUP (Activos a nivel LOW al pulsar) |
| Teclado Matricial 4x4 (Filas) | 23, 25, 27, 29 | Filas R1, R2, R3, R4 | Gestionado por librería Keypad |
| Teclado Matricial 4x4 (Columnas) | 31, 33, 35, 37 | Columnas C1, C2, C3, C4 | Gestionado por librería Keypad |
| Sensor DHT11 | Pin 41 | Señal de Datos (Data) | Unidireccional digital + VCC (5V) + GND |
| Pantalla GLCD ST7920 (128x64) | 50 (RS / CS), 51 (R/W / DATA), 53 (E / CLK) | SPI Serie por Software | Modo serie: Rotación 180° (U8G2_R2) + VCC/GND |
El sistema permite el control de los modos de iluminación tanto a través de los 4 pulsadores cableados directamente a las entradas digitales con pull-up, como a través del teclado matricial 4x4.
| Fila \ Col | Col 1 (Pin 31) | Col 2 (Pin 33) | Col 3 (Pin 35) | Col 4 (Pin 37) |
|---|---|---|---|---|
| Fila 1 (Pin 23) | '1' (Modo 0) | '2' (Modo 1) | '3' (Modo 2) | 'A' |
| Fila 2 (Pin 25) | '4' (Modo 3) | '5' | '6' | 'B' |
| Fila 3 (Pin 27) | '7' | '8' | '9' | 'C' |
| Fila 4 (Pin 29) | '*' | '0' | '#' | 'D' |
| Modo | Pulsador Físico (Pin) | Tecla Matricial | Última Tecla Registrada | Acción sobre los LEDs |
|---|---|---|---|---|
| 0 | Pulsador 0 (Pin 28) | '1' | '1' | Enciende todos los 9 LEDs simultáneamente |
| 1 | Pulsador 1 (Pin 26) | '2' | '2' | Apaga todos los LEDs (Estado de reposo por defecto) |
| 2 | Pulsador 2 (Pin 24) | '3' | '3' | Animación Secuencial (un solo LED desplazándose) |
| 3 | Pulsador 3 (Pin 22) | '4' | '4' | Animación Acumulativa (relleno progresivo de la barra) |
Lógica de Animación (Función actualizarLeds()):
Los modos 0 y 1 son estados fijos (estáticos). Los modos 2 y 3 ejecutan secuencias temporizadas cada 300 ms (INTERVALO_LED) sin detener el procesador:
leds[ledActual]. A cada paso se incrementa ledActual; al alcanzar el noveno LED vuelve cíclicamente a 0.Se utiliza la librería U8g2 en modo búfer completo con Software SPI y rotación de 180° (U8G2_ST7920_128X64_F_SW_SPI pantalla(U8G2_R2, ...)).
| Línea / Coordenada Y | Texto / Formato | Fuente | Descripción |
|---|---|---|---|
| Y = 10 px | Practica 3 EMP |
u8g2_font_6x10_tf | Encabezado principal fijo del proyecto |
| Y = 27 px | Temp: XX.X C |
u8g2_font_6x10_tf | Temperatura leída formateada con dtostrf |
| Y = 40 px | Hum: XX.X % |
u8g2_font_6x10_tf | Humedad relativa leída formateada con dtostrf |
| Y = 53 px | Ultima Tecla: X |
u8g2_font_6x10_tf | Último botón físico o tecla pulsada ('0', '1', '2', '3', '4') |
Formateo de Floats en AVR: Debido a que snprintf no soporta especificadores %f en Arduino AVR por defecto, se utiliza la función nativa dtostrf() para transformar las variables de temperatura y humedad en arreglos de caracteres (c-strings) antes de concatenarlas:
Para evitar retrasos en la respuesta a las pulsaciones y mantener fluidas las animaciones de los LEDs y el refresco de pantalla, el programa prescinde completamente de la función delay() y utiliza el temporizador del sistema millis():
| Tarea Concurrente | Intervalo | Variable de Control | Función Asociada |
|---|---|---|---|
| Animación de LEDs | 300 ms | tiempoLED |
actualizarLeds() |
| Actualización de Pantalla | 500 ms | tiempoPantalla |
actualizarPantalla() |
| Muestreo Sensor DHT11 | 2000 ms | tiempoDHT |
actualizarDHT() |
| Lectura de Pulsadores y Teclado | Tiempo real (cada ciclo) | Inmediata | leerBotones(), leerTeclado() |
#include <Keypad.h>
#include <DHT.h>
#include <U8g2lib.h>
// ==========================================
// 1. PINES DE LOS LED
// ==========================================
const int leds[] = {13, 12, 11, 10, 9, 8, 7, 6, 5};
const int NUM_LEDS = sizeof(leds) / sizeof(leds[0]);
// ==========================================
// 2. PULSADORES FISICOS
// ==========================================
const int botones[] = {28, 26, 24, 22};
const int NUM_BOTONES = sizeof(botones) / sizeof(botones[0]);
// ==========================================
// 3. TECLADO MATRICIAL 4x4
// ==========================================
const byte FILAS = 4;
const byte COLUMNAS = 4;
char teclas[FILAS][COLUMNAS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte pinesFilas[FILAS] = {23, 25, 27, 29};
byte pinesColumnas[COLUMNAS] = {31, 33, 35, 37};
Keypad teclado = Keypad(
makeKeymap(teclas),
pinesFilas,
pinesColumnas,
FILAS,
COLUMNAS
);
// ==========================================
// 4. SENSOR DHT11
// ==========================================
const int PIN_DHT = 41;
DHT dht(PIN_DHT, DHT11);
float temperatura = 0;
float humedad = 0;
unsigned long tiempoDHT = 0;
const unsigned long INTERVALO_DHT = 2000;
// ==========================================
// 5. PANTALLA GLCD
// ==========================================
const int GLCD_RS = 50;
const int GLCD_RW = 51;
const int GLCD_E = 53;
U8G2_ST7920_128X64_F_SW_SPI pantalla(
U8G2_R2,
GLCD_E,
GLCD_RW,
GLCD_RS,
U8X8_PIN_NONE
);
// ==========================================
// 6. VARIABLES DEL PROGRAMA
// ==========================================
int modo = 1;
int ledActual = 0;
bool acumulativo = false;
char ultimaTecla = '0';
unsigned long tiempoLED = 0;
const unsigned long INTERVALO_LED = 300;
unsigned long tiempoPantalla = 0;
const unsigned long INTERVALO_PANTALLA = 500;
// ==========================================
// 7. FUNCIONES DE LOS LED
// ==========================================
void apagarLeds() {
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(leds[i], LOW);
}
}
void encenderLeds() {
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(leds[i], HIGH);
}
}
void seleccionarModo(int nuevoModo) {
modo = nuevoModo;
ledActual = 0;
acumulativo = false;
apagarLeds();
if (modo == 0) {
encenderLeds();
}
}
// ==========================================
// 8. LECTURA DE LOS PULSADORES FISICOS
// ==========================================
void leerBotones() {
for (int i = 0; i < NUM_BOTONES; i++) {
if (digitalRead(botones[i]) == LOW) {
ultimaTecla = '1' + i;
seleccionarModo(i);
}
}
}
// ==========================================
// 9. LECTURA DEL TECLADO MATRICIAL
// ==========================================
void leerTeclado() {
char tecla = teclado.getKey();
if (tecla >= '1' && tecla <= '4') {
ultimaTecla = tecla;
seleccionarModo(tecla - '1');
}
}
// ==========================================
// 10. ANIMACION DE LOS LED
// ==========================================
void actualizarLeds() {
if (modo < 2) {
return;
}
if (millis() - tiempoLED < INTERVALO_LED) {
return;
}
tiempoLED = millis();
if (modo == 2) {
apagarLeds();
digitalWrite(leds[ledActual], HIGH);
ledActual++;
if (ledActual >= NUM_LEDS) {
ledActual = 0;
}
}
else if (modo == 3) {
digitalWrite(leds[ledActual], HIGH);
ledActual++;
if (ledActual >= NUM_LEDS) {
apagarLeds();
ledActual = 0;
}
}
}
// ==========================================
// 11. LECTURA DEL DHT11
// ==========================================
void actualizarDHT() {
if (millis() - tiempoDHT >= INTERVALO_DHT) {
tiempoDHT = millis();
float nuevaHumedad = dht.readHumidity();
float nuevaTemperatura = dht.readTemperature();
if (!isnan(nuevaHumedad) && !isnan(nuevaTemperatura)) {
humedad = nuevaHumedad;
temperatura = nuevaTemperatura;
}
}
}
// ==========================================
// 12. ACTUALIZACION DE LA PANTALLA
// ==========================================
void actualizarPantalla() {
if (millis() - tiempoPantalla < INTERVALO_PANTALLA) {
return;
}
tiempoPantalla = millis();
pantalla.clearBuffer();
pantalla.setFont(u8g2_font_6x10_tf);
pantalla.drawStr(0, 10, "Practica 3 EMP");
char strTemp[10];
char strHum[10];
char textoTemperatura[25];
char textoHumedad[25];
char textoTecla[25];
// Conversión segura de float a texto en AVR
dtostrf(temperatura, 4, 1, strTemp);
dtostrf(humedad, 4, 1, strHum);
snprintf(textoTemperatura, sizeof(textoTemperatura), "Temp: %s C", strTemp);
snprintf(textoHumedad, sizeof(textoHumedad), "Hum: %s %%", strHum);
snprintf(textoTecla, sizeof(textoTecla), "Ultima Tecla: %c", ultimaTecla);
pantalla.drawStr(0, 27, textoTemperatura);
pantalla.drawStr(0, 40, textoHumedad);
pantalla.drawStr(0, 53, textoTecla);
pantalla.sendBuffer();
}
// ==========================================
// 13. CONFIGURACION INICIAL
// ==========================================
void setup() {
for (int i = 0; i < NUM_LEDS; i++) {
pinMode(leds[i], OUTPUT);
}
for (int i = 0; i < NUM_BOTONES; i++) {
pinMode(botones[i], INPUT_PULLUP);
}
Serial.begin(115200);
apagarLeds();
dht.begin();
pantalla.begin();
pantalla.clearBuffer();
pantalla.setFont(u8g2_font_6x10_tf);
pantalla.drawStr(0, 15, "Practica 3 EMP");
pantalla.drawStr(0, 30, "Iniciando...");
pantalla.sendBuffer();
tiempoDHT = millis() - INTERVALO_DHT;
tiempoPantalla = millis() - INTERVALO_PANTALLA;
}
// ==========================================
// 14. BUCLE PRINCIPAL
// ==========================================
void loop() {
leerBotones();
leerTeclado();
actualizarLeds();
actualizarDHT();
actualizarPantalla();
}