1
\$\begingroup\$

Using an ISR on the atmega328 to read a string ended by a \r from UART and echo back the readout string afterwards

volatile char usart_input_buffer[8];
volatile int usart_in_count = 0;
volatile int usart_valid = 0;

ISR(USART_RX_vect)
{
    usart_input_buffer[usart_in_count] = UDR0;

    if(strcmp(usart_input_buffer[usart_in_count],'\r')) {
        usart_in_count = 0;
        usart_valid = 1;
    } else {
        usart_in_count++;
    }
}

void serial_send(char* ar) {
    int i;
    for (i = 0; i < strlen(ar); i++){
        while (( UCSR0A & (1<<UDRE0))  == 0){};
        delayms(1);
        UDR0 = ar[i];
    }
}

void init_uart() {
    CLKPR = 128;
    CLKPR = 0;
    DDRD |= (1 << PIND1);
    DDRD &= ~(1 << PIND0);
    UCSR0B |= (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0);   // Turn on the transmission and reception circuitry
    UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes
    UBRR0H = 0;
    UBRR0L=54;
}

int main() {
    init_uart();
    sei();
    while(1) {
        if(usart_valid == 1) {
            serial_send(usart_input_buffer);
            usart_valid = 0;
        }
    }
    return 1;
}

But the result that comes back, is messed up and contains a maximum of 1 correct character, intermittently.. What could be wrong?

\$\endgroup\$
1
\$\begingroup\$

Bugs in code not withstanding, that sounds more like a baud rate issue. If there is some consistency in characters that are correct, I would expect the following:

  • Slowing down data transmission (increasing delay between bytes) would increase the consistency of the results, as you would be less likely to cause a framing error
  • Bytes with a lot of 0's at the end are more likely to be correct, as the timing error accumulates throughout the packet. That would be things like numbers and control codes.

I would recommend using a logic analyzer or oscilloscope to verify the bit time on both systems. Depending on how you generate the clock frequency on the microcontroller, you may have an unstable clock reference (e.g. RC oscillator).

\$\endgroup\$
1
\$\begingroup\$

You have a few problems here.

strcmp compares 2 null terminated strings, but you are using it to compare usart_input_buffer (which is not null terminated) with a character '\r' which is also not a null terminated string. Try

if(usart_input_buffer[usart_in_count] == '\r') {

Also, to make a string null terminated you have to add the terminating null yourself. Like this:

if(usart_input_buffer[usart_in_count] == '\r') {
    usart_input_buffer[usart_in_count+1] = '\0';
    usart_in_count = 0;
    usart_valid = 1;
} else {
    usart_in_count++;
}
\$\endgroup\$
  • 2
    \$\begingroup\$ And it should be payed attention to a potential buffer overflow. Check usart_in_count with respect to sizeof(usart_input_buffer). \$\endgroup\$ – Rev1.0 Jun 26 at 7:52
  • 1
    \$\begingroup\$ "to make a string null terminated..." which is also required for strlen to work... \$\endgroup\$ – JimmyB Jun 26 at 11:19
  • \$\begingroup\$ Weirdly, the reason I went to strcmp was that if not being true ever.. I'll retry it, though.. \$\endgroup\$ – Rando Hinn Jun 26 at 20:44
  • \$\begingroup\$ @Steve G, I can now confirm, that the if statement you have proposed, does indeed not work.. usart_input_buffer[usart_in_count] == '\r' is never true \$\endgroup\$ – Rando Hinn Jun 27 at 15:30
  • \$\begingroup\$ Actually.. it is true in some really weird occasional cases, but the output back is still garbage. \$\endgroup\$ – Rando Hinn Jun 27 at 16:58

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.