← Índice del curso

Comunicación entre Dispositivos · Tema 37 · Comunicación inalámbrica

Bluetooth clásico

El Bluetooth clásico nació para reemplazar un cable: el serie que unía un teléfono con un auricular, una computadora con un módem, un GPS con un portátil. Esa herencia lo hace especialmente cómodo para un programador de microcontroladores, porque el perfil de puerto serie (SPP) ofrece un canal inalámbrico que, visto desde el programa, es una UART más: Serial.print() de un lado y una terminal en el teléfono del otro. En este tema se estudia cómo funciona por dentro (saltos de frecuencia, ranuras, paquetes, piconets), cómo se organiza su pila de protocolos, cómo se empareja un dispositivo y qué protege cada método, y cómo se lleva a la práctica con los módulos HC-05 y HC-06 y con el ESP32. También se explica dónde está su límite: es una tecnología de más de veinte años, con consumo medio y sin soporte para los iPhone, y por eso el tema siguiente presenta su hermano de bajo consumo, Bluetooth Low Energy.

01 · Objetivo

Qué es Bluetooth clásico

Bluetooth es una tecnología de radio de corto alcance para conectar dispositivos personales. La inició Ericsson en 1994 como una alternativa inalámbrica al cable RS-232 y, en 1998, cinco empresas fundaron el Bluetooth SIG, que mantiene el estándar y certifica los productos. Su nombre es el de un rey danés del siglo X, Harald «Diente Azul», que unificó tribus: la idea era unir fabricantes y dispositivos. El logotipo combina las runas de sus iniciales.

Hoy hay dos tecnologías con el mismo nombre y radios distintos, que no se entienden entre sí:

Bluetooth clásico frente a Bluetooth Low Energy.
AspectoClásico (BR/EDR)Low Energy (BLE)
Aparece1999 (versión 1.0); 2004 con EDR (2.0)2010 (versión 4.0)
ObjetivoFlujos continuos: audio, serie, archivosMensajes breves y ocasionales con consumo mínimo
Velocidad1 Mbit/s (BR) y 2 o 3 Mbit/s (EDR)1 o 2 Mbit/s en el aire; mucho menos útil en la práctica
ConsumoDecenas de mA mientras la conexión está activaUn ciclo de trabajo muy bajo: pocos µA de media
ConexiónSegundos para descubrir y emparejarMilisegundos para conectar
Uso típicoAuriculares, manos libres, audio, puerto serie inalámbricoSensores, relojes, balizas, accesorios
Tema del cursoEsteTema 38

Los teléfonos y computadoras son de modo dual: hablan las dos. Los accesorios pueden ser de un tipo u otro, y la compatibilidad con el microcontrolador depende del chip:

Qué Bluetooth tienen los módulos habituales.
Módulo o chipClásicoBLENotas
HC-05, HC-06Sí (2.0 + EDR)NoMódulos externos con interfaz serie; el HC-06 solo hace de esclavo
HM-10, JDY-08 y similaresNoSíMódulos serie BLE (tema 38)
ESP32 clásicoSíSíModo dual; ambos comparten la radio con el Wi-Fi
ESP32-S3, ESP32-C3, ESP32-C6NoSíSolo BLE: el código de este tema no compila
Arduino UNO R4 WiFi, Nano 33 BLENoSíSolo BLE

02 · La capa física

La radio: saltos, ranuras y paquetes

Bluetooth usa la banda ISM de 2,4 GHz (tema 34), la misma que Wi-Fi, y reparte la banda en 79 canales de 1 MHz (de 2402 a 2480 MHz). En lugar de elegir un canal fijo, los dos extremos saltan de canal 1600 veces por segundo siguiendo una secuencia pseudoaleatoria conocida por ambos (espectro ensanchado por saltos de frecuencia, FHSS). El tiempo se divide en ranuras de 625 µs, y en cada una se usa una frecuencia distinta. El efecto práctico es una resistencia notable a la interferencia: si un canal está ocupado por una red Wi-Fi o un horno de microondas, solo se pierde la ranura que cayó allí, y se retransmite en otro canal. Desde la versión 1.2, el salto adaptativo (AFH) marca los canales malos y los evita (se necesitan al menos 20 libres), con lo que Bluetooth y Wi-Fi conviven mejor: es el esquema de coexistencia del tema 34 en acción.

Ranuras de tiempo entre un maestro y un esclavo El tiempo está dividido en ranuras de 625 microsegundos numeradas de 0 a 7. El maestro transmite en las ranuras pares y el esclavo en las impares. En la ranura 0 el maestro envía un paquete de una ranura y el esclavo responde en la 1. En la ranura 2 el maestro envía un paquete de tres ranuras que ocupa de la 2 a la 4, y el esclavo responde en la 5. En la 6 el maestro envía un paquete de sondeo y el esclavo responde en la 7. Cada paquete usa la frecuencia de salto de su ranura inicial. MaestroEsclavo ranura 01234567 625 µs DH1DH3 (3 ranuras)POLLDH1DH1NULL f₀f₂ (la misma 3 ranuras)f₆f₁f₅f₇ El maestro empieza en las ranuras pares; el esclavo responde en la ranura impar siguiente al fin del paquete.

El acceso es por división en el tiempo (TDD): el maestro transmite en las ranuras pares y el esclavo en las impares, y un esclavo solo habla cuando el maestro lo invita (sondeo, polling). Nadie transmite sin permiso, por lo que no hay colisiones dentro de una piconet. Cuando no hay datos, el maestro envía un paquete POLL y el esclavo responde con un NULL para mantener la conexión. Un paquete puede ocupar 1, 3 o 5 ranuras, y el que responde usa la ranura siguiente al final: cuanto más largo el paquete, menos tiempo se gasta en los saltos y las respuestas, y más datos útiles hay por segundo. Los tipos más usados:

Tipos de paquete de datos de Bluetooth clásico. La velocidad en un sentido supone que el otro lado responde con paquetes de una ranura.
TipoModulaciónDatos útilesRanurasUn sentidoSimétrico
DM1GFSK, con FEC 2/317 bytes1108,8 kbit/s108,8 kbit/s
DH1GFSK27 bytes1172,8 kbit/s172,8 kbit/s
DM3 / DH3GFSK121 / 183 bytes3387,2 / 585,6 kbit/s258,1 / 390,4 kbit/s
DM5 / DH5GFSK224 / 339 bytes5477,9 / 723,2 kbit/s286,7 / 433,9 kbit/s
2-DH5π/4-DQPSK (EDR)679 bytes51448,5 kbit/s869,1 kbit/s
3-DH58DPSK (EDR)1021 bytes52178,1 kbit/s1306,9 kbit/s

Los números de la última columna son la velocidad máxima del enlace, antes de restar las cabeceras de L2CAP y RFCOMM, las retransmisiones y la eficiencia de los chips: un enlace SPP real se mueve en el orden de 100 a 200 kbyte/s, es decir, de 1 a 2 Mbit/s. Los paquetes DM llevan corrección de errores (FEC) y son más robustos con señal débil; los DH no la llevan y son más rápidos en un canal limpio; y los EDR (2-DH y 3-DH) usan modulaciones de fase de 2 o 3 bits por símbolo, que necesitan mejor relación señal/ruido (tema 34). El chip elige el tipo según los errores que observa. La herramienta 1 del laboratorio calcula cada uno.

Clases de potencia y alcance

Clases de potencia de Bluetooth clásico.
ClasePotencia máximaAlcance nominalDispositivos típicos
1100 mW (20 dBm)≈ 100 mAdaptadores USB de largo alcance, algunos módulos industriales
22,5 mW (4 dBm)≈ 10 mTeléfonos, HC-05 y HC-06, la mayoría de los módulos
31 mW (0 dBm)≈ 1 mAccesorios muy chicos

Con el presupuesto de enlace del tema 34 los números salen solos: una sensibilidad de −80 dBm es habitual en los chips de Bluetooth. Con 4 dBm de potencia, antenas de 0 dBi y 10 dB de margen, la pérdida admisible es de 74 dB y el alcance en espacio libre, de unos 49 m; con un exponente de pérdida de 3 (una casa con paredes), unos 13 m. Los «10 m» de la clase 2 son, entonces, razonables en interiores. Y como la comunicación es en los dos sentidos, manda el extremo con menos potencia: un adaptador de clase 1 con un módulo de clase 2 llega solo hasta donde llega este último (herramienta 3).

03 · Quién habla con quién

Piconets, roles y direcciones

Una conexión Bluetooth clásica forma una piconet: un maestro y hasta siete esclavos activos (identificados con una dirección de 3 bits; otros hasta 255 pueden estar «estacionados»). El maestro es quien inició la conexión y quien manda: su reloj y su dirección determinan la secuencia de saltos que todos siguen, y reparte los turnos de transmisión. Un esclavo no habla con otro esclavo: todo pasa por el maestro. Dos piconets pueden compartir un dispositivo, que es esclavo en una y maestro o esclavo en otra, y forman una scatternet, aunque es poco usada.

Los roles no son fijos. Un teléfono que se conecta a un HC-06 es el maestro; un HC-05 configurado como maestro (AT+ROLE=1) puede iniciar la conexión con otro módulo, y dos HC-05 emparejados (uno maestro y uno esclavo) funcionan como un cable serie inalámbrico entre dos microcontroladores. Las especificaciones recientes hablan de «central» y «periférico», pero los módulos y la documentación conservan los términos maestro y esclavo.

Cada dispositivo tiene una dirección BD_ADDR de 48 bits, como una MAC (por ejemplo 98:D3:31:FC:12:34), con un prefijo de fabricante, y un nombre legible («HC-05», «ESP32-Sensor») de hasta 248 bytes. También tiene una clase de dispositivo de 24 bits que anuncia qué es (teléfono, auricular, periférico…) para que el sistema muestre un icono. Para conectarse, el dispositivo que inicia debe encontrar al otro y después llamarlo:

  1. Inquiry (búsqueda). El que busca emite mensajes de consulta, y los dispositivos «visibles» o «descubribles» responden con su dirección, su clase y su reloj. Dura típicamente unos 10 segundos. Es lo que hace el teléfono al abrir «buscar dispositivos».
  2. Page (llamada). Con la dirección ya conocida, el maestro llama al esclavo, que escucha periódicamente (page scan), y se establece la conexión de banda base.
  3. Emparejamiento (la primera vez). Se intercambia una clave (sección 5) y se guarda: la próxima conexión no necesita repetir la búsqueda ni la clave.
  4. Conexión de datos. Se abren los canales de L2CAP y RFCOMM que necesita el perfil (sección 4).

Esto explica dos cosas que se notan en la práctica. La primera conexión con un módulo nuevo es lenta (descubrir, emparejar, buscar el servicio). Y un dispositivo que no es descubrible puede conectarse igual si el que llama ya conoce su dirección: «invisible» no es «inaccesible». Mientras hay conexión, el enlace puede entrar en modos de ahorro (sniff, hold) en los que el esclavo escucha solo en ciertos momentos, a costa de más latencia.

04 · Capas y perfiles

La pila de protocolos y los perfiles

Pila de protocolos de Bluetooth clásico con el perfil de puerto serie De arriba abajo: la aplicación, el perfil de puerto serie SPP, RFCOMM junto con el protocolo de descubrimiento de servicios SDP, L2CAP, y una línea que separa el host del controlador, la interfaz HCI. Debajo, el gestor de enlace LMP, la banda base y la radio de 2,4 gigahercios. Las capas superiores forman el host y las inferiores el controlador. HCI AplicaciónSPP · perfil de puerto serieRFCOMMSDPL2CAPLMP · gestor del enlaceBanda base Radio · 2,4 GHz Tu programa: comandos, telemetríaEmula un puerto RS-232 (UUID 0x1101)RFCOMM: hasta 30 puertos serie sobre un canalSDP: «¿en qué canal está el servicio?»L2CAP: canales y fragmentación de paquetesAutenticación, cifrado, modos de ahorroRanuras, saltos, paquetes, CRC, retransmisiónGFSK, π/4-DQPSK, 8DPSK Host (software) Controlador (chip de radio)

La pila se divide en dos mitades, unidas por la interfaz HCI (Host Controller Interface). El controlador (radio, banda base y gestor de enlace) es hardware y firmware del chip; el host (L2CAP hacia arriba) puede correr en el mismo chip o en el microcontrolador. En un módulo HC-05 todo está adentro: el microcontrolador solo ve una UART y no sabe nada de ranuras, canales ni emparejamientos. En un ESP32, el host corre en el propio procesador (por eso ocupa cientos de kilobytes de flash y RAM).

  • Banda base y LMP: ranuras, saltos, tipos de paquete, CRC y retransmisión (ARQ), y el protocolo entre controladores para autenticar, cifrar y cambiar de modo.
  • L2CAP: multiplexa varios canales lógicos sobre el enlace y fragmenta y rearma paquetes.
  • SDP (Service Discovery Protocol): un dispositivo pregunta a otro qué servicios ofrece y cómo conectarse. Para SPP, la respuesta incluye el canal de RFCOMM donde está el puerto serie. Por eso la aplicación del teléfono «busca el servicio» tras emparejar.
  • RFCOMM: emula puertos serie (hasta 30 por enlace) sobre L2CAP, con control de flujo y señales como RTS, CTS o DTR. Es el protocolo que da la apariencia de una UART.
  • Perfiles: definen cómo se usa la pila para una función concreta, de modo que dos dispositivos de marcas distintas se entiendan.
Perfiles de Bluetooth clásico más usados.
PerfilPara qué sirveEjemplo
SPP (Serial Port Profile)Puerto serie inalámbricoHC-05, instrumentos, robots, ESP32 con BluetoothSerial
HFP y HSPLlamadas telefónicas (manos libres, auricular)Auto, auricular
A2DP y AVRCPAudio estéreo y control de reproducciónParlante, auriculares
HIDTeclado, ratón, joystickTeclado inalámbrico, mando
PANRed IP sobre BluetoothCompartir Internet del teléfono
OPP y FTPTransferir objetos y archivosEnviar una foto entre teléfonos

SPP es el perfil que importa en el curso: el que convierte la radio en un cable serie. Del lado del teléfono Android se abre con una aplicación de terminal Bluetooth (que usa el identificador de servicio 00001101-0000-1000-8000-00805F9B34FB), y en Windows aparece como un puerto COM virtual. Pero los iPhone y iPad no lo soportan con aplicaciones comunes: iOS solo da acceso al Bluetooth clásico a accesorios con certificación MFi de Apple. Si el producto tiene que funcionar con un iPhone, la respuesta es Bluetooth Low Energy (tema 38).

05 · Quién es quién y qué se guarda

Emparejamiento y seguridad

Que dos dispositivos se vean no significa que puedan hablar. Para establecer una relación de confianza hacen un emparejamiento (pairing): acuerdan una clave de enlace secreta que después sirve para autenticarse en cada conexión y para cifrar el tráfico. Si la clave se guarda (bonding), la próxima vez la conexión es automática. Hay dos generaciones de emparejamiento:

Métodos de emparejamiento de Bluetooth clásico.
MétodoCómo funcionaProtección
PIN (heredado, hasta 2.0)Los dos escriben el mismo PIN (de 4 a 16 dígitos); la clave de enlace se calcula a partir de él y de números aleatorios intercambiados en el aireDébil: con un PIN de 4 dígitos, quien capture el intercambio prueba los 10 000 PIN fuera de línea en milisegundos
SSP: Just Works (2.1 en adelante)Intercambio de claves de curva elíptica (Diffie-Hellman); se acepta sin comparar nadaProtege contra escucha pasiva, no contra un atacante interpuesto (MITM)
SSP: comparación numéricaLos dos muestran un número de 6 dígitos y el usuario confirma que coincidenUn MITM tiene una probabilidad de 1 en 1 000 000 de pasar desapercibido por intento
SSP: ingreso de claveUn dispositivo muestra 6 dígitos y se tipean en el otro (teclados)Similar, y se descubre un bit del código por vuelta
SSP: fuera de bandaLos datos se intercambian por otro medio (NFC)Depende de ese medio; la más fuerte

Los módulos HC-05 y HC-06 usan el emparejamiento por PIN (PIN de fábrica 1234, o 0000 en algunos lotes), porque son de Bluetooth 2.0. Los teléfonos modernos y el ESP32 con enableSSP() usan SSP. En el Bluetooth 4.1 en adelante, Secure Connections reemplaza la curva P-192 por P-256 y el cifrado E0 por AES-CCM; los enlaces anteriores usan el cifrado de flujo E0, mucho más débil de lo deseable. Hay fallos conocidos en implementaciones y en el propio protocolo, como el ataque KNOB (2019), que fuerza una clave de cifrado de un solo byte de entropía, y BlueBorne (2017), que explotaba errores de las pilas: por eso cuenta mantener el firmware actualizado.

Qué hacer en un proyecto:

  • Cambiar el PIN de fábrica y el nombre (herramienta 4). Un módulo con «1234» y el nombre «HC-05» es el más fácil de atacar y de confundir con el de otra persona.
  • No exponer más de lo necesario: un módulo que debe aceptar un único compañero no tiene por qué estar siempre descubrible. El HC-05 permite fijar la dirección del compañero (AT+CMODE=1 y AT+BIND) y el HC-06 deja de ser visible tras la conexión.
  • Validar siempre los comandos en el microcontrolador (tema 33), aun si el enlace está cifrado: el enlace dice «quién» (aproximadamente), no «qué» ni «cuánto».
  • No transmitir secretos ni órdenes críticas sin autenticar en la aplicación. Con un PIN de 4 dígitos y un módulo barato, el cifrado no debería ser la única barrera: una cerradura abierta por Bluetooth necesita, además, un secreto o una respuesta a un desafío del lado de la aplicación (tema 49).
  • Pensar en el alcance: aunque nominalmente sea de 10 m, un atacante con una antena de ganancia llega mucho más lejos.

La herramienta 5 compara el esfuerzo de un ataque fuera de línea contra un PIN de N dígitos con la probabilidad de engañar a una comparación numérica.

06 · Hardware

Los módulos HC-05 y HC-06

Conexión de un HC-05 con un Arduino El Arduino entrega 5 voltios y masa al módulo. El pin D10 recibe lo que sale del TXD del módulo. El pin D11 envía hacia el RXD del módulo a través de un divisor de tensión formado por una resistencia de 1 kiloohm en serie y otra de 2 kiloohmios a masa, que baja los 5 voltios a 3,3 voltios. El pin D9 lee el pin STATE, que indica si hay conexión. El pin KEY se conecta a alimentación para entrar en el modo de comandos AT. Arduino UNO HC-05 5VGNDD10 (RX)D11 (TX)D9VCCGNDTXDRXDKEY / ENSTATE 1 kΩ2 kΩ KEY a VCC al encender: modo AT El RXD del módulo es de 3,3 V: el divisor baja los 5 V de D11 a 3,33 V.

Los HC-05 y HC-06 son módulos de bajo precio con un chip de Bluetooth 2.0 + EDR de clase 2 y una interfaz UART. Se alimentan con 3,6 a 6 V (la placa lleva un regulador de 3,3 V), pero sus señales de entrada y salida son de 3,3 V. Desde el módulo hacia un Arduino de 5 V no hay problema: 3,3 V se lee como un nivel alto. Pero lo que el Arduino manda al RXD del módulo debe bajarse: un divisor de 1 kΩ y 2 kΩ entrega 5 · 2 / 3 = 3,33 V. Conectar los 5 V directamente puede funcionar un tiempo y dañar la entrada.

Pines del HC-05.
PinFunción
VCC y GNDAlimentación (3,6 a 6 V) y masa común con el microcontrolador
TXDSalida serie del módulo (a 3,3 V): va al RX del microcontrolador
RXDEntrada serie del módulo (3,3 V): recibe del TX del microcontrolador, con divisor
STATESalida: en alto cuando hay un enlace establecido, en bajo si no
KEY (o EN)En alto al encender: modo de comandos AT a 38400 baudios. En bajo (o libre): modo de datos

El LED del módulo informa su estado: un parpadeo rápido indica que espera una conexión (modo de datos); un parpadeo lento, de unos dos segundos, que está en modo de comandos AT; un doble parpadeo cada dos segundos, que hay un enlace activo. El consumo es del orden de 30 a 40 mA mientras espera y de unos 8 mA conectado y quieto: no es un módulo para baterías. Las diferencias entre los dos:

HC-05 frente a HC-06.
AspectoHC-05HC-06
RolesMaestro o esclavo (configurable)Solo esclavo
Velocidad de datos de fábrica9600 baudios (8N1)9600 baudios (8N1)
Modo ATCon KEY en alto al encender: 38400 baudios; terminan con CR+LFSiempre, mientras no hay conexión: 9600 baudios; sin terminador
Nombre y PIN de fábricaHC-05 · 1234linvor o HC-06 · 1234
Pin STATE y KEYSíEn general, no

Configurar con comandos AT

Los comandos AT (los del viejo módem) se envían por la UART del módulo. Con el sketch puente de la sección 8, que reenvía lo que se escribe en el monitor serie, se configuran sin otro hardware. Los más usados:

Comandos AT principales (el HC-05 acepta mayúsculas y termina cada línea con CR+LF; algunos firmwares usan ? para consultar).
Comando HC-05EfectoEquivalente HC-06
ATPrueba; responde OKAT
AT+VERSION?Versión del firmwareAT+VERSION
AT+NAME=Sensor01Cambia el nombre visibleAT+NAMESensor01
AT+PSWD=4821Cambia el PIN (algunos firmwares: AT+PSWD="4821")AT+PIN4821
AT+UART=115200,0,0Velocidad, 1 bit de parada, sin paridadAT+BAUD8 (4 = 9600, 8 = 115200)
AT+ROLE=1Maestro (0 = esclavo)—
AT+ADDR?Dirección BD_ADDR del módulo—
AT+CMODE=1 y AT+BIND=98d3,31,fc1234Se conecta solo a la dirección indicada (con comas en lugar de dos puntos)—
AT+ORGLRestablece los valores de fábrica—
AT+RESETReinicia el módulo—

Procedimiento con el HC-05: apagar, mantener KEY (o EN) en alto (con el botón del módulo pulsado o un cable a VCC) y alimentar. El LED parpadea lento: ya está en modo AT. Con el puente a 38400 baudios y el monitor serie en «Ambos NL & CR», AT debe responder OK. Después de cambiar la velocidad con AT+UART, el módulo la usa en modo de datos, no en modo AT (que sigue en 38400). Con el HC-06: sin KEY, a 9600 baudios, sin saltos de línea y esperando alrededor de un segundo entre comandos; deja de responder en cuanto se conecta alguien. La herramienta 4 del laboratorio genera la secuencia y valida los datos.

Y un límite que conviene recordar: la velocidad del conjunto la fija la UART. A 9600 baudios pasan 960 bytes por segundo (una línea de 32 bytes tarda 33 ms), aunque la radio podría con casi cien veces más. Subir la velocidad a 115200 es sencillo en el módulo, pero la biblioteca SoftwareSerial del Arduino UNO se vuelve poco confiable por encima de unos 38400 baudios; para velocidades altas se usa una UART de hardware (Serial1 en el Mega o el ESP32).

07 · Una UART invisible

Un protocolo de aplicación sobre SPP

Un puerto serie inalámbrico se comporta como una UART: entrega una corriente de bytes sin estructura. No hay límites de mensaje, no hay confirmaciones propias de la aplicación y, si el enlace se corta, se pierden los bytes que estaban en camino. Todo lo demás lo tiene que poner el programa. El protocolo de este tema es el más simple que sirve: una orden por línea, en texto, terminada en \n (con \r opcional, como lo envían las terminales de teléfono y computadora).

Órdenes del nodo (mayúsculas obligatorias).
OrdenRespuestaEfecto
TEMP?T=23.5Lee la temperatura (décimas de grado, con el signo manejado aparte)
LED 1 / LED 0OKEnciende o apaga el LED
INT 30OK o ERR rangoIntervalo de envío automático en segundos (1 a 3600)
AYUDATexto de ayudaLista las órdenes
cualquier otraERR comandoNada
una línea de más de 31 caracteresERR largoSe descarta entera

Además, cada INT segundos el nodo envía T=… sin que se lo pidan (telemetría), pero solo si hay un enlace: lee el pin STATE del módulo. Sin esa comprobación, el programa escribiría en el vacío y llenaría el buffer del módulo. Decisiones que se repiten en cualquier protocolo serie (el tema 41 las trata en general):

  • Delimitar los mensajes. La línea es el delimitador; sin él, no se sabe dónde termina una orden. Se arma la línea byte a byte con un buffer de tamaño fijo y sin esperar, como en el tema 33.
  • Limitar y validar. Un buffer de 32 bytes: si la línea lo supera, se marca como desbordada y se descarta completa al llegar el \n, sin interpretarla a medias. Los números se leen solo con dígitos y se comprueba el rango.
  • Responder siempre. Con «OK» o «ERR…», el que manda sabe si fue entendido. Sin una respuesta, un error pasa en silencio.
  • Pensar en la pérdida. Un enlace de radio puede cortarse; si cada orden es independiente y se puede repetir (idempotente, como «LED 1»), reenviar es seguro. Una orden como «INC» (incrementar) no lo es, y requeriría números de secuencia y confirmaciones (tema 45).
  • Texto frente a binario. El texto se depura a ojo con cualquier terminal; el binario ocupa menos. Para unos pocos mensajes por segundo, el texto es lo mejor.

08 · Con el microcontrolador

Tres programas

1. El puente para configurar el módulo

Es lo primero que se carga: reenvía en los dos sentidos entre el monitor serie y el módulo, y permite escribir los comandos AT. Con el HC-05, KEY en alto al encender y el monitor serie a 9600 baudios con «Ambos NL & CR».

#include <SoftwareSerial.h>

SoftwareSerial bt(10, 11);          // RX, TX del Arduino

void setup() {
    Serial.begin(9600);             // monitor serie: elegir "Ambos NL & CR" para el HC-05
    bt.begin(38400);                // velocidad del modo AT del HC-05 (el HC-06 usa 9600)
    Serial.println(F("Puente AT listo. Escribí AT y enviá."));
}

void loop() {
    if (bt.available()) Serial.write(bt.read());      // del módulo a la computadora
    if (Serial.available()) bt.write(Serial.read());  // de la computadora al módulo
}

2. El nodo con HC-05

Con el módulo ya configurado, este programa atiende las órdenes y envía la temperatura. El cableado es el de la sección 6; el sensor es un TMP36 en A0.

#include <SoftwareSerial.h>

// ---------- Conexiones ----------
const uint8_t PIN_RX = 10;          // recibe: va al TXD del HC-05
const uint8_t PIN_TX = 11;          // transmite: va al RXD del HC-05 a través de un divisor de tensión
const uint8_t PIN_STATE = 9;        // STATE del HC-05: en alto cuando hay un enlace establecido
const uint8_t PIN_LED = 13;
const uint8_t PIN_TMP = A0;         // sensor TMP36: 500 mV a 0 °C y 10 mV por grado
SoftwareSerial bt(PIN_RX, PIN_TX);

// ---------- Estado ----------
const long INTERVALO_MIN = 1, INTERVALO_MAX = 3600;
uint16_t intervalo = 5;             // segundos entre envíos automáticos
char linea[32];
uint8_t n = 0;
bool desbordada = false;

// ---------- Utilidades ----------
int leerDecimas() {                 // décimas de grado: con 5 V, cada milivoltio sobre 500 es una décima
    long mv = analogRead(PIN_TMP) * 5000L / 1023;
    return (int)(mv - 500);
}

void formatearTemp(char *salida, size_t tam, int d) {
    int a = d < 0 ? -d : d;
    snprintf(salida, tam, "%s%d.%d", d < 0 ? "-" : "", a / 10, a % 10);
}

bool leerEntero(const char *texto, long &valor) {               // solo dígitos, de 1 a 4
    size_t largo = strlen(texto);
    if (largo < 1 || largo > 4) return false;
    valor = 0;
    for (size_t i = 0; i < largo; i++) {
        if (texto[i] < '0' || texto[i] > '9') return false;
        valor = valor * 10 + (texto[i] - '0');
    }
    return true;
}

// ---------- Protocolo: una orden por línea ----------
void responderTemperatura() {
    char t[10], r[20];
    formatearTemp(t, sizeof(t), leerDecimas());
    snprintf(r, sizeof(r), "T=%s", t);
    bt.println(r);
}

void procesar(const char *l) {
    long v;
    if (strcmp(l, "TEMP?") == 0) responderTemperatura();
    else if (strncmp(l, "LED ", 4) == 0 && (l[4] == '0' || l[4] == '1') && l[5] == 0) {
        digitalWrite(PIN_LED, l[4] == '1');
        bt.println("OK");
    } else if (strncmp(l, "INT ", 4) == 0) {
        if (leerEntero(l + 4, v) && v >= INTERVALO_MIN && v <= INTERVALO_MAX) { intervalo = v; bt.println("OK"); }
        else bt.println("ERR rango");
    } else if (strcmp(l, "AYUDA") == 0) bt.println("LED 0|1, TEMP?, INT 1-3600");
    else bt.println("ERR comando");
}

void servicioEntrada() {            // arma una línea a la vez, sin esperar
    while (bt.available()) {
        char c = bt.read();
        if (c == '\r') continue;
        if (c == '\n') {
            linea[n] = 0;
            if (!desbordada && n > 0) procesar(linea);
            else if (desbordada) bt.println("ERR largo");
            n = 0;
            desbordada = false;
            continue;
        }
        if (n < sizeof(linea) - 1) linea[n++] = c;
        else desbordada = true;     // se descarta el resto de la línea
    }
}

void servicioTelemetria() {
    static unsigned long ultimo = 0;
    if (digitalRead(PIN_STATE) == LOW) return;                  // sin enlace no se envía nada
    if (millis() - ultimo < (unsigned long)intervalo * 1000UL) return;
    ultimo = millis();
    responderTemperatura();
}

void setup() {
    pinMode(PIN_LED, OUTPUT);
    pinMode(PIN_STATE, INPUT);
    bt.begin(9600);                 // la velocidad de datos de fábrica del HC-05 y del HC-06
}

void loop() {
    servicioEntrada();
    servicioTelemetria();
}

Detalles que merecen atención. Los tres servicios no esperan: servicioEntrada procesa los bytes que hay y vuelve, y servicioTelemetria mira el reloj. La temperatura en décimas: el TMP36 entrega 10 mV por grado con 500 mV a 0 °C, de modo que cada milivoltio por encima de 500 es una décima de grado; el signo se trata aparte, como en el tema 33. El pin STATE evita enviar sin enlace. SoftwareSerial necesita que la línea RX tenga una interrupción de cambio de pin; en el UNO cualquier pin sirve, pero no puede recibir y transmitir a la vez, y es poco fiable por encima de 38400 baudios.

3. El ESP32 con BluetoothSerial

El ESP32 clásico tiene el Bluetooth dentro del chip y no necesita módulo. La biblioteca BluetoothSerial (incluida en el paquete de placas) ofrece una clase con la misma interfaz que Serial: begin, available, read, println. El nombre que se pasa a begin() es el que ve el teléfono.

#include <BluetoothSerial.h>            // solo en el ESP32 clásico (no en S3, C3 ni C6)

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error "Este ESP32 no tiene Bluetooth clásico o está desactivado"
#endif

BluetoothSerial SerialBT;
char linea[32];
uint8_t n = 0;

void alEvento(esp_spp_cb_event_t evento, esp_spp_cb_param_t *param) {
    if (evento == ESP_SPP_SRV_OPEN_EVT) Serial.println("Cliente conectado");
    else if (evento == ESP_SPP_CLOSE_EVT) Serial.println("Cliente desconectado");
}

void setup() {
    Serial.begin(115200);
    SerialBT.register_callback(alEvento);
    SerialBT.begin("ESP32-Sensor");     // el nombre que verá el teléfono; ofrece el perfil SPP
    Serial.println("Emparejá el teléfono con ESP32-Sensor");
}

void loop() {
    while (SerialBT.available()) {      // misma lectura de líneas que en el sketch del Arduino
        char c = SerialBT.read();
        if (c == '\r') continue;
        if (c == '\n') {
            linea[n] = 0;
            if (strcmp(linea, "TEMP?") == 0) SerialBT.println("T=23.5");   // reemplazar por la lectura real
            else SerialBT.println("ERR comando");
            n = 0;
            continue;
        }
        if (n < sizeof(linea) - 1) linea[n++] = c;
    }
}

Cuatro advertencias sobre el ESP32: solo el modelo clásico lo soporta, y el #error avisa al compilar para otros; consume mucha memoria (la pila de Bluedroid ocupa del orden de 300 a 400 kB de flash, y hay que elegir un esquema de particiones con espacio de aplicación suficiente); comparte la radio con el Wi-Fi, y usar los dos a la vez reduce el rendimiento de ambos; y con enableSSP() se activa el emparejamiento seguro simple (si se usa, el teléfono muestra una comparación numérica en lugar de pedir un PIN). La lectura de líneas es la misma que en el Arduino: el programa no se entera de qué hay debajo.

09 · Ver lo que pasa

Probar y depurar

La prueba se hace por capas, de la más cercana al hardware a la más alta:

  1. Alimentación y LED. Con el módulo solo, el LED debe parpadear rápido. Si no enciende, revisar la tensión y la masa común.
  2. Modo AT. Con el puente, AT debe responder OK. Si no responde o aparecen símbolos raros, la velocidad del monitor, del puente o del módulo no coinciden (en modo AT, el HC-05 trabaja a 38400 baudios; el HC-06, a 9600).
  3. Emparejamiento. Desde el teléfono, buscar dispositivos, elegir el nombre del módulo e ingresar el PIN. En Windows, el emparejamiento crea dos puertos COM virtuales (uno para conexiones salientes y otro para entrantes): se usa el saliente. En Linux, bluetoothctl y rfcomm bind /dev/rfcomm0 DIRECCIÓN 1.
  4. Eco. Una aplicación de terminal Bluetooth en el teléfono (como «Serial Bluetooth Terminal», en Android) se conecta al módulo; lo que se escribe aparece en el monitor serie del puente y viceversa.
  5. Protocolo. Con el nodo cargado, enviar TEMP?, LED 1, LED 2, INT 0, INT 10, una línea larga y AYUDA, y comparar con la tabla de la sección 7.
  6. Desde la computadora. Con el puerto COM virtual, un programa en Python con pyserial envía las mismas órdenes y las automatiza.
  7. Cortes y distancia. Alejarse hasta que el enlace se corte, y volver: el LED debe volver al parpadeo rápido y el pin STATE a bajo. Probar con una pared o con el cuerpo interpuesto.
Problemas frecuentes.
SíntomaCausa probable
El teléfono no encuentra el móduloEl módulo está conectado (el LED hace el doble parpadeo) o en modo AT; el HC-06 recién encendido necesita unos segundos; el teléfono cacheó una búsqueda anterior
Pide un PIN y no lo aceptaPIN distinto de 1234 o 0000 (el que se configuró); el teléfono tiene guardado el módulo con un PIN viejo: hay que «olvidar» el dispositivo y repetir
Aparecen caracteres basuraVelocidad distinta en el módulo y en el programa; la masa no es común; SoftwareSerial a velocidades altas
AT no respondeEl HC-05 no entró en modo AT (KEY no estaba en alto al encender); velocidad errónea; no se envía CR+LF; el HC-06 está conectado o necesita comandos sin terminador
Funciona unos minutos y se cortaLa alimentación se cae (al transmitir el módulo consume más); el regulador de la placa es débil; distancia o interferencia
Se pierden mensajesEl programa no vacía el buffer a tiempo (64 bytes); la UART va a baja velocidad; se envía sin enlace
El iPhone no ve el móduloNo es un error: iOS no soporta SPP; hay que usar un módulo BLE
El ESP32 no compila BluetoothSerialEl modelo no tiene Bluetooth clásico (S3, C3, C6) o la configuración lo desactiva

10 · Analogía con programación

Bluetooth en Python

Los cálculos de este tema (la velocidad de cada tipo de paquete, el cuello de botella de la UART, el alcance según las clases, la secuencia de comandos AT y la validación del protocolo) se pueden probar en la computadora. El modelo siguiente los reproduce y ejecuta la misma lógica de órdenes que el sketch.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

import math

RANURA_S = 625e-6                                            # una ranura de Bluetooth: 625 µs
PAQUETES = {                                                 # tipo: (bytes de datos, ranuras)
    "DM1": (17, 1), "DH1": (27, 1), "DM3": (121, 3), "DH3": (183, 3), "DM5": (224, 5), "DH5": (339, 5),
    "2-DH5": (679, 5), "3-DH5": (1021, 5),
}
CLASE_DBM = {1: 20, 2: 4, 3: 0}                              # potencia máxima de cada clase
HC06_BAUD = {1200: 1, 2400: 2, 4800: 3, 9600: 4, 19200: 5, 38400: 6, 57600: 7, 115200: 8}


def tasa(tipo, simetrica=False):
    datos, ranuras = PAQUETES[tipo]
    ranuras_totales = 2 * ranuras if simetrica else ranuras + 1       # el retorno ocupa una ranura
    return datos * 8 / (ranuras_totales * RANURA_S)


def tiempo_uart(nbytes, baudios):
    return nbytes * 10 / baudios                             # 8N1: 10 bits por byte


def alcance_m(clase_a, clase_b, sens=-80, margen=10, n=2.0, f_mhz=2441):
    presupuesto = min(CLASE_DBM[clase_a], CLASE_DBM[clase_b]) - sens - margen    # la clase menor limita
    pl_1m = 20 * math.log10(f_mhz) - 27.55
    return 10 ** ((presupuesto - pl_1m) / (10 * n))


def comandos_at(modulo, nombre, pin, baudios):
    if modulo == "HC-05":
        return [b"AT\r\n", f"AT+NAME={nombre}\r\n".encode(), f"AT+PSWD={pin}\r\n".encode(),
                f"AT+UART={baudios},0,0\r\n".encode(), b"AT+RESET\r\n"]
    return [b"AT", f"AT+NAME{nombre}".encode(), f"AT+PIN{pin}".encode(), f"AT+BAUD{HC06_BAUD[baudios]}".encode()]


def leer_entero(texto):
    return int(texto) if texto.isdigit() and 1 <= len(texto) <= 4 else None


def procesar(linea, estado):
    if linea == "TEMP?":
        return f"T={estado['temp']:.1f}"
    if linea.startswith("LED ") and linea[4:] in ("0", "1"):
        estado["led"] = linea[4:] == "1"
        return "OK"
    if linea.startswith("INT "):
        v = leer_entero(linea[4:])
        if v is not None and 1 <= v <= 3600:
            estado["intervalo"] = v
            return "OK"
        return "ERR rango"
    return "ERR comando"


def pin_tiempo_medio(digitos, por_segundo=1e6):
    return 10 ** digitos / 2 / por_segundo


print("tipo     datos ranuras  un sentido  simétrica")
for tipo in PAQUETES:
    d, r = PAQUETES[tipo]
    print(f"{tipo:>6} {d:>8} {r:>5} {tasa(tipo) / 1000:>10.1f} {tasa(tipo, True) / 1000:>10.1f} kbit/s")

for baud in (9600, 38400, 115200):
    print(f"UART a {baud:>6}: {baud / 10:>7.0f} bytes/s; 32 bytes tardan {tiempo_uart(32, baud) * 1000:.2f} ms; buffer de 64: {tiempo_uart(64, baud) * 1000:.1f} ms")
print(f"radio DH5: {tasa('DH5') / 8:,.0f} bytes/s, 32 bytes en {6 * RANURA_S * 1000:.2f} ms")

for a, b, n in ((2, 2, 2.0), (2, 1, 3.0), (1, 1, 3.0), (3, 3, 2.0), (1, 3, 2.0)):
    print(f"clases {a} y {b}, n = {n}: {alcance_m(a, b, n=n):.1f} m")

for linea in comandos_at("HC-05", "Sensor01", "4821", 115200):
    print("HC-05", linea)
for linea in comandos_at("HC-06", "Sensor01", "4821", 9600):
    print("HC-06", linea)

estado = {"temp": 23.5, "led": False, "intervalo": 5}
for linea in ("TEMP?", "LED 1", "LED 2", "INT 30", "INT 0", "INT 3601", "INT 12a", "HOLA"):
    print(f"{linea!r:>10} -> {procesar(linea, estado)!r}")
print(estado)

for d in (4, 6, 8, 12):
    print(f"PIN de {d} dígitos: {10 ** d:,} combinaciones, {pin_tiempo_medio(d):,.3f} s de media a 1e6/s")

Resultado: las velocidades salen 108,8 kbit/s (DM1), 172,8 (DH1), 387,2 (DM3), 585,6 (DH3), 477,9 (DM5), 723,2 (DH5), 1448,5 (2-DH5) y 2178,1 kbit/s (3-DH5) en un sentido, y 433,9 kbit/s para DH5 y 1306,9 para 3-DH5 en simétrico. La UART a 9600 baudios pasa 960 bytes por segundo (32 bytes en 33,33 ms, y el buffer de 64 bytes se llena en 66,7 ms), a 38 400 pasa 3840 y a 115 200, 11 520 bytes por segundo; la radio DH5 llega a 90 400 bytes por segundo. Con −80 dBm de sensibilidad y 10 dB de margen, dos módulos de clase 2 llegan a 49,0 m en espacio libre; clase 2 con clase 1 y n = 3, 13,4 m; dos de clase 1 con n = 3, 45,7 m; dos de clase 3 o una de clase 1 y una de clase 3 con n = 2, 30,9 m. Los comandos AT del HC-05 son AT, AT+NAME=Sensor01, AT+PSWD=4821, AT+UART=115200,0,0 y AT+RESET, todos con CR+LF; los del HC-06 con 9600 baudios, AT, AT+NAMESensor01, AT+PIN4821 y AT+BAUD4, sin terminador. Para las órdenes: TEMP? responde T=23.5; LED 1, OK; LED 2 y HOLA, ERR comando; INT 30, OK (y el intervalo pasa a 30); y INT 0, INT 3601 e INT 12a, ERR rango. Un PIN de 4 dígitos se agota en promedio en 0,005 s a un millón de pruebas por segundo, uno de 6 en 0,5 s, uno de 8 en 50 s y uno de 12 en 500 000 s (unos 5,8 días).

Es útil comparar los dos mundos: un protocolo de órdenes se prueba mucho más rápido en Python que en un microcontrolador con un módulo de radio, y la misma función de validación se traduce casi línea a línea a C.

11 · Exploración interactiva

Laboratorio: paquetes, UART, alcance, comandos AT y PIN

El laboratorio tiene cinco herramientas. La primera calcula la velocidad de un tipo de paquete y el tiempo de un mensaje. La segunda estudia el cuello de botella entre la UART y la radio. La tercera estima el alcance según la clase de potencia de los dos extremos. La cuarta arma los comandos AT de un HC-05 o un HC-06 y valida los datos. La quinta compara la seguridad de un PIN con la de la comparación numérica.

1. Paquetes y velocidad de la radio

Datos por paquete—
Velocidad en un sentido—
Velocidad simétrica—
Paquetes necesarios—
Tiempo en el aire—
Característica—

Elegí un tipo de paquete.

2. Cuello de botella: la UART

Tiempo por la UART—
Tiempo por la radio (DH5)—
Velocidad útil—
Carga de la UART—
Buffer de 64 bytes—
Veredicto—

Elegí la velocidad de la UART y el tamaño de los mensajes.

3. Alcance según la clase

Maestro al esclavo—
Esclavo al maestro—
Dirección que limita—
Alcance ideal—
Alcance con el entorno—
Referencia—

Elegí las clases de los dos extremos.

4. Comandos AT del HC-05 y el HC-06

Validación—
Secuencia de comandos—
Respuestas esperadas—
Cómo enviarlos—

Elegí el módulo y los datos nuevos.

5. Seguridad de un PIN

Combinaciones—
Tiempo medio del ataque fuera de línea—
Con comparación numérica (SSP)—
Veredicto—

Elegí la cantidad de dígitos.

En la herramienta 1, el tiempo de un mensaje cuenta, por cada paquete, las ranuras del paquete y una de respuesta. En la 2, la radio se supone con paquetes DH5 y la UART con 10 bits por byte (8N1). En la 3, se usa el modelo del tema 34 a 2,441 GHz con antenas de 0 dBi. En la 4, los comandos son los de los firmwares más comunes; los de tu módulo pueden variar. En la 5, el atacante captura el emparejamiento y prueba PIN en su computadora.

Recorrido guiado

  1. En la herramienta 1, con DH5 y 1000 bytes: 339 bytes en 5 ranuras, 723,2 kbit/s en un sentido y 433,9 simétrico; son 3 paquetes y unos 11,3 ms en el aire. Con 3-DH5 y 100 bytes: 1021 bytes por paquete, 2,18 Mbit/s y 1,31 Mbit/s simétrico, un solo paquete de 3,75 ms. Con DM1 y 20 bytes: 17 bytes, 108,8 kbit/s y 2 paquetes (2,50 ms). Con DH1 y 1000 bytes: 172,8 kbit/s y 38 paquetes (47,5 ms): los paquetes cortos son mucho menos eficientes. Con DH3: 585,6 kbit/s y 6 paquetes.
  2. En la herramienta 2, con los valores iniciales (9600 baudios, 32 bytes, 10 mensajes por segundo): la UART tarda 33,3 ms por mensaje y la radio 3,75 ms; el límite es la UART con 960 bytes/s, con una carga del 33 % y un buffer de 64 bytes que se llena en 66,7 ms. Subí a 115200: 2,78 ms por mensaje, 11 520 bytes/s y 2,8 % de carga. Con 115200 baudios, 200 bytes y 100 mensajes por segundo: 174 %, «sobrecarga». Con 9600 baudios, 100 bytes y 10 mensajes por segundo: 104 %, también sobrecarga.
  3. En la herramienta 3, con un maestro de clase 2 y un esclavo de clase 1 (n = 3): 74 dB en un sentido y 90 dB en el otro; limita la clase 2, con 49 m ideales y 13 m con n = 3. Poné 1 en el maestro: 90 dB en las dos direcciones, 309 m ideales y 46 m reales. Con 2 y 2 y n = 2: 49 m.
  4. En la herramienta 4, con los valores iniciales (HC-05, «Sensor01», PIN 4821, 115200): AT, AT+NAME=Sensor01, AT+PSWD=4821, AT+UART=115200,0,0 y AT+RESET, con CR+LF y a 38400 baudios. Con 06 y 9600: AT+NAMESensor01, AT+PIN4821 y AT+BAUD4, sin terminador. Con 06 y 230400: inválido (el HC-06 no admite esa velocidad). Con un PIN de 12: inválido (4 dígitos).
  5. En la herramienta 5, con 4 dígitos y un millón de pruebas por segundo: 10 000 combinaciones, 5 milisegundos: débil. Con 6: 0,5 s; con 8: 50 s; con 16: 158 años. Un PIN de 4 dígitos protege contra un curioso, no contra quien capture el emparejamiento.
Desafío: el brazo robótico de un taller

Un alumno quiere controlar un brazo robótico desde el teléfono con un HC-05 a 9600 baudios. Cada orden son 16 bytes y quiere enviar 30 órdenes por segundo (una por cada actualización de la pantalla táctil). ¿Anda? Con la herramienta 2: 16 bytes por 30 mensajes son 480 bytes por segundo, la mitad de los 960 bytes por segundo de la UART: carga del 50 %, apretado pero posible; cada mensaje tarda 16,7 ms. Pero si el programa del Arduino pasa más de 66 ms sin leer el buffer (por ejemplo, mientras mueve los motores con un delay o una función bloqueante), se pierden bytes. Soluciones: subir la UART a 38400 o 115200 (con una UART de hardware o un ESP32), vaciar el buffer en cada vuelta de loop() sin esperas, enviar solo cuando el valor cambia, y diseñar las órdenes para que puedan perderse: «posición = 90» (idempotente) y no «mover +5». Con un iPhone, ninguno de estos ajustes sirve: haría falta un módulo BLE (tema 38).

12 · Comprensión

Confusiones frecuentes

«Bluetooth clásico y BLE son lo mismo, solo que uno gasta menos»

Son dos radios distintos, con protocolos distintos, que no se entienden. Un HC-05 no habla con un módulo BLE, y un teléfono modo dual los atiende como dispositivos diferentes. Cada uno resuelve un problema distinto.

«El HC-05 funciona con cualquier teléfono»

Con Android y con las computadoras, sí. Con iPhone y iPad no: iOS no permite que las aplicaciones comunes usen SPP. Para ese caso, un módulo BLE.

«Con una radio de 723 kbit/s mis datos van a 723 kbit/s»

Entre el microcontrolador y el módulo hay una UART. A 9600 baudios pasan 960 bytes por segundo, unas noventa veces menos que la radio. Lo que limita es el eslabón más lento.

«Puedo conectar el TX del Arduino directo al RXD del HC-05»

La entrada del módulo es de 3,3 V. Con 5 V puede funcionar un tiempo y deteriorarla. Se usa un divisor resistivo (1 kΩ y 2 kΩ) o un adaptador de niveles. El otro sentido, del módulo al Arduino, no necesita nada.

«Un módulo que no aparece en la búsqueda no se puede conectar»

Ser descubrible es optativo. Un dispositivo que no responde a la búsqueda puede aceptar una llamada si se conoce su dirección. Esconderse no es un mecanismo de seguridad.

«Con Bluetooth cifrado, el protocolo no necesita validación»

El cifrado protege el enlace de terceros, pero el que está conectado puede enviar cualquier cosa: por error o con mala intención. El programa valida largo, caracteres y rango de todo lo que llega, igual que con cualquier entrada de red.

«El PIN de 4 dígitos es suficiente porque solo se prueba unas pocas veces»

Eso vale si el atacante debe probar contra el dispositivo. Con el emparejamiento heredado, quien captura el intercambio prueba los PIN en su propia computadora, sin límite de intentos: 10 000 combinaciones son milisegundos.

«Un HC-05 sirve para un dispositivo a baterías»

Gasta decenas de mA mientras espera y unos mA conectado, siempre. Una pila de botón no dura ni un día. Para baterías, BLE con ciclo de trabajo bajo (tema 38) o apagar el módulo entre usos.

«El maestro es el que tiene más potencia o el que envía datos»

El maestro es el que inició la conexión y marca el reloj y los turnos. Cualquiera de los dos puede ser fuente de datos, y los datos van en los dos sentidos.

13 · Práctica guiada

Predecí antes de comprobar

1. Tiempo en el aire

¿Cuánto tarda, como mínimo, un mensaje de 1000 bytes con paquetes DH5? ¿Y con 3-DH5?

Ver solución

DH5 lleva 339 bytes: 1000 / 339 → 3 paquetes. Cada uno ocupa 5 ranuras más una de respuesta: 6 · 0,625 ms = 3,75 ms, y el total son 11,25 ms. Con 3-DH5 (1021 bytes) entra en un solo paquete: 3,75 ms.

2. La UART como límite

Un nodo envía líneas de 50 bytes. ¿Cuántas por segundo puede transmitir a 9600 baudios y a 115200?

Ver solución

A 9600 baudios (8N1) pasan 960 bytes por segundo: 960 / 50 = 19,2 líneas por segundo (52 ms cada una). A 115200, 11 520 bytes por segundo: 230 líneas por segundo (4,3 ms cada una). En los dos casos la radio, con 90 400 bytes por segundo, queda lejos de ser el límite.

3. Alcance

Dos módulos de clase 2 con −80 dBm de sensibilidad y 10 dB de margen, ¿qué alcance tienen en espacio libre? ¿Y si uno de ellos se reemplaza por uno de clase 1?

Ver solución

Presupuesto: 4 + 80 − 10 = 74 dB, y con una pérdida a 1 m de 40,2 dB resultan 10(74 − 40,2)/20 ≈ 49 m. Si uno es de clase 1, el otro sigue transmitiendo con 4 dBm, y el enlace es de las dos direcciones: sigue siendo de 49 m. El esclavo de clase 1 se oirá a más distancia, pero no puede oír al maestro.

4. Comandos AT

Escribí la secuencia para dejar un HC-06 con nombre «Garaje», PIN 7391 y 115200 baudios. ¿Y en qué se diferencia la del HC-05?

Ver solución

HC-06 (a 9600 baudios, sin terminador, con 1 s entre comandos): AT+NAMEGaraje, AT+PIN7391, AT+BAUD8. El HC-05 (a 38400 baudios, en modo AT, con CR+LF): AT+NAME=Garaje, AT+PSWD=7391, AT+UART=115200,0,0, con un signo igual y los parámetros de la velocidad (parada y paridad) explícitos.

5. El divisor de tensión

Con R1 = 1 kΩ en serie y R2 = 2 kΩ a masa, ¿qué tensión llega al RXD del HC-05 cuando D11 está en alto a 5 V? ¿Y si el Arduino es de 3,3 V?

Ver solución

V = 5 · 2 / (1 + 2) = 3,33 V. Con un Arduino de 3,3 V el divisor ya no hace falta: la salida está a 3,3 V y se conecta directo (con el divisor, caería a 2,2 V, que podría no ser suficiente).

6. PIN o comparación numérica

¿Cuánto tarda en promedio un ataque fuera de línea contra un PIN de 4 dígitos a un millón de pruebas por segundo? ¿Y qué probabilidad tiene un atacante interpuesto de pasar inadvertido contra una comparación numérica de 6 dígitos?

Ver solución

10 000 combinaciones; la mitad, 5000, a un millón por segundo: 5 milisegundos. Contra la comparación numérica de 6 dígitos, el atacante tiene 1 posibilidad en 1 000 000 por intento de que los números coincidan y el usuario no note nada, y no puede repetir los intentos sin que se vea.

7. Validar el protocolo

¿Qué responde el nodo del sketch a LED 1, LED 2, INT 0, int 5, INT 45 y a una línea de 40 caracteres?

Ver solución

LED 1: OK. LED 2: el carácter 2 no es 0 ni 1: ERR comando. INT 0: está fuera del rango 1 a 3600: ERR rango. int 5: las órdenes distinguen mayúsculas, así que ERR comando. INT 45: OK (el intervalo pasa a 45 s). La línea de 40 caracteres supera el buffer de 32 bytes: ERR largo y se descarta entera.

14 · Síntesis

Ideas para recordar

  • Bluetooth clásico (BR/EDR) y Bluetooth Low Energy son dos tecnologías de radio distintas, incompatibles entre sí. El clásico sirve para flujos continuos (audio, puerto serie); BLE, para mensajes breves con consumo mínimo. Los módulos HC-05 y HC-06 y el ESP32 clásico son de clásico; el ESP32-S3, C3 y C6 no.
  • La radio usa 79 canales de 1 MHz en 2,4 GHz y salta 1600 veces por segundo; el tiempo se divide en ranuras de 625 µs y el maestro habla en las pares y el esclavo en las impares. El salto adaptativo evita los canales ocupados por Wi-Fi. Hay paquetes de 1, 3 y 5 ranuras (DM con corrección, DH sin ella, EDR con modulación de fase): hasta 723 kbit/s en 1 Mbit/s y 2,18 Mbit/s en EDR.
  • Las clases de potencia (100 mW, 2,5 mW, 1 mW) dan alcances nominales de 100, 10 y 1 m; el módulo con menos potencia limita el enlace. El presupuesto de enlace y el exponente del entorno dan los números.
  • Una conexión forma una piconet con un maestro y hasta siete esclavos activos. Se establece por búsqueda (inquiry), llamada (page), emparejamiento y apertura de los canales del perfil.
  • La pila se divide en host y controlador por la interfaz HCI: radio, banda base y LMP abajo; L2CAP, RFCOMM, SDP y los perfiles arriba. SPP es el perfil que emula un puerto serie sobre RFCOMM; los iPhone no lo soportan.
  • El emparejamiento por PIN (heredado) es débil: con 4 dígitos, quien captura el intercambio lo rompe en milisegundos. El emparejamiento seguro simple (SSP, con curva elíptica) protege contra escucha y, con comparación numérica de 6 dígitos, deja una posibilidad en un millón al atacante interpuesto. Se cambia el PIN de fábrica, se actualiza el firmware y se valida todo lo que llega.
  • El HC-05 y el HC-06 son módulos serie de 3,3 V en las señales: el RXD se alimenta con un divisor (1 kΩ y 2 kΩ). Se configuran con comandos AT (el HC-05 con KEY en alto, a 38400 baudios y con CR+LF; el HC-06 a 9600 y sin terminador). La UART, no la radio, limita la velocidad: 960 bytes por segundo a 9600 baudios.
  • Un puerto serie inalámbrico no tiene mensajes ni confirmaciones: el protocolo lo pone el programa. Una orden por línea, un buffer de tamaño fijo, validación de largo y rango, respuesta siempre, y órdenes idempotentes para tolerar la pérdida. El pin STATE evita enviar sin enlace.
  • Se prueba por capas: alimentación, modo AT, emparejamiento, eco, protocolo y distancia. Para baterías, para iPhone o para conexiones de milisegundos, Bluetooth clásico no es la herramienta: para eso está BLE.

¿Listo para el siguiente tema?

Antes de avanzar, explicá por qué el máximo de un HC-05 conectado a 9600 baudios es de 960 bytes por segundo aunque la radio llegue a 723 kbit/s; decidí qué pasaría si un módulo de clase 1 se conectara con uno de clase 3 (limita el de clase 3); y justificá por qué un teléfono Android puede comunicarse con un HC-05 con una aplicación de terminal y un iPhone no. Si podés justificar las tres respuestas, entendés cómo funciona un puerto serie sobre Bluetooth clásico.

En el próximo tema pasamos a Bluetooth Low Energy: otra radio, otro modelo de comunicación (servicios y características en lugar de un puerto serie), conexiones de milisegundos y consumos de microamperios, y compatibilidad con iPhone. Es el Bluetooth de los sensores a baterías.