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í:
| Aspecto | Clásico (BR/EDR) | Low Energy (BLE) |
|---|---|---|
| Aparece | 1999 (versión 1.0); 2004 con EDR (2.0) | 2010 (versión 4.0) |
| Objetivo | Flujos continuos: audio, serie, archivos | Mensajes breves y ocasionales con consumo mínimo |
| Velocidad | 1 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 |
| Consumo | Decenas de mA mientras la conexión está activa | Un ciclo de trabajo muy bajo: pocos µA de media |
| Conexión | Segundos para descubrir y emparejar | Milisegundos para conectar |
| Uso típico | Auriculares, manos libres, audio, puerto serie inalámbrico | Sensores, relojes, balizas, accesorios |
| Tema del curso | Este | Tema 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:
| Módulo o chip | Clásico | BLE | Notas |
|---|---|---|---|
| HC-05, HC-06 | Sí (2.0 + EDR) | No | Módulos externos con interfaz serie; el HC-06 solo hace de esclavo |
| HM-10, JDY-08 y similares | No | Sí | Módulos serie BLE (tema 38) |
| ESP32 clásico | Sí | Sí | Modo dual; ambos comparten la radio con el Wi-Fi |
| ESP32-S3, ESP32-C3, ESP32-C6 | No | Sí | Solo BLE: el código de este tema no compila |
| Arduino UNO R4 WiFi, Nano 33 BLE | No | Sí | 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.
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:
| Tipo | Modulación | Datos útiles | Ranuras | Un sentido | Simétrico |
|---|---|---|---|---|---|
| DM1 | GFSK, con FEC 2/3 | 17 bytes | 1 | 108,8 kbit/s | 108,8 kbit/s |
| DH1 | GFSK | 27 bytes | 1 | 172,8 kbit/s | 172,8 kbit/s |
| DM3 / DH3 | GFSK | 121 / 183 bytes | 3 | 387,2 / 585,6 kbit/s | 258,1 / 390,4 kbit/s |
| DM5 / DH5 | GFSK | 224 / 339 bytes | 5 | 477,9 / 723,2 kbit/s | 286,7 / 433,9 kbit/s |
| 2-DH5 | π/4-DQPSK (EDR) | 679 bytes | 5 | 1448,5 kbit/s | 869,1 kbit/s |
| 3-DH5 | 8DPSK (EDR) | 1021 bytes | 5 | 2178,1 kbit/s | 1306,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
| Clase | Potencia máxima | Alcance nominal | Dispositivos típicos |
|---|---|---|---|
| 1 | 100 mW (20 dBm) | ≈ 100 m | Adaptadores USB de largo alcance, algunos módulos industriales |
| 2 | 2,5 mW (4 dBm) | ≈ 10 m | Teléfonos, HC-05 y HC-06, la mayoría de los módulos |
| 3 | 1 mW (0 dBm) | ≈ 1 m | Accesorios 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:
- 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».
- 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.
- 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.
- 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
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.
| Perfil | Para qué sirve | Ejemplo |
|---|---|---|
| SPP (Serial Port Profile) | Puerto serie inalámbrico | HC-05, instrumentos, robots, ESP32 con BluetoothSerial |
| HFP y HSP | Llamadas telefónicas (manos libres, auricular) | Auto, auricular |
| A2DP y AVRCP | Audio estéreo y control de reproducción | Parlante, auriculares |
| HID | Teclado, ratón, joystick | Teclado inalámbrico, mando |
| PAN | Red IP sobre Bluetooth | Compartir Internet del teléfono |
| OPP y FTP | Transferir objetos y archivos | Enviar 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étodo | Cómo funciona | Protecció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 aire | Dé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 nada | Protege contra escucha pasiva, no contra un atacante interpuesto (MITM) |
| SSP: comparación numérica | Los dos muestran un número de 6 dígitos y el usuario confirma que coinciden | Un MITM tiene una probabilidad de 1 en 1 000 000 de pasar desapercibido por intento |
| SSP: ingreso de clave | Un 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 banda | Los 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=1yAT+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
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.
| Pin | Función |
|---|---|
| VCC y GND | Alimentación (3,6 a 6 V) y masa común con el microcontrolador |
| TXD | Salida serie del módulo (a 3,3 V): va al RX del microcontrolador |
| RXD | Entrada serie del módulo (3,3 V): recibe del TX del microcontrolador, con divisor |
| STATE | Salida: 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:
| Aspecto | HC-05 | HC-06 |
|---|---|---|
| Roles | Maestro o esclavo (configurable) | Solo esclavo |
| Velocidad de datos de fábrica | 9600 baudios (8N1) | 9600 baudios (8N1) |
| Modo AT | Con KEY en alto al encender: 38400 baudios; terminan con CR+LF | Siempre, mientras no hay conexión: 9600 baudios; sin terminador |
| Nombre y PIN de fábrica | HC-05 · 1234 | linvor o HC-06 · 1234 |
| Pin STATE y KEY | Sí | 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:
| Comando HC-05 | Efecto | Equivalente HC-06 |
|---|---|---|
AT | Prueba; responde OK | AT |
AT+VERSION? | Versión del firmware | AT+VERSION |
AT+NAME=Sensor01 | Cambia el nombre visible | AT+NAMESensor01 |
AT+PSWD=4821 | Cambia el PIN (algunos firmwares: AT+PSWD="4821") | AT+PIN4821 |
AT+UART=115200,0,0 | Velocidad, 1 bit de parada, sin paridad | AT+BAUD8 (4 = 9600, 8 = 115200) |
AT+ROLE=1 | Maestro (0 = esclavo) | — |
AT+ADDR? | Dirección BD_ADDR del módulo | — |
AT+CMODE=1 y AT+BIND=98d3,31,fc1234 | Se conecta solo a la dirección indicada (con comas en lugar de dos puntos) | — |
AT+ORGL | Restablece los valores de fábrica | — |
AT+RESET | Reinicia 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).
| Orden | Respuesta | Efecto |
|---|---|---|
TEMP? | T=23.5 | Lee la temperatura (décimas de grado, con el signo manejado aparte) |
LED 1 / LED 0 | OK | Enciende o apaga el LED |
INT 30 | OK o ERR rango | Intervalo de envío automático en segundos (1 a 3600) |
AYUDA | Texto de ayuda | Lista las órdenes |
| cualquier otra | ERR comando | Nada |
| una línea de más de 31 caracteres | ERR largo | Se 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:
- 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.
- Modo AT. Con el puente,
ATdebe responderOK. 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). - 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,
bluetoothctlyrfcomm bind /dev/rfcomm0 DIRECCIÓN 1. - 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.
- Protocolo. Con el nodo cargado, enviar
TEMP?,LED 1,LED 2,INT 0,INT 10, una línea larga yAYUDA, y comparar con la tabla de la sección 7. - Desde la computadora. Con el puerto COM virtual, un programa en Python con
pyserialenvía las mismas órdenes y las automatiza. - 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.
| Síntoma | Causa probable |
|---|---|
| El teléfono no encuentra el módulo | El 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 acepta | PIN 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 basura | Velocidad distinta en el módulo y en el programa; la masa no es común; SoftwareSerial a velocidades altas |
AT no responde | El 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 corta | La 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 mensajes | El 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ódulo | No es un error: iOS no soporta SPP; hay que usar un módulo BLE |
El ESP32 no compila BluetoothSerial | El 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
Elegí un tipo de paquete.
2. Cuello de botella: la UART
Elegí la velocidad de la UART y el tamaño de los mensajes.
3. Alcance según la clase
Elegí las clases de los dos extremos.
4. Comandos AT del HC-05 y el HC-06
Elegí el módulo y los datos nuevos.
5. Seguridad de un PIN
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
- 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.
- 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.
- 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.
- 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,0yAT+RESET, con CR+LF y a 38400 baudios. Con 06 y 9600:AT+NAMESensor01,AT+PIN4821yAT+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). - 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.