Dominio del controlador LCD en STM32: Configuración con STM32CubeMX e implementación de la interfaz paralela 8080

Introducción: Un controlador preciso, no un dispositivo "inteligente"

Un módulo LCD, como un panel MCU de 2.4 pulgadas (resolución 240×320, controlador ILI9341), no es un periférico pasivo. Es un sistema que requiere un control secuencial y preciso. Su comunicación con el microcontrolador, como el STM32G431, se basa en una interfaz paraella de 8 bits/16 bits (en este caso, 8080), donde múltiples líneas de datos deben coordinarse con señales de control. Entender esta coreografía es fudnamental para implementar el display correctamente.

Principios de hardware: Conexión y conflicto de pines

Parámetros de la pantalla

Característica Valor
Resolución 240 x 320 píxeles
Controlador ILI9341 (o similar)
Interfaz Paralela 8080 (16 líneas de datos)

Asignación de pines (ejemplo con STM32G431)

La conexión típica utiliza un puerto completo (ej. GPIOC) para las líneas de datos, maximizando la velocidad de transferencia.

Señal LCD Pin STM32 Función
D0–D15 PC0 - PC15 Datos de 16 bits (color del píxel)
CS PB9 Selección de chip (activo bajo)
RS (D/C) PB8 Selección de registro: 0=Comando, 1=Dato
WR PB5 Señal de escritura (flanco descendente)
RD PA8 Señal de lectura (flanco descendente)

Resolución del conflicto: Uso de un circuito de retención (Latch)

Los LED y el LCD pueden compartir el bus de datos GPIO. La solución es un circuito de retención (como un 74HC573). Este actúa como un filtro:

  • Datos del LCD: Pasan directamente al bus cuando la señal de control del latch está inactiva.
  • Estados de los LED: Se capturan y mantienen en la salida del latch solo cuando se pulsa la señal de captura (LE). Esto aísla el estado de los LED de las rápidas actualizaciones del bus de datos del display.

Conclusión: Actualizar los píxeles en pantalla no altera el estado de los LED. Para cambiar los LED, se debe invocar explícitamente una función que genere el pulso de captura en el latch, como GPIO_Latch_LED_State().

Protocolo 8080: La secuencia de comunicaciones

El protocolo 8080 es una secuencia sincronizada por señales de control. Se puede visualizar como una operación de escritura en dos fases controlada por el maestro (STM32):

  1. Fase de configuración: El maestro establece el nivel lógico de RS para indicar si la información en el bus de datos es un comando (ej. 0x2A para definir dirección de columna) o un dato (ej. el valor de color 0xF800 para rojo).
  2. Fase de transferencia: Con CS activo (bajo), el maestro coloca la información en el bus D0-D15 y genera un pulso en la línea WR (un ciclo bajo-alto). El esclavo (LCD) captura la información en el flanco de subida de WR.

La agrupación de todos los pines de datos en un solo puerto (GPIOC) es crítica para el rendimiento, ya que permite escribir todos los 16 bits de una vez mediante un solo acceso al registro de datos de salida (ODR) del puerto.

Configuración con STM32CubeMX

La configuración de los GPIO para el modo de salida rápida es esencial.

Pin Modo GPIO Configuración específica
PC0-PC15 Output Push Pull Velocidad: Very High. Sin pull-up/pull-down interno.
PB9 (CS), PB8 (RS), PB5 (WR), PA8 (RD) Output Push Pull Velocidad: High o Very High. Sin pull-up/pull-down interno.

Implementación del código

Dfeinición de macros para las señales de control

Definir macros mejora la legibilidad y abstrae el hardware.

// Definiciones para pines de control (ejemplo)
#define LCD_CS_PORT    GPIOB
#define LCD_CS_PIN     GPIO_PIN_9
#define LCD_RS_PORT    GPIOB
#define LCD_RS_PIN     GPIO_PIN_8
#define LCD_WR_PORT    GPIOB
#define LCD_WR_PIN     GPIO_PIN_5
// Macros de operación
#define LCD_SELECT_CS()    HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET)
#define LCD_DESELECT_CS()  HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET)
#define LCD_CMD_MODE()     HAL_GPIO_WritePin(LCD_RS_PORT, LCD_RS_PIN, GPIO_PIN_RESET)
#define LCD_DATA_MODE()    HAL_GPIO_WritePin(LCD_RS_PORT, LCD_RS_PIN, GPIO_PIN_SET)
// Escritura de 16 bits directamente al registro ODR del puerto C
#define LCD_WRITE_BUS(value)   (GPIOC->ODR = (value))

Función de escritura fundamental

/**
 * @brief Escribe una palabra de 16 bits en el LCD.
 * @param rs_flag 0 para enviar como comando, 1 para enviar como dato.
 * @param data La palabra de 16 bits a enviar.
 */
void LCD_Write(uint8_t rs_flag, uint16_t data) {
    LCD_SELECT_CS();
    if (rs_flag) {
        LCD_DATA_MODE();
    } else {
        LCD_CMD_MODE();
    }
    LCD_WRITE_BUS(data);
    // Generar pulso de escritura
    HAL_GPIO_WritePin(LCD_WR_PORT, LCD_WR_PIN, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_WR_PORT, LCD_WR_PIN, GPIO_PIN_SET);
    LCD_DESELECT_CS();
}

Función de impresión formateada

Una función versátil para mostrar texto con formato, similar a printf.

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

/**
 * @brief Muestra una cadena formateada en una línea específica del LCD.
 * @param y Coordena Y de la línea (0 a 319, dependiendo de la orientación).
 * @param format Cadena de formato estilo printf.
 * @param ... Argumentos variables.
 */
void LCD_Printf(uint16_t y, const char *format, ...) {
    static char buffer[64]; // Buffer estático para evitar asignación dinámica
    va_list args;

    va_start(args, format);
    int length = vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    if (length > 0) {
        // Se asume una función de bajo nivel que dibuja texto en una posición Y
        LCD_DisplayStringAt(0, y, (uint8_t *)buffer, LEFT_MODE);
    }
}

Resumen de funciones de alto nivel

  • LCD_Init(): Secuencia de inicialización del controlador ILI9341.
  • LCD_Clear(uint16_t color): Rellena toda la pantalla con un color.
  • LCD_SetTextColor(uint16_t color): Establece el color para texto y gráficos posteriores.
  • LCD_FillRect(x, y, w, h, color): Dibuja un rectángulo relleno.

Ejemplo de aplicación: Panel de estado del sistema

int main(void) {
    // Inicialización del HAL, relojes, GPIO...
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    LCD_Init();
    LCD_SetOrientation(LANDSCAPE);
    LCD_Clear(COLOR_WHITE);
    LCD_SetFont(&Font16); // Establecer fuente
    LCD_SetTextColor(COLOR_BLACK);

    uint32_t loop_count = 0;
    while (1) {
        // Actualizar la pantalla cada 500ms
        if ((HAL_GetTick() % 500) == 0) {
            // Limpiar el área de texto antes de redibujar
            LCD_FillRect(0, 0, 240, 60, COLOR_WHITE);

            LCD_Printf(10, "Estado: Activo");
            LCD_Printf(30, "Ciclo: %lu", loop_count++);
        }
        // Otras tareas de la aplicación...
    }
}

Este bucle principal demuestra cómo actualizar dinámicamente la información en el display sin bloquear el sistema, sentando las bases para interfaces más complejas.

Etiquetas: STM32 HAL LCD 8080 Interfaz Paralela

Publicado el 6-21 23:31