¿Está cuantificada la tasa de baudios en serie del ATMEGA328P?

Estoy usando un ATMEGA328p, ejecutándose desde su oscilador interno (dividido por 8 = 1MHz).

He medido (aproximadamente) la salida del oscilador, usando mi analizador lógico Salae, en un rango de 960 KHz a 1000 KHz, por lo que no es horrible. Hice esto usando el fusible "Salida de reloj en PORTB0".

Si configuro la velocidad en baudios en 9600, emite en serie a 10220 baudios. (¿Esto es porque no estoy usando un cristal o por la cuantificación?)

Si aumento F_CPU o disminuyo USART_BAUDRATE, gradualmente, la salida en baudios en serie no disminuye, hasta que salta a 8800 baudios.

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 

int main(void) {
        // serial port setup
        UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
        UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
        UBRR0H = (BAUD_PRESCALE >> 8);
        UBRR0L = BAUD_PRESCALE;
        ...

¿Hay alguna forma de cuantificación que afecte a los baudios de salida?

PD: estoy usando GCC en Linux para compilar el código y no estoy usando el código/IDE de Arduino.

Respuestas (3)

Como ya se mencionó, esta cuantificación es fundamental para la arquitectura, que solo puede dividir el reloj de origen por un número entero.

Sin embargo, su problema es bastante evitable. El ATmega UART puede operar en dos modos; uno donde necesita un reloj a 16x la tasa de baudios, y otro donde el reloj solo necesita ser 8x.

Está utilizando el modo 16x, lo que significa que necesita un divisor entero de 62,5 KHz (1 MHz / 16) que producirá 9600 baudios. Eso sería alrededor de 6.5 que no se puede usar. Si, en cambio, divide por 6, obtiene 10417 baudios teóricos, que está más lejos de 9600 de lo deseable.

Sin embargo, si en su lugar usa el modo 8x, ahora puede dividir 125 KHz a 9600, algo que el número 13 se aproxima muy de cerca para producir 9615 baudios.

Entonces, la solución real a su problema es operar el UART en modo de "doble velocidad" y usar 8 en lugar de 16 en la fórmula para calcular el divisor. Dado que la división real es el valor programado más uno, escribiría 12 en los registros del divisor.

Es un sistema totalmente digital. Debe operar en pasos discretos.

Esta es la fórmula de la hoja de datos:ingrese la descripción de la imagen aquí

El registro UBRR tiene 16 bits de ancho (UBRRL + UBRRH), por lo que solo puede conducir a 65536 configuraciones de baudios posibles.

Mire también la sección "24.11. Ejemplos de configuración de velocidad de transmisión" y la tabla 24-4 de la hoja de datos.

Si posee un analizador lógico preciso, es posible que desee calibrar la frecuencia del reloj interno a través de OSCCAL (registro de calibración del oscilador) para obtener una mayor precisión. De todos modos, casi siempre se necesita un oscilador de cristal en una comunicación asíncrona limpia.

Si bien puede haber un pequeño error de reloj aquí, el problema específico sobre el que se pregunta no tiene nada que ver con la calibración, sino que es fundamental para la división del reloj entero. En realidad, los ATmegas generalmente funcionan bien para la comunicación en serie asíncrona usando el oscilador interno sin ninguna medida de calibración adicional; el problema real aquí es que el chip se configuró incorrectamente de una manera que produciría una tasa de baudios bastante errónea incluso con un reloj de fuente perfecto.
@ChrisStratton Muy bien, leí tu respuesta y parece tener sentido. Es un problema relacionado con la programación. Tenía la intención de publicar esto como un comentario, pero no tengo suficiente reputación ☹.