Reputation: 31
I have recently come up to program Atmega8 with no external crystal for serial communication using hardware uart. I have checked many code samples and libraries. But at the end there was no success: This is the code:
#define F_CPU 1000000UL
#define UART_BAUD 19200
#include <avr/io.h>
#include <util/delay.h>
#define BAUDRATE ((F_CPU)/(UART_BAUD*16UL)-1) // set baud rate value for UBRR
// function to initialize UART
void uart_init (void)
{
UBRRH = (BAUDRATE>>8); // shift the register right by 8 bits
UBRRL = BAUDRATE; // set baud rate
UCSRB|= (1<<TXEN)|(1<<RXEN); // enable receiver and transmitter
UCSRC|= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); // 8bit data format
}
// function to send data
void uart_transmit(unsigned char data)
{
while (!( UCSRA & (1<<UDRE))); // wait while register is free
UDR = data; // load data in the register
}
// function to receive data
unsigned char uart_recieve(void)
{
while((!(UCSRA)) & (1<<RXC)); // wait while data is being received
return UDR; // return 8-bit data
}
int main(void)
{
DDRB = 0b00000001; // set LED pin as OUTPUT
PORTB = 0b00000001; // set all pins to LOW
uart_init();
while (1)
{
for(unsigned char i=10; i< 127; i++)
{
uart_transmit (i);
_delay_ms(10);
}
uart_transmit ('A');
uart_transmit (13);
uart_transmit (10);
_delay_ms(500);
PORTB = 1-PORTB;
}
return 0;
}
The code is written to send date at baud rate of 19200 with 8 bit length, No parity bits and 1 stop bits.
The problem is that when I check the out put using a USB to TTL converter and terminal program, I get the following results for the above code for a configuration of 19200-7-N-2 and 19200-7-N-1
0A 0B 0C 0D 0E - 0F 10 11 12 13 ..... .....
14 15 16 17 18 - 19 1A 1B 1C 1D ..... .....
1E 1F 00 01 02 - 03 04 05 06 07 ..... .....
08 09 0A 0B 0C - 0D 0E 0F 10 11 ..... .....
12 13 14 15 16 - 17 18 19 1A 1B ..... .....
1C 1D 1E 1F 20 - 21 22 23 24 25 .... !"#$%
26 27 28 29 2A - 2B 2C 2D 2E 2F &'()* +,-./
30 31 32 33 34 - 35 36 37 38 39 01234 56789
3A 3B 3C 3D 3E - 3F 20 21 22 23 :;<=> ? !"#
24 25 26 27 28 - 29 2A 2B 2C 2D $%&'( )*+,-
2E 2F 30 31 32 - 33 34 35 36 37 ./012 34567
38 39 3A 3B 3C - 3D 3E 21 0D 0A 89:;< =>!..
At this configuration it seems to be a missing bit no. 6 For a configuration of 19200-8-N-2 and 19200-8-N-1 I get the following results in terminal
8A 8B 8C 8D 8E - 8F 90 91 92 93 ..... .....
94 95 96 97 98 - 99 9A 9B 9C 9D ..... .....
9E 9F 80 81 82 - 83 84 85 86 87 ..... .....
88 89 8A 8B 8C - 8D 8E 8F 90 91 ..... .....
92 93 94 95 96 - 97 98 99 9A 9B ..... .....
9C 9D 9E 9F A0 - A1 A2 A3 A4 A5 ..... .....
A6 A7 A8 A9 AA - AB AC AD AE AF ..... .....
B0 B1 B2 B3 B4 - B5 B6 B7 B8 B9 ..... .....
BA BB BC BD BE - BF A0 A1 A2 A3 ..... .....
A4 A5 A6 A7 A8 - A9 AA AB AC AD ..... .....
AE AF B0 B1 B2 - B3 B4 B5 B6 B7 ..... .....
B8 B9 BA BB BC - BD BE A1 23 E1 ..... ...#.
At this configuration there seems to be an extra bit no. 8 set to 1 and again missing bit no. 6.
Any suggestion on the problem origin?
Upvotes: 2
Views: 1939
Reputation: 4654
#define BAUDRATE ((F_CPU)/(UART_BAUD*16UL)-1)
with F_CPU = 1'000'000, UART_BAUD = 19'200 and rounding downwards gives you:
1000000 / (19200 * 16) - 1 = 2
and actual uart speed will be
1000000 / 16 / (2 + 1) = 20833
which gives you 8.5% error.
Even enabling 2x mode (U2X
in UCSRA
) will not help. It is not possible to correctly setup USART to communicate on this speed, when clocking from 1MHz source.
But, when clocking from the internal RC-oscillator you can select higher output speed of the prescaler (by setting the fuses accordingly, or doing it programmatically).
E.g. you can select 2 MHz main clock frequency and setup the USART to utilize 2x mode:
// rounding toward nearest integer, instead of downwards
// divide by 8 (instead of 16) in 2x mode
#define BAUDRATE ((F_CPU + (UART_BAUD*4))/(UART_BAUD*8)-1) // set baud rate value for UBRR
...
void uart_init (void)
{
// the gcc compiler is able to update UBRRH and UBRRL on its own
UBRR = BAUDRATE; // set baud rate
UCSRA = (1 << U2X); // enable 2x mode
UCSRB = (1<<TXEN)|(1<<RXEN); // enable receiver and transmitter
UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); // 8bit data format
}
...
Now, with F_CPU = 2'000'000, BAUDRATE value will be:
(2000000 + (4 * 19200)) / (8 * 19200) - 1 = 12
And actual speed:
2000000 / 8 / (12 + 1) = 19231
which gives less than 0.2% error
Upvotes: 1
Reputation: 31
Finally got to solve the problem I just added an external crystal and it started working flawlessly. I didn't expect that much of effect from internal oscillator!!!!
Upvotes: 0