El estándar RS485 no define ningún protocolo de software; es puramente una Capa Física (Hardware). En lugar de transmitir "0V o 3.3V" a través de un cable referenciado a tierra (Single-ended), utiliza dos cables entrelazados (Trenzado) típicamente etiquetados como A y B.
Si el STM32 envía un "1" lógico, el chip transceptor MAX485 eleva la línea A y baja la línea B. Si envía un "0", hace lo contrario. El receptor remoto no mira el voltaje respecto a Tierra, sino la diferencia de voltaje entre A y B. Si un motor eléctrico inyecta +50V de ruido por inducción magnética al cable, el ruido impacta ambos cables por igual. Como el receptor solo lee "la diferencia" entre ambos, el ruido se cancela matemáticamente a cero. ¡Magia analógica!
Como las líneas A y B se comparten con todos los nodos de la red, la comunicación RS485 estándar es Half-Duplex: puedes hablar o escuchar, pero no ambos al mismo tiempo. El chip transceptor tiene dos pines de control vitales:
En ingeniería de PCB, solemos puentear los pines RE y DE juntos y conectarlos a un solo GPIO de control (Direction Pin) en el STM32. Si el GPIO está en 0, la máquina escucha. Si el GPIO está en 1, la máquina habla.
Cuando envías un mensaje por código (ej. `"Hola"`), el microcontrolador envía los bytes velozmente al hardware UART. Si miras el bit TXE (Registro Vacío), te dirá que el registro ya está libre. Muchos ingenieros novatos bajan el pin DE/RE (volver a escuchar) inmediatamente después del último TXE. ¡Grave error!
El registro puede estar libre, pero el Shift Register físico (que empuja los bits 1 a 1 al cable a 115200 baudios) todavía está escupiendo la última letra 'a'. Si cortas el pin de transmisión en ese milisegundo, la última letra quedará mutilada, destruyendo el Checksum (CRC) de tu mensaje Modbus y el servidor jamás responderá.
En Bare-Metal, la solución para apagar el modo de Transmisión es vigilar la bandera TC (Transmission Complete), no el TXE. El bit TC solo se enciende cuando el hardware ha confirmado eléctricamente que el último Bit de Parada (Stop Bit) salió de la máquina por completo.
Ejercicio 1: Inicializaremos el pin PA8 como salida normal (Push-Pull) para controlar los pines unidos DE/RE del MAX485. Modificaremos nuestra función clásica de envío UART (Día 130) para que "levante" el pin a 3.3V antes de hablar, transmita todos los caracteres revisando el TXE, y al terminar el bucle, espere de manera no bloqueante al bit TC para volver a poner el pin en 0V, regresando el chip a su estado seguro de "Escucha".
/**
* @file rs485_driver.c
* @brief Driver Físico RS485 con Gestión Segura de DE/RE y Trampa TC
*/
#include "stm32f401xe.h"
#include <stdbool.h>
// Macros de manipulación atómica rápida del pin DIR (PA8)
#define RS485_MODO_TX() (GPIOA->BSRR = GPIO_BSRR_BS8) // Pone PA8 en 1 (Hablar)
#define RS485_MODO_RX() (GPIOA->BSRR = GPIO_BSRR_BR8) // Pone PA8 en 0 (Escuchar)
void inicializar_rs485_hardware(void) {
// Asumimos que los relojes del GPIOA y USART2 ya están activos (Día 130)
// Configurar PA8 como salida de propósito general (Push-Pull) para el DIR
GPIOA->MODER &= ~GPIO_MODER_MODE8;
GPIOA->MODER |= GPIO_MODER_MODE8_0; // 01: General purpose output mode
// Velocidad alta para cambiar de estado rápidamente
GPIOA->OSPEEDR |= (3 << (8*2));
// ESTADO POR DEFECTO: Siempre escuchando (RX)
// El bus RS485 es silencioso. Si todos los nodos intentan hablar al mismo
// tiempo (Modo TX), chocarán eléctricamente (Bus Contention) y se quemarán.
RS485_MODO_RX();
}
/**
* @brief Envía un bloque de datos por RS485 bloqueando el bus momentáneamente
* @param buffer Puntero a los datos
* @param longitud Cantidad matemática de bytes a enviar
*/
void rs485_enviar_trama_bloqueante(uint8_t* buffer, uint16_t longitud) {
// 1. Tomar el control físico del bus RS485 (DE = 1)
RS485_MODO_TX();
// Pequeño retardo de hardware para que los transistores del MAX485 se abran
// Unos cuantos NOPs o 1 microsegundo son suficientes en la mayoría de chips
__NOP(); __NOP(); __NOP(); __NOP();
// 2. Empujar los bytes a través del USART2
for(uint16_t i = 0; i < longitud; i++) {
// Esperar a que el Registro de Datos esté libre
while (!(USART2->SR & USART_SR_TXE));
// Cargar el byte (El hardware UART comienza a shiftarlo al cable)
USART2->DR = buffer[i];
}
// ==========================================================
// 3. LA TRAMPA MORTAL DE LA CAPA FÍSICA (Transmission Complete)
// ==========================================================
// ¡Los bytes están en tránsito mecánico a 115200 baudios!
// NO debemos apagar el pin DIR todavía.
// Esperamos específicamente la bandera TC (Bit 6 del SR)
while (!(USART2->SR & USART_SR_TC));
// 4. Liberar el bus inmediatamente después del último bit de parada
RS485_MODO_RX();
}
int main(void) {
// inicializar_relojes();
// inicializar_usart2_dma_circular(); // Recepción asíncrona del Día 135
inicializar_rs485_hardware();
while(1) {
// Si el DMA y el IDLE detectan un paquete entrante (Modbus)
// if (bandera_trama_lista) {
// procesar_tramas_pendientes();
//
// if (paquete_para_mi) {
// // Responder al Servidor Central "Litros=145"
// rs485_enviar_trama_bloqueante(respuesta, len);
// }
// }
}
return 0;
}
Objetivo del día: Blindaje de Capa Física para topología Multi-Punto Industrial.
Un patio de gasolinera es grande, y el cuarto de control de la estación (donde está la computadora punto de venta de las secretarias) puede estar a cientos de metros del área de las bombas. Si usarás un cable normal UART de 3.3V, el ruido estático y la resistencia eléctrica atenuarían la señal a cero en menos de 3 metros.
Al dotar a tu firmware de la lógica de conmutación DIR (DE/RE) controlada por la bandera de hardware TC, has habilitado tu máquina para portar un chip MAX485 en la placa de circuito impreso (PCB). La señal asíncrona del procesador ahora se convierte en un robusto "latido diferencial" A/B capaz de perforar el ruido electromagnético de los motores trifásicos. Aún más importante, configurando por defecto tu máquina para "escuchar" (RX), has garantizado que múltiples Despachadores de Gas puedan conectarse en "Daisy-Chain" al mismo cable de 2 hilos compartiendo el mismo bus sin freírse mutuamente.
DE (Hablar) y RE (Escuchar), comúnmente enrutados a un solo pin GPIO del microcontrolador (Pin DIR).TXE (Transmit Empty) provocará la mutilación del último byte transmitido, ya que el registro de desplazamiento (Shift Register) aún no lo inyecta por completo al cable.