Archivo por días: 27 diciembre, 2025

Cuando muchos baudios no funcionan

Estos días estoy haciendo un pequeño proyecto con un Arduino UNO, y me he encontrado con que el puerto serie no funciona correctamente a velocidades mayores de 57 600 baudios: cada vez que intentaba utilizar 115 200 baudios, mi terminal recibía basura.

Tras mucho investigar, descubrí que el problema es debido a que la UART del Atmega 328P que lleva el Arduino UNO utiliza el mismo reloj externo de 16MHz, pero toma 16 muestras de cada bit, por lo que la velocidad efectiva es 1MHz. Esa frecuencia es la que se divide para obtener la velocidad de transmisión/recepción deseada, y aquí es donde viene el problema: la fórmula para obtener el divisor que hay que programar en el registro del Atmega es, en el caso de un reloj externo de 16MHz como en el Arduino Uno, (16 000 000 / 16·baudios) – 1, y si calculamos el valor para 115 200, el resultado es 7,68… que no es un número entero, con lo que el divisor real será 7. Eso significa que la velocidad real del puerto serie es de 125 000 baudios. Tenemos un error de casi un 9%, que es mucho para un puerto serie. Para velocidades inferiores el error es menor; por ejemplo, para 57 600 tenemos que el valor es 16,36, con lo que la velocidad real es 58 823, y el error es de aproximadamente un 2%, más que aceptable para un puerto serie.

Podríamos pensar «Bueno, pero si la UART a la que está conectada también utiliza un reloj de 1MHz, el error será el mismo y debería funcionar». Y así es… salvo por el detalle de que no es el caso. El Arduino original era una placa diseñada para conectarse directamente al puerto serie de un PC, pero con la desaparición de éstos a manos del puerto USB, el fabricante decidió añadir un conversor USB<->serie directamente en la placa, específicamente el FT232. Si nos fijamos en el esquema interno que viene en su datasheet, vemos que la UART utiliza el mismo reloj que el subsistema USB, que es de 48MHz. También en el datasheet vemos que el divisor de la UART ofrece un reloj con una frecuencia 16 veces superior a la deseada; pero dado que parte de una frecuencia tres veces superior, la precisión es mucho mayor. En concreto, para 115 200, la velocidad real es 115 385 baudios. Esto explica por qué no es capaz de comunicarse a esa velocidad con el microcontrolador: la diferencia es demasiada.

¿Y cómo solucionamos este problema? Simple: calculamos la velocidad real a la que está trabajando el sistema de menos precisión (Atmega), y utilizamos esa velocidad en el sistema de más precisión (FT232). Para ello, utilizamos la función:

velocidad_real = reloj_externo / (16·(floor(reloj_externo/(16·velocidad deseada))))

Así, si ponemos el Atmega a 115 200 baudios, la velocidad real será 125 000 baudios. Poniendo 125 000 baudios en el FT232 la velocidad real será… ¡125 000 baudios también! Lo que tiene sentido, porque la frecuencia de reloj del FT232 es un múltiplo entero de la del Atmega.

Con este método he podido aumentar la velocidad del puerto serie hasta 500 000 baudios sin problemas.