Mega 328 uart baud rate calculation

7 posts / 0 new
Author
Message

Hello, i need help clarifiyng someting. I am trying to make my atmega328(16MHz) talk via max3232 rs232 ic to main PLC. So far i managed to get atmega to send ASCII char to PLC and for PLC to recognize it.

But here is my dillema:

in datasheet there equation for calculation like this:

UBRRn=(FOSC/(16*baud))-1

-this one does not work for me

on all the forums i see equation:

UBRRn=((F_CPU/16/BAUD) - 1)

-this one only work for me if i change divider 16, to somewhere beetwen 230 and 270, so it comes to:

UBRRn=((F_CPU/245/BAUD) - 1)

whit divider of 245 i get almsot 95% accuracs on my PLC or serial monitor.

I also had to add delay of 1ms, or else the readout on serial monitor is jsut random code.

UBRRn = baud register

FOSC is oscilaltor frequency

And BAUD is baud rate which is 9600.

This is code:

```
#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 16000000
#define BAUD 9600
#define UBRRn ((F_CPU/245/BAUD) - 1)

int main(void){

char ar[]= "03gfg4";

int stlgt = 6; // string length

UBRR0H = (UBRRn >> 8); // UART setup
UBRR0L = UBRRn;
UCSR0B = (1 << TXEN0)| (1 << TXCIE0) | (1 << RXEN0) | (1 << RXCIE0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //////
UCSR0A = (0 << U2X0);

while (1){
for (int i = 0; i < stlgt; i++){
while (( UCSR0A & (1<<UDRE0))  == 0){};         // wait until the port is ready to be written to
UDR0 = ar[i];
_delay_ms(1); // delay for stability
if (i == (stlgt - 1)){ // return after whole char is sent
return 0;
}
}
}
}
```

This topic has a solution.

Last Edited: Fri. Aug 11, 2017 - 06:53 AM
This reply has been marked as the solution.

Klemko wrote:
in datasheet there equation for calculation like this: UBRRn=(FOSC/(16*baud))-1 -this one does not work for me

First, you have to remember that you are in a programming language.  In this case, C.  There are rules for evaluating expressions.  (16*baud) with baud being 9600 will do, on this platform, 16-bit integer multiply.  16*9600 overflows 16-bit signed value, so you will not get what you think.

There must be a zillion working examples of GCC UBR settings on these forums alone...this one is pertinent

https://www.avrfreaks.net/forum/w...

That indicates that indeed UBR value of 103 gives a minimal error, much less than the about 2% USART tolerance for good comms.

Examine the generated code to see what UBRRL value you are really getting...about 6 or 5?

...which leads to:  What speed is your AVR really running at?  What clock source is being used?  The symptoms indicate that your AVR is really running at the default ~1MHz.  And you see from the chart that you cannot expect reliable comms at that speed. unless U2X is used.

Please post a complete test program that demonstrates your symptoms.  There are interrupt sources enabled, but no ISRs shown.

Your toolchain has a utility header setbaud.h to do calculations for you.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Thu. Aug 10, 2017 - 02:40 PM

thanks a loooot for nice desriptive answer, i will study all through and do it right way :DD

I think you have not set your fuses correctly......

it seems your processor is running on its internal 8MHz RC oscillator with the CLK/8 fuse bit still set.

So effectively your processor is running at 1MHz.

so your frequency is a factor of 16 off. that means your divider has to be 16 times higher

16 * 16 = 256

the 245 is rather close to that.

As running from the internal RC gives an inaccurate clock you still get errors every now and then.

If you are not sure you can set a pin to toggle once a second and then see how fast or slow it really changes

Last Edited: Fri. Aug 11, 2017 - 06:37 AM

Thank you good sir, i did not know i have to also set up clock fuses. Now after reading your post and diving into datasheet soem more, i have set clock fuse to external 16MHz, and divider fuse for 8 to get 2MHz(im running on 3.3V), got UBRR value of 12(12,02 from calcualting formula, so accuracy realy is around 0.2%) from datasheet and now communication works like a charm. Even whi no delays at full speed i havent notice any error. Thanks again to all who helped ;D

Klemko wrote:
and divider fuse for 8 to get 2MHz
If that is the case then why have you done?:

```#define F_CPU 16000000
#define BAUD 9600
#define UBRRn ((F_CPU/245/BAUD) - 1)```

The 16000000 here is wrong. If you know the CPU speed is 2MHz then why does that not say:

```#define F_CPU 2000000
```

If you "lie" about the F_CPU setting you WILL get the wrong result. There is no question that the forumlae is (FOSC/(16*baud))-1 which is obviously, by simple algebra, (FOSC/16/baud)-1

16MHz/16/9600 - 1 is 103.16666. As you cannot use fractional parts you would therefore use 103.

2MHz/16/9660 - 1 is 12.0208333 so you would use 12.

Using your 16MHz/245/9600 - 1 it is 5.80272 so I guess you were putting 5 in the UBRR ? I have no idea how that was working if the CPU was really running at 2MHz?!? That suggests you are wrong and it is not running at 2MHz. As Lee pointed out:

While the "close" value for 9600 @ 1MHz is 6 not 5 all this does rather suggest the micro is running at somewhere near 1MHz. So there's a string chance that when you say:

Klemko wrote:
i have set clock fuse to external 16MHz
you have not actually achieved that.

"There is no question that the forumlae is (FOSC/(16*baud))-1 which is obviously, by simple algebra, (FOSC/16/baud)-1"

You might want to read Dean Camera's tutorial "Using the USART in AVR-GCC" at http://www.fourwalledcubicle.com....

From Chapter 4

# define USART_BAUDRATE 9600
// Naive Version - has rounding bugs !
//# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL))) - 1)
// Better Version - see text below

# define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)