Receive a String

2.1k views Asked by At

How to received string in uart. I am using avr studio 5 and brays terminal like this one

enter image description here

Same as this picture I am using baudrate of 9600. Went I try to type "abcdef", it only come out "abcf" .

My code are like this --->

#include <avr/io.h>

void serial_init(void)
{
    UBRRH = 0x00;
    UBRRL = 95;   //baudrate 9600 and F_CPU 14745600UL
    UCSRB =  (1 << RXEN) | (1 << TXEN) | (1<<RXCIE); 
    UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)|(1 << UCSZ1);
}

unsigned long long Usart_Receive(void)          
{
    while((UCSRA & (1 << RXC)) == 0) {};
    return UDR;
}
void USART_Transmit(unsigned long c)   
{
    PORTD= 0b00000100;  //RTS Enable
    while ((UCSRA & (1 << UDRE)) ==0) {};
    UDR = c;
    PORTD= 0b00000000;  //RTS Disable
}

int main(void)
{
    unsigned char data;
    serial_init();
    while (1)
    {
        data = Usart_Receive();
        _delay_ms(100);
        USART_Transmit(data);
    }
    return 0;   
}

Simple as that, but I cannot find my problem why it only appear 4 letter at the terminal. I hope somebody can help about this. THANK.

2

There are 2 answers

0
OooO On BEST ANSWER

Here are the answer that are work.

int main(void)
 {

    char data[1][40];   
    int i1 = 0;
    int i2 = 0;
        serial_init();

        while (1)
    {

        for (i1=0;i1<1;i1++) 
            { 
               for (i2=0;i2<40;i2++) 
               { 
                  data[i1][i2] = Usart_Receive(); 
               } 
            } 

           for (i1=0;i1<1;i1++) 
           { 
               for (i2=0;i2<40;i2++) 
               { 
                  Usart_Transmit(data[i1][i2]); 
               } 
           }       

      }  
    return 0;   
}

Thank for those who are helping me before this.

0
Rev On

As one of the comments already pointed out, you declare USART_Receive but call Usart_Receive. This shouldn't even compile (without warning at least), since C is case sensitive. You should also change the return value to char or uint8_t.

The actual cause of problem that you only receive/echo 'abcf' when you actually send 'abcdef' probably is the _delay_ms(100);. Transmitting a character @9600 baud takes about 1ms.
The AVR controllers only provide a very small FIFO (one or two bytes) on the receive side that will overflow if the UDR register isn't read out after an appropriate interval (depending on transmission speed, obviously).

The current receive sequence would be something like:

  • Usart_Receive() is waiting for first char 'a'
  • UDR is immediately cleared by reading it
  • wait 100ms (UDR is not read during this time)
  • during the 100ms delay (remember that transmitting 5 chars only takes about 5ms)
    • 'b' is received into UDR
    • 'c' is pending in the first FIFO byte
    • 'd' is pending in the receive sequence
    • 'e' will overwrite 'd'
    • 'f' will overwrite 'e'
  • after 100ms you echo 'a'
  • 'b' is read from UDR, 'c' is moving from FIFO byte to UDR and 'f' is moving to first FIFO byte
  • 100ms pause
  • echo 'b'
  • 'c' is read from UDR, 'f' is moving from FIFO byte to UDR
  • 100ms pause
  • echo 'c'
  • 'f' is read from UDR
  • 100ms pause
  • echo 'f'

-> abcf

You have to make sure that UDR is polled at least every millisecond. Another solution would be an interrupt based approach, where you handle each received char in the corresponding ISR without risking the main code blocking your UDR readout.