How can I fix this code so that my AVR can talk through the serial port?

Recently, I have been pulling my hair out trying to get an ATmega162 on my STK200 to talk to my computer over RS232. I checked and made sure that the STK200 contains the MAX202CPE chip.

I set up the chip to use its internal 8 MHz clock and divided it by 8.

I tried to copy the code from the data sheet (and made changes where the compiler complained), but to no avail.

My code is below, can someone please help me fix the problems I have?

I confirmed that my serial port works on other devices and is not faulty.

Thanks!

#include <avr/io.h> #include <avr/iom162.h> #define BAUDRATE 4800 void USART_Init(unsigned int baud) { UBRR0H = (unsigned char)(baud >> 8); UBRR0L = (unsigned char)baud; UCSR0B = (1 << RXEN0) | (1 << TXEN0); UCSR0C = (1 << URSEL0) | (1 << USBS0) | (3 << UCSZ00); } void USART_Transmit(unsigned char data) { while(!(UCSR0A & (1 << UDRE0))); UDR0 = data; } unsigned char USART_Receive() { while(!(UCSR0A & (1 << RXC0))); return UDR0; } int main() { USART_Init(BAUDRATE); unsigned char data; // all are 1, all as output DDRB = 0xFF; while(1) { data = USART_Receive(); PORTB = data; USART_Transmit(data); } } 
+4
source share
4 answers

After reading the data sheet a little more carefully, I set the speed incorrectly. The ATmega162 data sheet contained a clock diagram based on the data transfer rate and the corresponding error.

For 4800 baud and a clock frequency of 1 MHz, the error was 0.2%, which was acceptable to me. The trick passed 12 instead of USART_Init () instead of 4800.

Hope this helps someone else!

+2
source

I commented on Greg's answer, but would like to add one more thing. For these kinds of problems, the gold standard debugging method is to first understand the asynchronous serial communication, then get an oscilloscope and see what happens on the line. If the characters are exchanged, and this is just a vigorous problem, it will be especially useful, since you can calculate the speed that you see, and then adjust the divider accordingly.

Here is a super fast primer, no doubt you can find something much more complete on Wikipedia or elsewhere.

Assume 8 bits, no parity, 1 stop bit (the most common setting). Then, if the transmitted character says 0x3f (= ascii '?'), Then the line looks like this:

 ...--+ +---+---+---+---+---+---+ +---+--... | S | 1 1 1 1 1 1 | 0 0 | E +---+ +---+---+ 

A high (1) level is + 5 V on the chip and -12 V after conversion to RS232 levels.

Low (0) level is 0 V on the chip and +12 V after conversion to RS232 levels.

S is the start bit.

Then we have 8 bits of data that are least significant at first, so here 00111111 = 0x3f = '?'.

E is the stop bit (e for the end).

Time moves from left to right, just like an oscilloscope display. If the speed is 4800, then each bit spans (1/4800) seconds = 0.21 milliseconds (approximately).

The receiver works by taking a sample of the line and distorting the falling edge (a calm line is simply logical “1” all the time). The receiver knows the transmission speed and the number of start bits (1), so it measures half the bit-bit from the falling edge to find the middle of the start bit, then sequentially punches the line for 8 bits in a row after that to collect the data bit. Then the receiver waits for another bit time (half way through the stop bit) and starts looking for another start bit (that is, the falling edge). In the meantime, the symbol read becomes available to the rest of the system. The transmitter ensures that the next falling edge does not start until the stop bit is completed. The transmitter can be programmed to always wait longer (with additional stop bits), but this is an obsolete problem, additional stop bits are only necessary with very slow hardware and / or software settings.

+6
source

I do not have reference material, but the UBRR data rate register usually contains the value of the divider, and not the most desired data rate. A quick google search indicates that the correct divisor value for 4800 baud may be 239. So try:

 divisor = 239; UBRR0H = (unsigned char)(divisor >> 8); UBRR0L = (unsigned char)divisor; 

If this does not work, refer to the reference documents for your specific chip for the correct divisor calculation formula.

+5
source

There are two useful things to debug UART communications:

1) Make feedback on the connector and make sure that you can read what you write. If you send a character and return it accurately, you know that the equipment is correctly connected and that at least the basic UART register settings are correct.

2) Resend the character 0x55 ("U") - the binary bit 01010101 will allow you to quickly see the bit width on the oscilloscope, which allows you to check the correct speed setting.

+5
source

All Articles