Dec-29th-2008

Using the USART of AVR Microcontrollers : Reading and Writing Data


Till now we have seen the basics of RS232 communication, the function of level converter and the internal USART of AVR micro. After understanding the USART of AVR we have also written a easy to use function to initialize the USART. That was the first step to use RS232. Now we will see how we can actually send/receive data via rs232. As this tutorial is intended for those who are never used USART we will keep the things simple so as to just concentrate on the "USART" part. Of course after you are comfortable with usart you can make it more usable my using interrupt driven mechanism rather than "polling" the usart.

So lets get started! In this section we will make two functions :-

  • USARTReadChar() : To read the data (char) from the USART buffer.
  • USARTWriteChar(): To write a given data (char) to the USART.

This two functions will demonstrate the use of USART in the most basic and simplest way. After that you can easily write functions that can write strings to USART.

Reading From The USART : USARTReadChar() Function.

This function will help you read data from the USART. For example if you use your PC to send data to your micro the data is automatically received by the USART of AVR and put in a buffer and bit in a register (UCSRA) is also set to indicate that data is available in buffer. Its now your duty to read this data from the register and process it, otherwise if new data comes in the previous one will be lost. So the funda is that wait until the RXC bit (bit no 7) in UCSRA is SET and then read the UDR register of the USART.

(See the full description of USART registers)


char USARTReadChar()
{
   //Wait untill a data is available

   while(!(UCSRA & (1<<RXC)))
   {
      //Do nothing
   }

   //Now USART has got data from host
   //and is available is buffer

   return UDR;
}

Writing to USART : USARTWriteChar()

This function will help you write a given character data to the USART. Actually we write to the buffer of USART and the rest is done by USART, that means it automatically sends the data over RS232 line. One thing we need to keep in mind is that before writing to USART buffer we must first check that the buffer is free or not. It its not we simply wait until it is free. If its not free it means that USART is still busy sending some other data and once it finishes it will take the new data from buffer and start sending it.

Please not that the data held in the buffer is not the current data which the USART is busy sending. USART reads data from the buffer to its shift register which it starts sending and thus the buffer is free for your data. Every time the USART gets it data from buffer and thus making it empty it notifies this to the CPU by telling "USART Data Register Ran Empty" (UDRE) . It does so by setting a bit (UDRE bit no 5) in UCSRA register.

So in our function we first wait until this bit is set (by the USART ), once this is set we are sure that buffer is empty and we can write new data to it.

(See the full description of USART registers)


void USARTWriteChar(char data)
{
   //Wait until the transmitter is ready

   while(!(UCSRA & (1<<UDRE)))
   {
      //Do nothing
   }

   //Now write the data to USART buffer

   UDR=data;
}


Note: Actually their are two separate buffers, one for transmitter and one for receiver. But they share common address. The trick is that all "writes" goes to the Transmitter's buffer while any "read" you performs comes from the receiver's buffer.

That means if we read UDR we are reading from receivers buffer and when we are writing to UDR we are writting to transmitters buffer.

UDR=some_data; //Goes to transmitter

some_data=UDR; //Data comes from receiver

(See the full description of USART registers)

Sample program to use AVR USART

The following program makes use of the two functions we developed. This program simply waits for data to become available and then echoes it back via transmitter but with little modification. For example if you send "A" to it, it will send you back "[A]" that is input data but surrounded by square bracket. This program is enough to test the USART yet easy to understand.


/*

A simple program to demonstrate the use of USART of AVR micro

*************************************************************

See: www.eXtremeElectronics.co.in for more info

Author : Avinash Gupta
E-Mail: me@avinashgupta.com
Date : 29 Dec 2008

Hardware:
   ATmega8 @ 16MHz

   Suitable level converter on RX/TX line
   Connected to PC via RS232
   PC Software :  Hyper terminal @ 19200 baud
               No Parity,1 Stop Bit,
               Flow Control = NONE

*/

#include <avr/io.h>
#include <inttypes.h>

//This function is used to initialize the USART
//at a given UBRR value
void USARTInit(uint16_t ubrr_value)
{

   //Set Baud rate

   UBRRL = ubrr_value;
   UBRRH = (ubrr_value>>8);

   /*Set Frame Format


   >> Asynchronous mode
   >> No Parity
   >> 1 StopBit

   >> char size 8

   */

   UCSRC=(1<<URSEL)|(3<<UCSZ0);


   //Enable The receiver and transmitter

   UCSRB=(1<<RXEN)|(1<<TXEN);


}


//This function is used to read the available data
//from USART. This function will wait untill data is
//available.
char USARTReadChar()
{
   //Wait untill a data is available

   while(!(UCSRA & (1<<RXC)))
   {
      //Do nothing
   }

   //Now USART has got data from host
   //and is available is buffer

   return UDR;
}


//This fuction writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(char data)
{
   //Wait untill the transmitter is ready

   while(!(UCSRA & (1<<UDRE)))
   {
      //Do nothing
   }

   //Now write the data to USART buffer

   UDR=data;
}

void main()
{
   //This DEMO program will demonstrate the use of simple

   //function for using the USART for data communication

   //Varriable Declaration
   char data;

   /*First Initialize the USART with baud rate = 19200bps
   
   for Baud rate = 19200bps

   UBRR value = 51

   */

   USARTInit(51);    //UBRR = 51

   //Loop forever

   while(1)
   {
      //Read data
      data=USARTReadChar();

      /* Now send the same data but but surround it in
      square bracket. For example if user sent 'a' our
      system will echo back '[a]'.

      */

      USARTWriteChar('[');
      USARTWriteChar(data);
      USARTWriteChar(']');

   }
}

Download Sample Program

Running the USART Demo

You can run the above program in a ATmega8, ATmega16, ATmega32 cpu running at 16MHz without any modification. If you are using different clock frequency you have to change the UBRR value that we are passing to USARTInit() function. See previous tutorial for calculating UBRR value. The MCU should be connected to PC using a RS232 level convertor. In PC you can run hyper terminal to send/receive data via usart. Start hyper terminal and press keys on your keyboard. The keys you press will be sent via PC's serial port to the AVR micro where our program will echo it back but with surrounded brackets. The data sent by the MCU will be received by the PC's serial port and will be displayed by the Hyper terminal.

See Also


36 Responses to “Using the USART of AVR Microcontrollers : Reading and Writing Data”

  1. 1
    Avinash Says:

    @Raghu

    That will require the knowledge abt the underlying robot hardware like sensor position and number etc …

  2. 2
    percy villegas t Says:

    Hello Avinash

    I can send data from my Pc “C#” to Usart ”Atmega32” with RS232 line, it work without problem.

    Now I will send the information without RS232 line, I want send the information with Bluetooth. I need a Transmitter and receiver can you recommend me some who is easy to use?

    Why you don’t program in CodeVisionAVR it is much easy? And the program is gratis but you must also use AVR Studio for simulation. But write code is much easy with CodeVisionAVR.

    Thanks for all your help!!!!

    Percy Villegas.

  3. 3
    newman Says:

    hi use this code for intrnal oscilator atmega8 8Mhz baud rate 9600. what all must i change? UBRR=51 ? or what change in software AVR Studio

  4. 4
    Ritesh Says:

    Hello Avinash,

    you have used UCSRB=(1<<RXEN)|(1<<TXEN); for no interrupt , what should we use if there is a interrupt

  5. 5
    Ritesh Says:

    Hello Avinash,

    you have used UCSRB=(1<<RXEN)|(1<<TXEN); for no interrupt , what should we use if there is a interrupt, Can you plz help me

  6. 6
    Ritesh Says:

    hello avinash,

    there is a program in your tutorial which counts from 0-999 .i want to interface RS232 in the program (USART) so that I can see the increment from 0 to 999 in hyperterminal . I tried to combined your USART program with that but unscessful….
    can you please help me out

    thanking you
    ritesh kumar

  7. 7
    Nils Says:

    Hello,

    Does anyone has this kind of program for a AVR STK128 board with an ATmega128.

    greetz

  8. 8
    teja Says:

    hello avinash
    nice job avinash, this is the best avr beginers forum i found on internet.
    i have a problem with with an usart implementation.
    i tried implementing an usart code for a quizbuzzer system (used 8mhz internal clk so i used USARTInit(25); ).The hyperterminal displayed junk values(like “..[ “) instead of the chars “1″ “2″ or “3″,when i used ur functions.
    i even implemented the code given above, but the heyperterminal wasn’t accepting any input or displaying any output.
    what could be the fault in this case?
    is there a way i can rectify it?
    i used a pc with vista installed in it and i used a hyperterminal 6.3 version downloaded from the internet(since i couldn’t find hyperterminal on vista)
    thanks
    teja

  9. 9
    percy Says:

    Hello AVANISH
    Now you can see what I have do with atmega_32 in the factory Talaris “Teller Cash Dispenser” there we regulate a motor. All the code is do in CodeVisionAVR. You can se the code and one video (10 minutes) about the project here.

    http://villegastello.weebly.com/talaris_motorreglering.html

    http://video.google.com/videoplaydocid=2332502783057173830

    Why you don’t program in CodeVisionAVR? It is easier you know.

    thanks

    Percy Villegas

  10. 10
    rajat Says:

    hi avinash
    I burned your code on to my atmega16(4 Mhz external) and 4800 baud using avr burnomat with the settings as fuse>>clock options>>external clock>> ceramic, 3 – 8Mhz. however the hyperterminal shows some garbage value whenever i type character….can you help

  11. 11
    fabelizer Says:

    Hi Avinash!

    Nice Tutorials!

    I just tried to build the code in AVR Studio 4, and have a couple of errors due to URSEL. Below is the message screen:

    Build started 31.5.2009 at 22:47:50
    avr-gcc -mmcu=attiny2313 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT RS232.o -MF dep/RS232.o.d -c ../RS232.c
    ../RS232.c: In function ‘USARTInit’:
    ../RS232.c:49: error: ‘URSEL’ undeclared (first use in this function)
    ../RS232.c:49: error: (Each undeclared identifier is reported only once
    ../RS232.c:49: error: for each function it appears in.)
    ../RS232.c: At top level:
    ../RS232.c:95: warning: return type of ‘main’ is not ‘int’
    make: *** [RS232.o] Error 1
    Build failed with 3 errors and 1 warnings…

    Am I missing a library? I never used ‘C’ before, and barely no anything about assembler….but learning!

    Thanks for all your great work!!!!
    -fab

  12. 12
    Avinash Says:

    @fabelizer

    try compiling for ATmega8

  13. 13
    fabelizer Says:

    Will try it. I did go to the tiny3213 data sheet and found there was no such designation. Didn’t have time to check the megas though. I do think that will solve it. Thanks!
    -fab

  14. 14
    gulab Says:

    why 8051 uses standard baud rate of 9600bps????? reply to my mail

  15. 15
    luca Says:

    Hi! all…
    I copied the source code into avr studio and build it with WinAvr..but the program doesn’t work…can somebody send the .hex file to romandini.luca@libero.it?? it is so urgent..
    P.S. I’m using an atmega8 4MHz external clock 9600 boud..

  16. 16
    luca Says:

    Thanks for help!!!

  17. 17
    Jeff Says:

    Hi!
    Any plans to post something using interrupt-driven USART routines?

  18. 18
    Avinash Says:

    @Jeff

    I have the routines ready but I have to create documentation so that I can post it here.

  19. 19
    RF Communication Between Microcontrollers - Part II | eXtreme Electronics Says:

    [...] introduction. You should also be familiar with RS232 communication. If you are new to it please see RS232 Serial Communication Tutorial. I also recommend using wireless link only after you have successfully tried wired RS232 [...]

  20. 20
    Siddharth Dev Says:

    Hello Avinash,

    Again a great tutorial!! But “download a pdf version” tab is missing now..

  21. 21
    Amaury Says:

    Thank you for this tutorial it was really help full I used it in an atmega32p with small tweeks to enable dual USART communications at two different speeds. Interrupt driven usart routines will be also very helpful!. Xon/Xoff flow control is something that it been driving me nuts!, do you know where can i get a sample code? or where can i get a better idea of how to implement it?

  22. 22
    mitul tailor Says:

    i have tried to communicate my bot with pc through uart. i m using avr atmega8.but i m unable to transmit or receive the data. m using 16Mhz crystal.pls rply

  23. 23
    pran Says:

    hi,

    Thank u very much for all the tuts.I tried the above said program but when ever I type a letter in hyperteminal I only get a bunch of 9 C’s
    I dont understand.max232 cirkt is working.I looped it back and saw that working.
    Please reply to me as soon as possible.Your solution is worth to me.

  24. 24
    jig Says:

    hi, really excellent beginner’s tutorial.

    Thanks for the job boss.

  25. 25
    Ray Says:

    How do i test serial communication using windows vista (no hyperterminal with vista).

    regards,

    Ray

  26. 26
    rakesh Says:

    Hello Avinash
    today i compile the code given by you in usart_demo.c but when i press f it give fþ6-
    and with other like that
    c >> f&-
    g >> æf

    can you tell me what is wrong here

  27. 27
    rakesh Says:

    now i change MCU freqency to 12MHz,still error is same but echo back in other symbol.
    what freqency should i used for propare work of this module
    Thanks

  28. 28
    Blimey Says:

    If you have Vista and need a terminal google PuttY… a helpfull tool..

    Skåååll

    Blim

  29. 29
    Avinash Says:

    @Rakesh

    WHY DON’T U USE THE FREQ THAT THE PROGRAM IS DEVELOPED FOR ???????????

    IT IS CLEARLY WRITTEN IN THE PROGRAM.

    WHY ARE U DISTURBING OTHER WITH YOUR VERY SILLY MISTAKE ???

  30. 30
    Shouvik Says:

    hey Avinash..
    congratulations!! Your AVR series of tutorials are among the best that can be found on the internet. Its hard to believe that these tutorials are free of charge. I am doing a project with Atmega32. It uses usart to communicate to a ericsson phone. But the problem is I want pc communication at the same time.As the mobile would take up the usart port how can i implement serial communication for pc?? might be a naive question to ask but I am really confused..

  31. 31
    Avinash Says:

    use a second software usart. if u know how usar works (given in details in one of the tuts) then u can easily implement in software . use it for less data intensive line.

  32. 32
    Shouvik Says:

    hey avinash !!
    Thanx for the quick reply!! you are awesome!! Ya I found out how to use a software UART.Thanks.Cheerz

  33. 33
    Qasim Says:

    plz help me

    i am using avr atmegs 32 and i am communication with pic microcontroller when i send character values like “ATP” it recognize n respond
    and for instance i have to send it data like “0100″ it dosend respond
    i am using functions defined above in this tutorial

    bt when i send 0100 through hyperterminal the pic controller recognize why does not it recognize integer values from my controller plz helo

  34. 34
    fabelizer Says:

    Qasim,

    You are really not sending an integer value, you are actually sending an ascii value. You must use a function such as atoi (ascii to integer) to convert to an integer if that is what you want to use. Check an ascii code table to see what integers the characters are really sending, and be sure your code can respond to them, or convert them.

    -fab

  35. 35
    archerne Says:

    avinash,
    great explanation! I am currently trying to put this on an ATMega128 board, and it is complaining about alot of things. I fixed alot of them by finding that the board this code was made for has 1 usart, while the one i am using has 2. however i think i got that working, now it is just complaining about the URSEL. any ideas?

  36. 36
    zahid Says:

    hi
    the above code is working fine on Atmega32 and 16 but not on attiny2313.I have changed the statement

    UCSRC=(1<<URSEL)|(3<<UCSZ0);
    to
    UCSRC = (1 << UCSZ1) | (1 << UCSZ0);
    pls help…………

Leave a Reply

Comments

    • Del Chann: Hello is it possible to use this board to interface with a smoke sensor, motion sensor,...
    • Elijah Nicolia: May I consider part regarding your main guide to my personal site
    • Tifany Wiebusch: I go along with you actually, I believe! Might this become doable for you to have...
    • Sinopteek: When i try to run this software under OpenSuSe 11.2 (x64), i’ll have next error:...
    • kapil: @Dhananjay I used that its working and it can programme 3 to 4 times after that there is a...
    • Dhananjay: Sir, At present I am using progisp to flash AT89SXX with usbasp(with modified firmware)....
    • Shashi Jain: plz dont fight wid each other…k i accept my fault… neway m not a rich person...

Video