1

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.

OooO
  • 13
  • 1
  • 8
  • 1
    I wonder why UART receive function returns `unsigned long long`, esp. in an 8-bit MCU like AVR? – phuclv Jun 19 '14 at 11:01
  • What is the use of `_delay_ms(100); USART_Transmit(data);`in the main program? – pingul Jun 19 '14 at 11:04
  • Did you make sure that the above code is correct? You declare `USART_Receive` then call `Usart_Receive`. You also you assign the return value of `Usart_Receive` which most probably an `unsigned long long` to an `unsigned char`. And you only pass a char to `USART_Transmit` but inside the function it's an `unsigned long` cast to an `unsigned long long` – phuclv Jun 19 '14 at 11:05
  • about `_delay_ms(100);` @pingul , this delay function was to complete the transmission or wait for the datatobe receive. If I remove this delay, it come out nonsense. I have try that. – OooO Jun 19 '14 at 12:32
  • Yes, I sure this code is correct, because I just test it right now, and about the `unsigned long long`, and change to `unsigned char`, the result is just the same. And I sorry about the `USART_receive` and `Usart_receive`, it a little bit typo there,but I already change it @LưuVĩnhPhúc . This code is really work, if I can show you the results picture, but I can not do it, because I dont have enough points, haha. sorry about that. – OooO Jun 19 '14 at 12:34
  • You should use char type instead of unsign long long or unsigned long, which are very inefficient on 8-bit MCU, and there's no point returning long long just to assign it to a char, and no point to use long as argument just to receive char too – phuclv Jun 19 '14 at 13:21

2 Answers2

3

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.

Rev
  • 5,330
  • 4
  • 21
  • 49
-2

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.

OooO
  • 13
  • 1
  • 8