micropython-uart-comunicacion-serial

Comunicación serie UART en MicroPython

  • 5 min

La UART (Universal Asynchronous Receiver-Transmitter) es un protocolo serie asíncrono para enviar bytes entre dos dispositivos. A pesar de ser una tecnología veterana, sigue siendo omnipresente.

¿Quieres conectar un módulo GPS? UART. ¿Un módulo Bluetooth HC-05? UART. ¿Comunicar dos placas entre sí? UART. Incluso cuando conectas tu placa al ordenador por USB para programarla, en realidad estás usando un convertidor USB-Serial que emula una UART.

En este artículo vamos a aprender a usar la clase machine.UART para dominar este protocolo fundamental.

¿Qué es la UART?

A diferencia de otros protocolos que veremos (como I2C o SPI), la UART es asíncrona. Esto significa que no hay una señal de reloj compartida que marque el ritmo.

Para que dos dispositivos se entiendan, ambos deben ponerse de acuerdo previamente en la velocidad de transmisión, conocida como Baud Rate (típicamente 9600 o 115200 baudios).

El cableado básico: TX con RX

La comunicación UART utiliza dos líneas de datos:

  • TX (Transmit): Por donde salen los datos.
  • RX (Receive): Por donde entran los datos.

La Regla del Cruce Esta es la causa del 90% de los fallos en principiantes: El TX de un dispositivo va al RX del otro, y viceversa.

  • TX RX
  • RX TX
  • GND GND (¡Nunca olvides compartir la tierra!)

La clase machine.UART

En MicroPython, el manejo es muy sencillo. Primero, necesitamos saber qué UARTs por hardware tiene disponibles nuestra placa.

  • ESP32: Tiene 3 UARTs (0, 1, 2). La UART0 suele estar ocupada por el USB/REPL. Generalmente usaremos la UART1 o UART2. Lo genial del ESP32 es que podemos asignar los pines TX/RX a casi cualquier GPIO.
  • Raspberry Pi Pico: Tiene 2 UARTs (0 y 1) con pines predefinidos pero flexibles dentro de ciertos grupos.
  • ESP8266: Más limitado, tiene UART0 (USB) y UART1 (Solo TX).

Inicialización básica

Vamos a configurar una comunicación a 9600 baudios.

from machine import UART, Pin

# Ejemplo para ESP32 usando UART2
# tx=17, rx=16 son pines típicos para UART2 en muchas placas ESP32
uart = UART(2, baudrate=9600, tx=17, rx=16)

# Ejemplo para Raspberry Pi Pico (UART0)
# tx=Pin(0), rx=Pin(1)
# uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))

print(uart)
Copied!

Al imprimir el objeto uart, veremos la configuración actual, lo que nos sirve para verificar que hemos asignado bien los parámetros.

Enviar datos

Para enviar información usamos el método .write(). Es importante recordar que la UART envía bytes, no cadenas de texto Unicode.

# Enviamos bytes puros
uart.write(b'Hola Mundo')

# Si tenemos una cadena (string), hay que codificarla
mensaje = "Temperatura: 25C\n"
uart.write(mensaje.encode('utf-8'))
Copied!

Añadir \n (salida de línea) al final es una buena práctica para indicar al receptor que el mensaje ha terminado.

Recibir datos

Leer es un poco más delicado porque no sabemos cuándo van a llegar los datos. Tenemos varios métodos:

  • read(n): Lee n bytes. Si no pones n, lee todo lo que haya.
  • readline(): Lee hasta encontrar un carácter de nueva línea (\n).
  • any(): Devuelve un valor positivo si hay caracteres esperando en el buffer. Este es muy importante. Ojo, no siempre es un contador exacto de todos los bytes disponibles.

Lectura no bloqueante

La forma correcta de leer un sensor o dispositivo serial sin bloquear nuestro programa es comprobar primero si hay algo que leer con .any().

import time

while True:
    # Preguntamos: ¿Hay datos en el buzón?
    if uart.any() > 0:
        # Leemos todo lo que haya
        datos = uart.read()
        
        # Procesamos los datos (decodificamos de bytes a string)
        try:
            texto = datos.decode('utf-8')
            print("Recibido:", texto)
        except:
            print("Datos binarios recibidos (no texto)")
            
    # Hacemos otras cosas...
    time.sleep(0.1)
Copied!

Ejemplo práctico de loopback

¿Cómo probamos si esto funciona sin tener un sensor GPS o Bluetooth a mano? Haciendo un Loopback.

Conecta con un cable el pin TX de tu placa directamente a su propio pin RX. Así, todo lo que “hables” deberías “escucharlo” inmediatamente.

from machine import UART
import time

# Configura los pines según tu placa (ej. ESP32 UART2)
uart = UART(2, baudrate=9600, tx=17, rx=16)

uart.write(b'Prueba de eco')
time.sleep(0.1) # Damos un instante para que la señal viaje

if uart.any():
    recibido = uart.read()
    print(recibido) # Debería imprimir b'Prueba de eco'
else:
    print("No he escuchado nada. ¿Revisaste el cable?")
Copied!

Configuración avanzada

Aunque el 99% de las veces usamos la configuración estándar 8N1 (8 bits de datos, No paridad, 1 bit de stop), a veces nos encontramos con equipos industriales raros. Podemos configurar todo:

# Configuración 8N1 explícita (por defecto es así)
uart.init(bits=8, parity=None, stop=1)

# Configuración con Paridad Par (Even) - Rara pero existe
uart.init(parity=0) 
Copied!

Errores comunes

  1. Ruido en la línea: Si recibes caracteres extraños o símbolos raros, casi seguro que tienes un desajuste de Baud Rate. Asegúrate de que emisor y receptor tengan la misma velocidad.
  2. Niveles de voltaje: Recuerda que el ESP32/Pico trabaja a 3.3V. Si conectas un dispositivo UART antiguo de 5V (como algunos Arduinos viejos o módulos GPS antiguos), podrías quemar el pin RX. Usa un divisor de tensión o un convertidor de nivel lógico.
  3. Buffer desbordado: Si el dispositivo envía datos muy rápido y tú no los lees con uart.read(), el buffer interno se llenará y empezarás a perder información.

La UART es la puerta de entrada al mundo de los módulos externos. Una vez que dominas el write, any y read, puedes conectar prácticamente cualquier cosa.