DÍA 125 DE 365

Fase 3: Comunicaciones y Redes Industriales

📖 Teoría a Estudiar

El Expansor de Puertos PCF8574

Una pantalla LCD estándar (con el chip controlador Hitachi HD44780) no sabe qué es el bus I2C. Habla en un protocolo paralelo muy antiguo y engorroso. Para no lidiar con eso, los ingenieros le sueldan en la parte trasera una "Mochila I2C" (Backpack). Este módulo contiene un chip PCF8574.

El PCF8574 es un Expansor de I/O de 8 bits. Tú le envías un solo byte por el cable I2C (SDA), y él traduce esos 8 bits en 8 pines físicos de salida lógica, controlando la pantalla en tu lugar. Su dirección estándar en la red I2C suele ser 0x27 o 0x3F.

Mapeo de Bits y el Modo a 4-Bits (Nibbles)

Como solo tenemos 8 pines en el expansor, no podemos enviar los 8 bits de un caracter al mismo tiempo (porque la LCD requiere pines adicionales de control). La solución de la industria es utilizar el Modo a 4 Bits. Enviamos el caracter en dos partes: primero los 4 bits altos (High Nibble) y luego los 4 bits bajos (Low Nibble).

El cableado interno entre el expansor y la pantalla está estandarizado de la siguiente manera (del Bit 7 al Bit 0):

ARQUITECTURA DEL DRIVER: I2C A MODO 4-BITS LCD STM32 Master I2C SDA SCL PCF8574 Addr: 0x27 P7-P4 DATA P3 (BL) P2 (EN) P0 (RS) GAS LP EL SOL -------------------- Vol: 10.45 L Total: $120.00 MXN HD44780 (20x4) Enviando el Carácter 'A' (Hex 0x41) en Modo 4 Bits 1. Enviar Nibble Alto (4) 0100 1 1 0 1 D7-D4 | BL | EN | RW | RS 2. Enviar Nibble Bajo (1) 0001 1 1 0 1 D7-D4 | BL | EN | RW | RS

⚙️ Ejercicios Prácticos

Ejercicio 1: Crea la librería Bare-Metal para la pantalla LCD. Utilizaremos la función i2c_escribir_byte() de tu driver. Deberemos enviar los comandos de inicialización mágica (0x33, 0x32, 0x28) requeridos por Hitachi para sincronizar la pantalla a 4-bits, y diseñaremos las funciones para posicionar el cursor y escribir cadenas de texto.


/**
 * @file i2c_lcd_driver.c
 * @brief Driver Bare-Metal para Pantalla LCD 20x4 con Módulo I2C PCF8574
 */

#include "stm32f401xe.h"
#include <stdint.h>

// Dirección I2C común del Expansor PCF8574. (Modificada por 0x27 << 1)
#define LCD_I2C_ADDR 0x4E 

// Mapas de Bits del PCF8574
#define LCD_BIT_RS  0x01  // Register Select (0 = Comando, 1 = Dato)
#define LCD_BIT_RW  0x02  // Read/Write (Lo mantenemos en 0)
#define LCD_BIT_EN  0x04  // Enable
#define LCD_BIT_BL  0x08  // Backlight (Luz de fondo)

// Dependencia del driver I2C base (Día 123)
extern void i2c_iniciar_transaccion(uint8_t direccion);
extern void i2c_escribir_dato(uint8_t dato); // Transmite y espera ACK
extern void i2c_detener_transaccion(void);
extern void delay_ms_bloqueante(uint32_t ms); // Timer de retardo simple

/**
 * @brief Envia un byte físico al expansor I2C empaquetado en una mini-transacción
 */
void lcd_enviar_i2c(uint8_t dato_empaquetado) {
    i2c_iniciar_transaccion(LCD_I2C_ADDR);
    i2c_escribir_dato(dato_empaquetado);
    i2c_detener_transaccion();
}

/**
 * @brief Ejecuta el pulso Enable (High -> Low) para que la LCD procese la línea
 */
void lcd_pulso_enable(uint8_t dato_listo) {
    lcd_enviar_i2c(dato_listo | LCD_BIT_EN);     // EN en Alto
    delay_ms_bloqueante(1);                      // Espera de estabilidad (1ms)
    lcd_enviar_i2c(dato_listo & ~LCD_BIT_EN);    // EN en Bajo (Ejecuta lectura)
    delay_ms_bloqueante(1);
}

/**
 * @brief Envía un byte completo (Comando o Caracter) dividido en dos Nibbles
 */
void lcd_enviar_byte(uint8_t byte_crudo, uint8_t modo_rs) {
    
    // Nibble Alto (Enviamos los 4 bits altos en su lugar, sumando Backlight y RS)
    uint8_t nibble_alto = (byte_crudo & 0xF0) | LCD_BIT_BL | modo_rs;
    lcd_pulso_enable(nibble_alto);
    
    // Nibble Bajo (Desplazamos los 4 bits bajos a la zona alta)
    uint8_t nibble_bajo = ((byte_crudo << 4) & 0xF0) | LCD_BIT_BL | modo_rs;
    lcd_pulso_enable(nibble_bajo);
}

/**
 * @brief Secuencia mágica de inicialización de Hitachi HD44780
 */
void lcd_inicializar(void) {
    // La pantalla tarda hasta 50ms en encender tras aplicar VDD
    delay_ms_bloqueante(50); 
    
    // Forzar modo a 4-bits enviando comandos en Nibbles directos
    lcd_pulso_enable(0x30 | LCD_BIT_BL);
    delay_ms_bloqueante(5);
    lcd_pulso_enable(0x30 | LCD_BIT_BL);
    delay_ms_bloqueante(1);
    lcd_pulso_enable(0x30 | LCD_BIT_BL);
    delay_ms_bloqueante(1);
    lcd_pulso_enable(0x20 | LCD_BIT_BL); // Set 4-bit mode!
    delay_ms_bloqueante(1);
    
    // Configurar Pantalla
    lcd_enviar_byte(0x28, 0); // 4-bits, 2 líneas, formato 5x8
    lcd_enviar_byte(0x0C, 0); // Display ON, Cursor OFF
    lcd_enviar_byte(0x06, 0); // Auto-incremento del cursor
    lcd_enviar_byte(0x01, 0); // Limpiar pantalla
    delay_ms_bloqueante(2);
}

/**
 * @brief Ubica el cursor en una posición (Fila 0-3, Columna 0-19)
 */
void lcd_set_cursor(uint8_t fila, uint8_t col) {
    // Offsets de memoria de la pantalla 20x4
    uint8_t offset[] = {0x00, 0x40, 0x14, 0x54};
    // El comando SET_DDRAM_ADDR tiene el bit 7 (0x80) en Alto
    lcd_enviar_byte(0x80 | (col + offset[fila]), 0); 
}

/**
 * @brief Escribe una cadena de texto (String)
 */
void lcd_escribir_cadena(char *texto) {
    while (*texto) {
        lcd_enviar_byte((uint8_t)(*texto), LCD_BIT_RS); // RS=1 para Datos
        texto++;
    }
}

int main(void) {
    
    // inicializar_i2c1(); // Driver del Día 123
    lcd_inicializar();
    
    // Pintando la interfaz del Despachador
    lcd_set_cursor(0, 0);
    lcd_escribir_cadena("ESTACION: CENTRO 01");
    
    lcd_set_cursor(1, 0);
    lcd_escribir_cadena("Prc: $10.50 MXN / Lt");
    
    while(1) {
        
        // (Las lecturas de litros calculadas en el Día 115 se
        // transforman a String y se envían a la Fila 3).
        
        // lcd_set_cursor(2, 0);
        // lcd_escribir_cadena(string_litros_compensados);
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Experiencia de Usuario y Certificación Visual.

El reglamento de gasolineras y gaseras exige una pantalla legible a plena luz del sol. Además, la pantalla no debe estar físicamente conectada a las mismas pistas eléctricas que las válvulas de potencia, pues un arco eléctrico en la botonera frontal podría saltar a la pantalla y de ahí a tu microcontrolador, friendo el sistema entero.

Al utilizar este módulo I2C para controlar tu LCD de **20 columnas por 4 filas**, no solo creas una interfaz limpia con espacio suficiente para mostrar los litros facturados, el precio unitario y la compensación por temperatura simultáneamente. También logras una arquitectura donde el panel frontal del Despachador requiere **solo 4 cables (VDD, GND, SDA, SCL)**, haciéndolo increíblemente fácil de mantener por los técnicos de la estación, reducir el costo de arneses y aumentar la inmunidad al ruido industrial.

📝 Resumen del Día