Fundamentos · 12 min de lectura

Qué es UART: conexión TX/RX, baudios y comunicación serie Arduino

Qué es UART y cómo funciona: TX/RX cruzados, baudios, bits de inicio y parada, unir dos Arduino, SoftwareSerial, 5V y 3,3V, ESP32 Serial2 y UART de la Pico.

La respuesta corta a qué es UART: UART (Universal Asynchronous Receiver-Transmitter) es el hardware de comunicación serie que permite a dos dispositivos intercambiar datos byte a byte con solo dos cables de datos (TX y RX) y una masa (GND) común. Cada línea que ves en el Monitor Serie con el Arduino conectado al ordenador llega por UART. Decenas de módulos, como receptores GPS, el módulo Bluetooth HC-05, el Wi-Fi ESP-01, el GSM SIM800L, lectores de huellas y reproductores MP3, también hablan con el Arduino por UART.

En este artículo explicamos paso a paso por qué UART no necesita línea de reloj, qué es la velocidad en baudios, cómo se enmarca un byte con bits de inicio, datos y parada, por qué TX y RX se cruzan, cómo comunicar dos Arduino primero en un sentido y luego en ambos, los límites de SoftwareSerial, cómo conectar con seguridad placas de 5 V y 3,3 V, los tres UART del ESP32 y los pines UART de la Raspberry Pi Pico. En la última sección verás cómo crear paquetes con caracteres de inicio y fin para que los datos no se mezclen, y los errores más habituales.

Conversor USB-TTL CP2102
Conversor USB-TTL CP2102: convierte el puerto USB del ordenador en un UART con pines TX, RX y GND; el chip USB del Arduino Uno hace lo mismo.

¿Qué es UART y cómo funciona?

La palabra «asíncrono» del nombre es la clave: en I2C y SPI se envía una señal de reloj junto con los datos, mientras que UART no tiene línea de reloj. En su lugar, ambos lados acuerdan antes una velocidad, llamada velocidad en baudios. En reposo la línea está en HIGH (1). Para enviar un byte, el emisor pone la línea en LOW durante un bit; es el bit de inicio (start), que dice al receptor «empieza a contar». Después van los 8 bits de datos, empezando por el menos significativo (LSB), puede venir un bit de paridad opcional y al final la línea se mantiene en HIGH al menos un bit; es el bit de parada (stop). El ajuste por defecto del Arduino es 8N1: 8 bits de datos, sin paridad, 1 bit de parada.

BitInicioD0D1D2D3D4D5D6D7Parada
Letra 'A' (0x41 = 0100 0001)0100000101
Nivel de la líneaLOWHIGHLOWLOWLOWLOWLOWHIGHLOWHIGH

Cada bit dura 1 / baudios segundos. A 9600 baudios un bit dura 104,2 microsegundos; como en una trama 8N1 cada byte ocupa 10 bits (inicio + 8 datos + parada), se pueden enviar como máximo 960 bytes por segundo. Tras detectar el flanco de bajada del bit de inicio, el receptor lee la línea en el centro de cada bit. Aunque los relojes de ambos lados difieran un poco, los datos se leen bien mientras el error acumulado en 10 bits no supere medio bit; por eso el error total de baudios debe quedar por debajo del 2–3 % aproximadamente. Con su cristal de 16 MHz, el Arduino Uno no genera 115200 baudios exactos y la velocidad real difiere un 2,1 %; aun así funciona porque está dentro del límite.

BaudiosDuración del bitBytes por segundo máx. (8N1)¿Dónde se usa?
9600104,2 µs960GPS NEO-6M, HC-05 en modo datos, DFPlayer Mini, ajuste clásico del Monitor Serie
1920052,1 µs1920Algunos sensores y módems antiguos
3840026,0 µs3840HC-05 en modo de comandos AT
5760017,4 µs5760Bootloaders antiguos de Arduino, límite superior de SoftwareSerial
1152008,68 µs11520ESP32 y ESP-01, salida de depuración rápida
1000000 o más1 µs o menos100 000+Enlaces cortos entre placas, registro rápido de datos

Diferencias entre UART, I2C y SPI

Los tres métodos de comunicación serie más usados en Arduino son UART, I2C y SPI. UART funciona solo entre dos dispositivos, y los dos pueden hablar cuando quieran (full duplex). I2C reúne decenas de dispositivos con direcciones en los mismos dos cables; SPI es mucho más rápido con cuatro cables pero necesita un pin de selección por dispositivo. Para más detalles, mira los artículos Qué es I2C y Qué es SPI.

CaracterísticaUARTI2CSPI
Cables2 (TX, RX) + GND2 (SDA, SCL) + GND4 (SCK, MOSI, MISO, CS) + GND
Línea de relojNo (asíncrono)SíSí
Número de dispositivos2 (punto a punto)Hasta 127, por direcciónTantos como pines CS
Velocidad típica9600–115200 baudios100–400 kHz1–80 MHz
Ambos sentidos a la vezSí (full duplex)NoSí
Módulos típicosGPS, Bluetooth, GSM, ESP-01, huellaOLED, LCD, RTC, BME280Tarjeta SD, RFID, TFT, LoRa

TX y RX cruzados y masa común

La regla de oro del cableado UART: el pin TX (transmitir) de un dispositivo va al pin RX (recibir) del otro, es decir, los cables se cruzan. Piénsalo como boca y oído: donde uno habla, el otro tiene que escuchar. Si unes TX con TX, dos salidas quedan conectadas entre sí y no pasa ningún dato. El tercer cable, GND, da a ambas placas la misma referencia de tensión; sin él, «HIGH» y «LOW» pierden sentido y los datos se convierten en caracteres sin sentido. Aunque las placas se alimenten de fuentes distintas, las masas deben estar unidas.

Arduino ACableArduino BNota
TX (D11, SoftwareSerial)→RX (D10, SoftwareSerial)Lo que envía A llega a B
RX (D10, SoftwareSerial)←TX (D11, SoftwareSerial)La respuesta de B llega a A
GND—GNDMasa común, obligatoria
5Vopcional5VSolo si una sola placa se alimenta por USB
En el Arduino Uno y el Nano, los pines del UART por hardware D0 (RX) y D1 (TX) también están conectados al chip USB. Si intentas subir un programa con un módulo conectado a esos pines, la carga falla con el error «not in sync» y en el Monitor Serie se mezclan los datos del módulo con los del ordenador. Desconecta los cables de D0/D1 al subir el código o usa otros pines con SoftwareSerial, como en los ejemplos de este artículo.

Comunicar dos Arduino: en un sentido

Arduino Uno
Arduino Uno: como su único UART por hardware (D0/D1) está reservado al USB, lo más cómodo es unir dos Uno con SoftwareSerial en D10/D11.

En el primer ejemplo, la placa A envía diez veces por segundo a la placa B el valor de un potenciómetro en A0, y la placa B ajusta con él el brillo del LED en D9. Ambas placas usan SoftwareSerial en D10 (RX) y D11 (TX), así la conexión USB y el Monitor Serie quedan libres. Como los valores se envían con println(), cada número termina con los caracteres «\r\n» (fin de línea); el receptor sabe que el número está completo al verlos. Conexión: D11 de A a D10 de B, D10 de A a D11 de B y las masas juntas.

C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11 (diğer karta / to the other board)
4
5void setup() {
6  Serial.begin(9600);           // USB: bilgisayar / computer
7  link.begin(9600);             // iki tarafta aynı baud / same baud on both sides
8}
9
10void loop() {
11  int deger = analogRead(A0);   // potansiyometre 0-1023 / potentiometer 0-1023
12  link.println(deger);          // ör. "512\r\n" / e.g. "512\r\n"
13  Serial.println(deger);
14  delay(100);                   // saniyede 10 ölçüm / 10 readings per second
15}
16
C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11
4const int LED_PIN = 9;          // PWM pini / PWM pin
5
6char tampon[8];                 // en fazla 7 karakter + '\0' / up to 7 chars + '\0'
7byte konum = 0;
8
9void setup() {
10  Serial.begin(9600);
11  link.begin(9600);
12  pinMode(LED_PIN, OUTPUT);
13}
14
15void loop() {
16  while (link.available()) {               // gelen her baytı oku / read every incoming byte
17    char c = link.read();
18    if (c == '\n') {                       // satır bitti / line complete
19      tampon[konum] = '\0';
20      int deger = atoi(tampon);
21      analogWrite(LED_PIN, map(deger, 0, 1023, 0, 255));
22      Serial.println(deger);
23      konum = 0;
24    } else if (c != '\r' && konum < sizeof(tampon) - 1) {
25      tampon[konum++] = c;                 // satıra ekle / append to the line
26    }
27  }
28}
29

Hay dos cosas a tener en cuenta en el código receptor. Primero, los datos nunca llegan «de una pieza»: «512» llega como tres bytes separados, con aproximadamente 1 milisegundo entre ellos. Por eso juntamos los bytes en un búfer y los convertimos en número cuando llega el fin de línea. Segundo, el código nunca espera: funciones como readString() o parseInt() esperan 1 segundo por defecto cuando no llegan datos y ralentizan tu programa. Leer los bytes según llegan es la forma más fiable y rápida. Además limitamos el tamaño del búfer para que un dato corrupto no se escriba fuera del array.

Comunicación en ambos sentidos: comando y respuesta

En los proyectos reales suele hacer falta una conversación en ambos sentidos: una placa envía un comando y la otra lo ejecuta y responde. En el ejemplo de abajo la placa A funciona como puente: reenvía a B cada carácter que escribes en el Monitor Serie y muestra cada carácter que llega de B. La placa B entiende los comandos «LED ON», «LED OFF» y «DURUM?» (estado), responde a cada uno y además avisa por sí sola cuando se pulsa el botón de D2. No olvides poner el fin de línea del Monitor Serie en Nueva línea (Newline); B sabe así que el comando ha terminado.

C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11
4
5void setup() {
6  Serial.begin(9600);
7  link.begin(9600);
8  Serial.println("Komut yaz / type a command: LED ON, LED OFF, DURUM?");
9}
10
11void loop() {
12  if (Serial.available()) link.write(Serial.read());   // bilgisayar -> B kartı / computer -> board B
13  if (link.available()) Serial.write(link.read());     // B kartı -> bilgisayar / board B -> computer
14}
15
C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11);    // RX = 10, TX = 11
4const int LED_PIN = 13;         // kart üstündeki LED / on-board LED
5const int BUTON_PIN = 2;        // buton GND'ye / button to GND
6
7String satir = "";
8int oncekiButon = HIGH;
9
10void komutCalistir(String k) {
11  k.trim();                                  // \r ve boşlukları at / strip \r and spaces
12  if (k == "LED ON") {
13    digitalWrite(LED_PIN, HIGH);
14    link.println("OK LED=1");
15  } else if (k == "LED OFF") {
16    digitalWrite(LED_PIN, LOW);
17    link.println("OK LED=0");
18  } else if (k == "DURUM?") {                // durum sorgusu / status query
19    link.print("LED=");
20    link.print(digitalRead(LED_PIN));
21    link.print(" BUTON=");
22    link.println(digitalRead(BUTON_PIN) == LOW ? 1 : 0);
23  } else {
24    link.print("HATA / unknown: ");
25    link.println(k);
26  }
27}
28
29void setup() {
30  link.begin(9600);
31  pinMode(LED_PIN, OUTPUT);
32  pinMode(BUTON_PIN, INPUT_PULLUP);
33  satir.reserve(32);
34}
35
36void loop() {
37  while (link.available()) {
38    char c = link.read();
39    if (c == '\n') {
40      komutCalistir(satir);
41      satir = "";
42    } else if (satir.length() < 31) {
43      satir += c;
44    }
45  }
46
47  int buton = digitalRead(BUTON_PIN);        // değişince kendiliğinden bildir / report changes unprompted
48  if (buton != oncekiButon) {
49    oncekiButon = buton;
50    link.println(buton == LOW ? "BUTON BASILDI / pressed" : "BUTON BIRAKILDI / released");
51    delay(20);                               // basit debounce / simple debounce
52  }
53}
54

La llamada trim() en la placa B elimina el carácter \r que llega cuando el Monitor Serie está en «Ambos NL y CR», además de los espacios sobrantes, de modo que los comandos se reconocen con cualquiera de los dos ajustes. Usar reserve(32) con el objeto String evita que la memoria se reasigne cada vez que se añade un carácter y reduce la fragmentación de los 2 KB de RAM del Uno. Esta estructura es también la base para hablar con el Arduino desde un programa en Python en el ordenador; detalles en el artículo comunicación serie entre Arduino y Python.

Los límites de SoftwareSerial

SoftwareSerial imita un UART por software en lugar de por hardware: el propio procesador mide el tiempo de cada bit. Es muy práctico, pero tiene un precio. Al transmitir, las interrupciones se desactivan durante todo el byte; a 9600 baudios eso es aproximadamente 1 milisegundo por byte, y mientras tanto millis() puede desviarse, los pulsos de un servo pueden temblar y se pueden perder datos que llegan por otro puerto serie. Solo un puerto SoftwareSerial puede escuchar a la vez; si abres un segundo, eliges cuál escucha con listen(). En placas como la Mega y la Leonardo solo pueden usarse como RX ciertos pines con interrupción.

CaracterísticaUART por hardware (Serial)SoftwareSerialAltSoftSerial
Pines en el UnoD0 (RX), D1 (TX), compartidos con USBCasi cualquier pin (PCINT para RX)Fijos: D8 (RX), D9 (TX)
Velocidad fiable máxima1–2 Mbaudios57600 baudios (115200 al límite)Estable a velocidades medias (9600–38400)
Carga de CPUMuy baja (búfer por hardware)Alta, interrupciones apagadas al enviarMedia, usa el Timer1
Enviar y recibir a la vezSíNoSí
Varios puertos4 en la MegaSolo uno escucha a la vezUn solo puerto
ConflictosCarga del código y Monitor SerieLibrerías sensibles al tiempo como Servo y NeoPixelPWM en D10 y Servo (Timer1)
Si vas a usar más de un módulo UART (por ejemplo GPS + Bluetooth), elige en lugar del Uno un Arduino Mega con cuatro UART por hardware (Serial1–Serial3 además de Serial) o un ESP32 con tres. En la Leonardo y la Pro Micro el USB va aparte, así que Serial1 en D0/D1 queda totalmente libre.

Niveles de 5V y 3,3V

En UART, el nivel «HIGH» es la tensión de trabajo de la placa: 5 V en el Arduino Uno y 3,3 V en el ESP32, la Raspberry Pi Pico, el ESP-01 y la mayoría de módulos modernos. Conectar directamente una salida TX de 5 V a una entrada RX de 3,3 V somete la entrada a sobretensión y daña el pin, con el tiempo o al momento; ni el ESP32 ni la Pico con RP2040 toleran 5 V. El sentido contrario suele ir bien: el Uno considera HIGH a partir de 3,0 V, así que puede leer un TX de 3,3 V, aunque al estar cerca del límite un conversor de nivel es más robusto con cables largos.

ConexiónQué hace faltaEjemplo
TX del Uno (5 V) → RX de ESP32 / Pico (3,3 V)Divisor de tensión o conversor de nivel1 kΩ en serie + 2 kΩ a GND: 5 × 2/3 ≈ 3,3 V
TX de ESP32 / Pico (3,3 V) → RX del Uno (5 V)Normalmente directoEl Uno considera HIGH por encima de 3,0 V
TX del Uno → RX del HC-05Se recomienda divisorEl RX del HC-05 trabaja a nivel de 3,3 V
TX del Uno → RX del SIM800LDivisor de tensiónEl nivel de señal del SIM800L ronda los 2,8 V
Las dos placas a 5 V o las dos a 3,3 VDirectoUno ↔ Nano, ESP32 ↔ Pico
Un divisor de tensión solo sirve para señales en un sentido y de velocidad baja o media (por ejemplo hasta 115200 baudios). Para líneas bidireccionales o muy rápidas usa un conversor de nivel lógico bidireccional basado en BSS138. Puedes calcular las resistencias con la calculadora de divisor de tensión; los conversores de nivel se explican a fondo en el artículo conversor de nivel lógico.

UART en el ESP32: Serial, Serial1 y Serial2

El ESP32 tiene tres UART por hardware y lo mejor es que, gracias a su matriz GPIO, los pines UART se pueden llevar a casi cualquier pin. UART0 (Serial) está conectado al chip USB-serie y se usa para el Monitor Serie. UART2 (Serial2) está por defecto en GPIO 16 (RX) y 17 (TX). Los antiguos pines por defecto de UART1 (GPIO 9 y 10) están conectados a la memoria flash de la placa y no se pueden usar directamente, así que inicia siempre Serial1 indicando pines: begin(baudios, SERIAL_8N1, RX, TX). El código de abajo crea un puente en ambos sentidos entre el Monitor Serie y un dispositivo conectado a UART2 (un GPS, otro Arduino, un sensor); es ideal para ver las frases NMEA de un módulo GPS.

UARTNombre en ArduinoRX / TX por defectoNota
UART0SerialGPIO 3 / GPIO 1Conectado al chip USB-serie, carga y Monitor Serie
UART1Serial1GPIO 9 / GPIO 10 (flash, no usar)Indica otros pines en begin(), p. ej. 25 / 26
UART2Serial2GPIO 16 / GPIO 17En placas WROVER 16/17 los usa la PSRAM, elige otros pines
C++ (Arduino IDE)
1// ESP32: UART0 = Serial (USB), UART2 = Serial2 (GPIO 16/17)
2const int RXD2 = 16;            // karşı cihazın TX'i buraya / the other device's TX goes here
3const int TXD2 = 17;            // karşı cihazın RX'ine / to the other device's RX
4
5void setup() {
6  Serial.begin(115200);                          // USB Seri Monitör / USB Serial Monitor
7  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);   // baud, çerçeve, RX, TX / baud, frame, RX, TX
8  // UART1'i de istediğin pinlere taşıyabilirsin / UART1 can be moved to any free pins:
9  // Serial1.begin(115200, SERIAL_8N1, 25, 26);
10  Serial.println("UART2 hazir / ready");
11}
12
13void loop() {
14  while (Serial2.available()) Serial.write(Serial2.read());   // UART2 -> USB
15  while (Serial.available()) Serial2.write(Serial.read());    // USB -> UART2
16}
17

Los UART del ESP32 llegan hasta 5 Mbaudios y cada uno tiene su búfer por hardware; el búfer de recepción por defecto es de 256 bytes y se puede ampliar antes de begin() con una llamada como Serial2.setRxBufferSize(1024). Esto importa con módulos GPS que envían decenas de frases por segundo o módulos GSM con respuestas largas. Como los pines del ESP32 son de 3,3 V, no olvides el divisor de la sección anterior al conectarlo a un Arduino de 5 V. Puedes ver los pines del ESP32 en la herramienta Pinout.

Pines UART de la Raspberry Pi Pico y MicroPython

La Raspberry Pi Pico tiene dos UART por hardware (uart0 y uart1) y cada uno puede llevarse a varios pares de pines. En MicroPython, el REPL y la salida de print() van por un puerto serie virtual aparte en el USB, así que UART0 queda totalmente libre; no hace falta desconectar cables al subir código como en Arduino. Los pines de la Pico son de 3,3 V y en la Pico con RP2040 no toleran 5 V. El código de abajo hace en la Pico lo mismo que la placa B en Arduino: lee líneas de UART0, enciende o apaga el LED integrado con «LED ON» y «LED OFF» y responde. Si quieres que hable con el código puente del Uno, no olvides un divisor de tensión en el TX del Uno.

UARTPines TXPines RXEjemplo en MicroPython
uart0GP0, GP12, GP16GP1, GP13, GP17UART(0, 9600, tx=Pin(0), rx=Pin(1))
uart1GP4, GP8GP5, GP9UART(1, 9600, tx=Pin(4), rx=Pin(5))
MicroPython
1from machine import UART, Pin
2import time
3
4uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))   # UART0: GP0 = TX, GP1 = RX
5led = Pin("LED", Pin.OUT)                             # Pico ve Pico W dahili LED / on-board LED
6
7tampon = b""
8while True:
9    if uart.any():
10        tampon += uart.read()                         # gelen baytlar / incoming bytes
11        while b"\n" in tampon:                        # her tam satırı işle / handle each full line
12            satir, tampon = tampon.split(b"\n", 1)
13            try:
14                komut = satir.decode().strip()
15            except UnicodeError:
16                continue                              # bozuk bayt: atla / corrupt byte: skip
17            if komut == "LED ON":
18                led.on()
19                uart.write("OK LED=1\n")
20            elif komut == "LED OFF":
21                led.off()
22                uart.write("OK LED=0\n")
23            else:
24                uart.write("HATA / unknown: " + komut + "\n")
25    if len(tampon) > 64:                              # satır sonu hiç gelmezse taşmayı önle / avoid overflow
26        tampon = b""
27    time.sleep_ms(5)
28

Empaquetar datos: carácter de inicio y de fin

UART es un flujo de bytes; no sabe dónde empieza ni dónde acaba nada. Cuando el emisor escribe «23.5,48,812», puede que el receptor haya empezado a escuchar a mitad, que un byte se haya perdido por ruido o que dos lecturas se junten. La solución es convertir los datos en un paquete: si cada paquete empieza con «<» y termina con «>», el receptor ignora todo hasta el primer «<», procesa el paquete cuando llega «>» y descarta los medios paquetes intermedios. El emisor solo tiene que escribir los valores entre Serial.print('<'), comas y Serial.print('>'). Puedes probar ya mismo el receptor de abajo escribiendo <23.5,48,812> en el Monitor Serie.

C++ (Arduino IDE)
1// Paket biçimi / packet format: <sicaklik,nem,isik>  ör. / e.g. <23.5,48,812>
2const byte MAKS = 32;
3char tampon[MAKS];
4byte konum = 0;
5bool paketIcinde = false;                    // '<' görüldü mü? / have we seen '<'?
6
7void paketiIsle(char* p) {
8  char* parca = strtok(p, ",");              // ilk alan / first field
9  if (!parca) return;
10  float sicaklik = atof(parca);
11  parca = strtok(NULL, ",");
12  if (!parca) return;                        // eksik alan: paketi at / missing field: drop
13  int nem = atoi(parca);
14  parca = strtok(NULL, ",");
15  if (!parca) return;
16  int isik = atoi(parca);
17
18  Serial.print("Sicaklik / temp: ");
19  Serial.print(sicaklik, 1);
20  Serial.print("  Nem / humidity: ");
21  Serial.print(nem);
22  Serial.print("  Isik / light: ");
23  Serial.println(isik);
24}
25
26void setup() {
27  Serial.begin(9600);                        // Seri Monitör'den <23.5,48,812> yazarak dene / test from the Serial Monitor
28}
29
30void loop() {
31  while (Serial.available()) {
32    char c = Serial.read();
33    if (c == '<') {                          // yeni paket başladı / a new packet starts
34      paketIcinde = true;
35      konum = 0;
36    } else if (c == '>' && paketIcinde) {    // paket bitti / packet complete
37      tampon[konum] = '\0';
38      paketIcinde = false;
39      paketiIsle(tampon);
40    } else if (paketIcinde) {
41      if (konum < MAKS - 1) tampon[konum++] = c;
42      else paketIcinde = false;              // çok uzun, bozuk: at / too long, corrupt: drop
43    }                                        // paket dışındaki baytlar yok sayılır / bytes outside packets are ignored
44  }
45}
46
MétodoEjemploVentajaInconveniente
Texto con fin de línea512\nEl más simple, legible en el Monitor SerieA media línea no se sabe dónde empieza
Carácter de inicio y fin<23.5,48,812>Se recupera solo si pierde la sincroníaNo se pueden usar < y > dentro de los datos
Texto con suma de control (como NMEA)$GPGGA,...*47Detecta paquetes corruptosAlgo más de cálculo y código
Paquete binario0xAA, longitud, datos, CRCEl más corto y rápidoDifícil de leer y depurar

En entornos con ruido o con cables largos puedes ir un paso más allá y añadir una suma de control (checksum) al paquete. El formato NMEA de los módulos GPS es un buen ejemplo: se hace el XOR de todos los caracteres entre «$» y «*» y el resultado se escribe al final como un número hexadecimal de dos cifras. El receptor hace el mismo cálculo y descarta el paquete si no coincide. Así evitas errores traicioneros, como que un «812» corrupto se procese como «872».

El emisor no debe ir más rápido de lo que el receptor puede procesar. El búfer de recepción por hardware del Arduino Uno es de solo 64 bytes; si usas delay() largos en loop(), los bytes que llegan se pierden cuando el búfer se llena. En el receptor usa millis() en lugar de delay() y comprueba Serial.available() en cada vuelta del bucle.

Ideas de proyectos con UART

  • Control desde el móvil: el HC-05 es en realidad un UART inalámbrico; controla un LED, un relé o un coche robot desde el móvil con el HC-05.
  • Registro GPS: interpreta las frases NMEA que un GPS NEO-6M envía por UART y guarda la posición en una tarjeta SD.
  • Sistema de dos placas: une por UART un Uno que lee los sensores con un ESP32 que envía los datos a internet por Wi-Fi.
  • Alarma por SMS: envía comandos AT a un SIM800L por UART y recibe un SMS cuando se abra una puerta.
  • Panel de control en el ordenador: envía comandos al Arduino desde una aplicación de escritorio en Python y dibuja gráficas con los datos de los sensores.
  • Reproductor MP3: elige canciones, ajusta el volumen y reproduce avisos de voz por UART con un DFPlayer Mini.

Errores frecuentes y soluciones

SíntomaCausa probableSolución
Caracteres sin sentido en el Monitor SerieVelocidades distintasUsa los mismos baudios en el código y en el Monitor Serie
No llega ningún datoTX unido a TX y RX a RXCruza los cables: TX → RX, RX → TX
Caracteres corruptos al azarGND sin conectarUne las masas de las dos placas
La carga falla (not in sync)Hay un módulo en D0/D1Desconecta los cables al subir o usa SoftwareSerial
No se reconocen los comandosEl fin de línea es \r\n o no hayPon el Monitor Serie en Nueva línea y limpia el texto con trim()
Se pierde el final de los mensajes largosSe desbordó el búfer de 64 bytesNo uses delay(), lee los datos según llegan, baja la velocidad
El RX del ESP32 no funciona o se dañóSe conectó un TX de 5 V directamenteAñade un divisor de tensión o un conversor de nivel
SoftwareSerial falla a 115200La temporización por software no llegaUsa 57600 o menos, o pasa a un UART por hardware
Si un módulo UART no responde, conéctalo primero directamente al ordenador con un conversor USB-TTL y envíale comandos desde un terminal serie. Si allí funciona, el problema está en el código Arduino o en el cableado; si tampoco funciona allí, revisa los baudios, la alimentación y el propio módulo.

UART es el primer método de comunicación que conviene aprender en electrónica: bastan dos cables, una masa común y la misma velocidad, y bien montado funciona años sin problemas. Cuando domines el cableado cruzado, los niveles de tensión y el empaquetado, podrás usar con soltura decenas de módulos, del GPS al GSM. En la app BlueGrays encontrarás proyectos de comunicación en un sentido y en ambos entre dos Arduino, encender un LED desde el móvil por Bluetooth y un coche controlado por Bluetooth, paso a paso con esquema y código.

Preguntas frecuentes

¿Qué significa UART y para qué sirve?

UART significa Universal Asynchronous Receiver-Transmitter, es decir, receptor-transmisor asíncrono universal. Permite que dos dispositivos intercambien datos byte a byte sin línea de reloj, solo con los cables TX y RX y una velocidad acordada de antemano. El Monitor Serie de Arduino y los módulos GPS, Bluetooth y GSM usan UART.

¿Cómo se conectan TX y RX?

El pin TX de un dispositivo va al pin RX del otro, y su RX al TX del otro, así que la conexión es cruzada. Además, los pines GND de los dos dispositivos deben estar unidos. Conectar TX con TX bloquea por completo los datos.

¿Qué son los baudios y cuál elijo?

La velocidad en baudios es el número de bits enviados por segundo y debe ser igual en ambos lados. Los valores más comunes con módulos Arduino son 9600 y 115200; 9600 es el valor por defecto de la mayoría de módulos GPS y Bluetooth, y 115200 se prefiere para el ESP32 y salidas rápidas. Empieza con la velocidad por defecto que indique el módulo.

¿UART y puerto serie son lo mismo?

En el uso diario suelen significar lo mismo. UART es la unidad de hardware que serializa los datos; el puerto serie es la conexión COM o /dev/tty del ordenador. RS-232 y RS-485 son estándares que usan otros niveles de tensión para llevar las señales UART a más distancia.

¿Cómo uso varios UART en Arduino?

El Uno tiene un solo UART por hardware compartido con el USB; para más puertos se usa SoftwareSerial, pero solo uno puede escuchar a la vez. El Arduino Mega tiene tres UART por hardware extra (Serial1, Serial2 y Serial3), el ESP32 tres en total y la Raspberry Pi Pico dos.

¿Qué longitud puede tener un cable UART?

UART con niveles TTL de 3,3 V o 5 V funciona de forma fiable hasta unos pocos metros a baja velocidad, y la distancia se acorta al subir los baudios. Para distancias mayores, los transceptores RS-485 (como el MAX485) llegan a cientos de metros, y RS-232 a unos 15 metros.

Ver todos los proyectos
Comunicación unidireccional entre 2 Arduino
#57Intermedio
Premium

Comunicación unidireccional entre 2 Arduino

Haces que dos Arduino hablen por un solo cable: pulsas el botón de uno y se enciende el LED del otro, vuelves a pulsar y se apaga. La placa que envía avisa del botón con un mensaje corto, y la que rec

4.4(37)
50
Comunicación bidireccional entre 2 Arduino
#58Intermedio
Premium

Comunicación bidireccional entre 2 Arduino

Dos Arduino se conectan con cables y hablan entre sí: pulsas el botón de uno y se enciende la luz del otro, lo pulsas otra vez y se apaga. Las dos placas llevan el mismo programa, así que cada una env

4.5(20)
26
Controlar un LED desde el móvil por Bluetooth
#34Principiante
Premium

Controlar un LED desde el móvil por Bluetooth

Un pequeño ensayo para encender y apagar las luces de tu habitación desde el móvil. El módulo Bluetooth pasa al Arduino las letras que envías desde el teléfono; una letra enciende el LED rojo, otra en

4.8(68)
89
Coche controlado por Bluetooth con L298N
#80Avanzado
Premium

Coche controlado por Bluetooth con L298N

Convierte tu móvil en un mando y conduce tu propio coche robot. El Arduino recibe por un módulo Bluetooth las órdenes de una app de control remoto en el móvil y mueve las ruedas con un controlador de

5.0(38)
65
Teclado para desarrolladores de Python
#66Intermedio
Premium

Teclado para desarrolladores de Python

Si te cansa escribir los mismos patrones una y otra vez mientras programas, este pequeño teclado está hecho para ti. El Arduino Leonardo se conecta al ordenador como si fuera un teclado, y cada tecla

4.6(35)
45
HC-SR04 Medición de distancia (pantalla en serie)
#27Principiante

HC-SR04 Medición de distancia (pantalla en serie)

El sensor HC-SR04 funciona igual que un murciélago que se orienta en la oscuridad: emite un sonido que no puedes oír, escucha el eco y mide a qué distancia está el objeto que tiene delante. El Arduino

4.6(46)
71
Temperatura y humedad con DHT11
#55Intermedio

Temperatura y humedad con DHT11

¿Qué temperatura hace en tu habitación, y el aire está húmedo o seco? El sensor DHT11 mide la temperatura y la humedad, y el Arduino escribe los valores en una pantalla LCD de dos líneas, actualizándo

4.7(47)
73
Lectura de la intensidad luminosa con el módulo LDR del ESP32
#113Principiante

Lectura de la intensidad luminosa con el módulo LDR del ESP32

Visualización en tiempo real en el monitor serie del valor bruto del ADC del módulo LDR y del porcentaje relativo de luz calculado a partir de referencias de oscuridad y claridad. Este porcentaje no es una medición en lux. Explica el funcionamiento de la calibración del módulo. Es recomendable realizarlo antes del Proyecto 10, ya que se utiliza para determinar el valor umbral.

4.6(36)
55