3
\$\begingroup\$

I seem to be getting random character in my USART output with an ATMEGA8

uart.c

#define FOSC 8000000
#define BAUD_RATE 9600
#define UBRR_VALUE (uint16_t)(FOSC/16/BAUD_RATE-1)

#include "uart.h"

volatile u8buf UART_RCV_BUFFER;
FILE uart0_str = FDEV_SETUP_STREAM(UARTSendByte, UARTReceiveByte, _FDEV_SETUP_RW);

ISR(USART_RXC_vect)
{
    //got a byte from USART. add to buffer
    volatile uint8_t data;
    scanf("%c",&data);
    if((UART_BUFFER_WRITE(&UART_RCV_BUFFER, data)==1) || (data=='.'))
    {
        //either buffer full or '.' received
        //stop the UART receiver unit + disable interrupt
        UCSRB &= ~((1<<RXEN) | (1<<RXCIE));
    }
}

ISR(USART_UDRE_vect)
{
    volatile uint8_t data;
    if(UART_BUFFER_READ(&UART_RCV_BUFFER, &data)==1)
    {
        //end of buffer reached. nothing more to transmit
        //disable RX
        UCSRB &= ~((1<<RXEN) | (1<<RXCIE));
        //reset buffer
        UART_BUFFER_INIT(&UART_RCV_BUFFER);
        //enable  RX side
        UCSRB |= ((1<<RXEN) | (1<<RXCIE));
    }
    else printf("%c",&data);
}

void UART_WRITE_STRING(char* str)
{
    //Sending a string without any command
    //disable RX/TX interrupts
    UCSRB &= ~((1<<RXCIE) | (1<<UDRIE));
    printf("%s",str);
    //re-enable RX/TX interrupts
    UCSRB |= (1<<RXCIE) | (1<<UDRIE);
}


void UART_INIT(void)
{
    UBRRH = (uint8_t)(UBRR_VALUE>>8); //set UBRR register
    UBRRL = (uint8_t)UBRR_VALUE;
    UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);//set frame format: asynchronous,8data,1stop,no parity
    UCSRB = (1<<TXEN) | (1<<RXEN) | (1<<RXCIE) | (1<<UDRIE);

    UART_BUFFER_INIT(&UART_RCV_BUFFER);
    stdin=&uart0_str;
    stdout=&uart0_str;  
}


void UART_BUFFER_INIT(volatile u8buf *buf)
{
    buf->index = 0;
}

uint8_t UART_BUFFER_WRITE(volatile u8buf *buf, volatile uint8_t data)
{
    if(buf->index<UART_RCV_BUF_SIZE)
    {
        buf->index = data;
        buf->index++;
        return 0;
    }
    else return 1;

}

uint8_t UART_BUFFER_READ(volatile u8buf *buf, volatile uint8_t *data)
{
    if(buf->index>0)
    {
        buf->index--;
        *data = buf->buffer[buf->index];
        return 0;
    }
    else return 1;
}

int UARTSendByte(char u8data, FILE *stream)
{
    if(u8data=='\n')
    {
        UARTSendByte('\r',0);
    }
    while(!(UCSRA&(1<<UDRE))){};
    UDR = u8data;
    return 0;
}

int UARTReceiveByte(FILE *stream)
{
    uint8_t data;
    // Wait for byte to be received
    while(!(UCSRA&(1<<RXC))){};
    data=UDR;
    //echo input data
    UARTSendByte(data,stream);
    // Return received data
    return data;
}

main.c

#include "uart.h"
#include "twi.h"



int main (void)
{
    DDRC = 0x01; //set PC0 as output
    PORTC = 0x01; //turn on PC0
    //PD0 = RXD = INPUT
    //PD1 = TXD = OUTPUT
    DDRD = 0x03;

    UART_INIT(); //initialize UART
    sei(); //Enable global interrpts

    //_delay_ms(500);   

    UART_WRITE_STRING("Hello World ! 1:)\n");
    UART_WRITE_STRING("Hello World ! 2:)\n");
    UART_WRITE_STRING("Hello World ! 3:)\n");
    for(;;)
    {

    }
}

This upon execution should give me

Hello World ! 1:)
Hello World ! 2:)
Hello World ! 3:)

But what i get is

\n\nHello World ! 1:)
Hello World ! 2:)
Hello World ! 3:)

the number of \n is random. Sometimes there is none, sometimes 1 or 2 or 3. Any idea what I am doing wrong here?

\$\endgroup\$
  • \$\begingroup\$ @sherrellbc Agreed. That's more of a programming style habit but I do like your shortcut. However that should be the cause of my issue \$\endgroup\$ – Ankit Jun 24 '14 at 13:07
  • \$\begingroup\$ Did you somehow overload printf? I don't see what you did there. Your USART_WRITE_STRING() just calls printf. Without proper spacing and indentions the code is a bit hard to read. Check out an earlier version of a USART implementation I wrote for the AtMega328p here. I think I had some issues with setting the baud rate with that code, so just change that part and it should work just fine. I can post my final version later if you want once I have access to it. I also appear to have left out usart_writeString() at that point. \$\endgroup\$ – sherrellbc Jun 24 '14 at 13:14
  • \$\begingroup\$ .. But it just calls usart_writeByte() in a loop until the char* points to '\0' since the passed string literals are always null-terminated. \$\endgroup\$ – sherrellbc Jun 24 '14 at 13:15
4
\$\begingroup\$

It is a good habit to flush serial input buffer on your PC before starting to use it to ensure sender and receiver are synchronized. One useful trick is not to send your raw data, but encapsulate it in a frame of which you can easily recognize start, end and payload. You probably want to add a checksum too, so you can simply check if the data you received is the same as the data you tried to send.

Useful similar other questions:

\$\endgroup\$
  • \$\begingroup\$ thank you for the links. Increasing the baud rate to 38400 and using 2 stop bits seems to have solved the issue \$\endgroup\$ – Ankit Jun 26 '14 at 3:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.