0
\$\begingroup\$

I'm trying to learn how to use the USART interface on an Atmega328p. For now, I just try to send a 'c' character bytes every 500 ms and read it on my computer using a PL2303 USB-serie TTL converter.

Data are transmitted, but I don't get the result I want on the receiving side.

Here is what I have programmed in my microcontroller:

#define BAUDRATE 9600
#define BAUD (((F_CPU / (BAUDRATE * 16UL))) - 1)
void uart_init()
{ 
 UBRR0 = BAUD;
 /* 8 data bites, no parity, one stop bit */
 UCSR0C |= _BV(UCSZ01) | _BV(UCSZ00);
 /* Enable UART input and output */
 UCSR0B |= _BV(RXEN0) | _BV(TXEN0);
}
int main()
{
 uart_init();
 for (;;)
 {
 while ((UCSR0A & _BV(UDRE0)) == 0);
 UDR0 = 'c';
 _delay_ms(500);
 }
}

I read the data in python using pyserial:

import serial
with serial.Serial(
 '/dev/ttyUSB0',
 baudrate=9600,
 bytesize=serial.EIGHTBITS,
 parity=serial.PARITY_NONE) as port:
 while True:
 print(port.read())

I somehow have the correct result. I have some correct bytes 'c', but about one of two is '\xe3':

b'\xe3'
b'c'
b'\xe3'
b'c'
b'\xe3'
b'\xe3'
b'\xe3'
b'c'
b'c'
b'c'
b'\xe3'

It seems that I have a random high order byte that appears from time to time.

I can't manage to find where is my problem. I check on the scope, and the data sent are always the same. So I think I have something wrong on the receiving side. But can't find what it can be. I have double checked F_CPU, which is at 1Mhz.

asked May 1, 2017 at 19:39
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You cant do that combination of F_CPU, baud rate & prescaler. The math just doesn't work. Your actual baud rate (which you'll see if you measure it on a 'scope) is about 10416, not 9600 - so you're often seeing the stop-bit as the last data bit (the MSb). \$\endgroup\$ Commented May 1, 2017 at 19:44

1 Answer 1

1
\$\begingroup\$

There is too much error in your baud-rate clock. (1MHz/9600*16) = 6.51. This gets rounded down to 6 so the frequency error is (6.51/6)-1 = 8.5%.

UART baud rate needs to have better than 5% accuracy to avoid receive errors. Why? The receiver starts timing when the Start bit goes low, then samples the signal in the middle of each bit. If the frequency is wrong then the sampling point will progressively slip relative to the middle of each bit. After 9 bits at 5% error the sample point is just within the correct bit period, but at 8.5% error it is in the previous bit (so the Stop bit is detected as bit 7).

enter image description here

The UART at the sending end also has some timing error. If the errors are in the same direction at both ends then they will partially cancel and you might get away with>5% error. But if they are in opposite directions then it will be worse. So in order to assure that any two random systems can communicate without error their baud rates must be accurate to better than +-2.5%. Other effects such as timing and sampling jitter, noise and uneven slew rates may reduce the margin even more.

For an ATmega328 running at 1MHz you can set the U2X0 bit in UCSR0A and make UBRR0 = 12, then you should get 9615.38 Baud which is only 0.2% error (plus any error in system clock frequency).

AVR Baud Rate Calculator

answered May 1, 2017 at 21:36
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.