SALIDA AVR USART casi similar a la entrada

Mi salida es diferente de mi entrada cuando trato de leerla desde mi terminal Hercules. ¿Podría deberse a una mala inicialización de UART?

Entradas : | a, 1, 123

Salidas:|a, ±, ±²³

Código:

#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 1000000 // 1 Mhz
#endif

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

int main (void)
{
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8-bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8) ; // Load upper 8-bits of the baud rate value into the high byte
                                    //of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8 -bits of the baud rate value into the low byte of the
    //UBRR register
    for (;;) // Loop forever
    {
    while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is
    //ready to be read from UDR
    ReceivedByte = UDR ; // Fetch the received byte value into the variable "ByteReceived"
while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to
//be written to it
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}
}

Respuestas (1)

Usando números aproximados para 9600 con un reloj de 1MHz 1000000 / 9600 / 16 = 6.51 que se truncará a 6 y luego se reducirá a 5 una vez que se reste 1. Puede ver que pierde mucha precisión cuando los números divisores son tan pequeños que se convierten en un número entero. Aquí hay una calculadora que puede resultarle útil:

Calculadora de tasa de baudios AVR de WormFood

Eso muestra un error del 7,5% que es demasiado alto, necesitará más del 5% para un funcionamiento confiable si el dispositivo al que está conectado es muy preciso, pero normalmente me gusta apuntar a un error del 2% o menos. Las alternativas que vienen a la mente son cambiar la frecuencia de cristal (o apagar el CKDIV8fusible si lo está usando) o elegir una tasa de baudios como 4800 que tenga un margen de error aceptable a esa tasa de reloj.

Aunque mirando la tabla más a fondo (haciendo clic en la casilla de verificación correspondiente), otra opción sería usar el U2X=1modo que duplica la frecuencia de reloj UART efectiva que reduciría el error al 0,2%. En ese caso, su código debe incluir:

#define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 8UL ))) - 1)
UCSRA |= (1 << U2X);

Eso hace que el receptor muestree la mitad de la frecuencia, por lo que puede que no sea tan confiable, pero podría ser una opción si hay una razón por la que no desea aumentar la frecuencia del reloj.

¿Cómo sabes que 5 es malo?
Es solo porque la diferencia entre 5 y 5.51 es bastante grande como porcentaje. Digamos que usó un reloj de 10MHz, sería 65.1 - 1 = 64.1, y la diferencia entre 64 y 64.1 es mucho menor como porcentaje.