krismath
krismath

Reputation: 1969

AVR USART transmitting only 2 chars

Below is a code ran on an ATmega328P. It's supposed to send "abcdef" to my computer every second. However, it sent me only "ab" every second. What is wrong here?

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

void USART_transmit(unsigned char data);
void print(const unsigned char *buffer, size_t n);
void print(const char* str);

int main(void) {
    // Serial.begin(115200)
    UCSR0B |= (1<<TXEN0);
    UBRR0L = 8;

    while(1){
        // Serial.write(i)
        print("abcdef");

        _delay_ms(1000);
    }
}

void USART_transmit(const uint8_t data) {
    /* wait for empty transmit buffer */
    while (!UCSR0A & (1<<UDRE0));
    UDR0 = data;
}

void print(const uint8_t *buffer, size_t n) {
    while(n--){
        USART_transmit(*buffer++); //**
    }
}

void print(const char *str) {
    if(strlen(str) != 0) print((const uint8_t *) str, strlen(str));
}

The code resulted in:

ababababababababababab...

Changing from USART_transmit(*buffer++); to USART_transmit(n + 48); (+48 to convert to char) resulted in:

5454545454545454545454545454...

So I guess the loop shouldn't be stopping?

Upvotes: 0

Views: 529

Answers (1)

Rev
Rev

Reputation: 6092

The "data register empty" check is wrong.

while (!UCSR0A & (1<<UDRE0));

should be

while (!(UCSR0A & (1 << UDRE0)));

In your case, the check is not blocking until the buffer is empty. I think one byte is buffered in the USART output buffer and one byte is pending in UDR. Every additional byte is then discarded, this is why you see only "ab".

Upvotes: 2

Related Questions