2
votes

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?

2
Are you sure you uploaded right .hex to your MCU? I mean, maybe you have changed UCSRC in older FW versions and then you only think that it is wrong.dunajski
I have checked them all many timesKJA

2 Answers

0
votes

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!!!!

0
votes

#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