Using the USART/serial [tutorial part 2]

Hello again, today I will continue with my tutorial series and I write a bit about the USART(or UART in other avr models), the USART give us the possibility to have a serial port, and that is a pretty nice thing to have, because it can be used for example to upload programs to our Arduino(via bootloader), to have a communication channel between our micro-controller and our computer, or to talk to some sensors/chips, the most used ones are serial backpacks for lcd’s and graphical lcd’s and GPS modules that use almost always an serial interface.
The serial protocol is a fairly old protocol created many years ago it was used by Teletypes and terminals, its also a robust protocol(at least when we use the RS-232 standard that involves +12v and -12v or more so its immune to noise and can cope with long transmission lines), the serial protocol uses 2 wires, one to receive data and other to send data, and of course you must have a shared ground between your arduino/micro-controller and the other device. The serial interface sends the data in little blocks of one byte with one start bit and one stop bit, the USART does all the job about the setting of the start and stop bits. The clock signal of the serial protocol is implicit, this means that is is “joined” with the data stream and there is no need to have a separate wire to transmit the clock from one device to another, we only need to say to the USART which clock speed we want to use(this is the baud rate) and again the USART module will do all the heavy lifting.

If you want to know a bit more about the RS-232 protocol read this Wikipedia page, its also good to know a bit more about the protocol, but not mandatory:

http://en.wikipedia.org/wiki/RS-232

Also, its always good to have the datasheet of the atmega328p in hand as it as all the information that we will need, link here:

http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf

And we can also create a small stub program, this will be our base program that we use every time that we start a new project in AvrStudio, it as the basic includes and the main function:

#define F_CPU 16000000UL        //Says to the compiler which is our clock frequency, permits the delay functions to be very accurate
#include <avr/io.h>            /General definitions of the registers values
#include <util/delay.h>            //This is where the delay functions are located

int main(void){                //The begin of our main function
 //This is where our code goes

return 0;                //As usual all non-void functions must have a return
}

This is a little but handy stub and it also saves us the time to write is every time we start a new project.

Now talking specifically about the USART module and how to create a program to use it. In this tutorial instead of just putting all the code together in the main function I will instead create some basic functions, so if you want to use serial comm in another project you just have to copy the functions and call then where they are needed.
So, in pseudo-code this is what we need to do:

Start and setup of the USART
Create a function to send a byte/char
Create a function to receive a byte/char
Make a simple echo program in our main function

Now we know what we want to do, but how? Well we open the datasheet and we start to read it, luckily the datasheet is ordered by chapters so we can jump to the USART chapter(page 177, section 19) and there we can see that there is even some sample code in C and assembly so our work here is a bit easier than we though, so lets start with the initialization code:

void USART_init(void){

 UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
 UBRR0L = (uint8_t)(BAUD_PRESCALLER);
 UCSR0B = (1<<RXEN0)|(1<<TXEN0);
 UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01));
}

Lets explain what all those strange names mean, UBRR0H and UBRR0L are the registers where we set the baudrate, but not directly, in this two registers we put a value that is dependent of the baudrate that we want to use(for example 9600) and the cpu(crystal) frequency, and to arrive to that value there are two ways, one is to read the tables provided by the datasheet(in the USART section, near the end) or use the little formula that was used to generate those values present in the datasheet, the last option is better, because we can just use the #define directive and have the compiler do all the maths, and we can just change the baudrate and re-compile the code, so we don’t have to go read the datasheet everytime we want to change the baudrate or if we use a different cristal with different frequency than the 16Mhz, so here is the formula:

]#define BAUD 9600        //The baudrate that we want to use
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)    //The formula that does all the required maths

Now about the UCSR0B is the register that control if the Rx(receive, this is the one activated by the RXEN0 bit) and Tx(transmit/send, this is the one activated by the TXEN0 bit) pins(in Arduino those are the digital 0 and 1) are activated or not, also this is where we can enable the interrupts associated with the USART, but we will not use those for now. And the UCSR0C is the register that as some more configuration bits, this one is a bit more protocol specific, this is where we configure the data bits lenght, parity check and number of stop bits, I have chosen the 8N1 settings because its the most common settings for serial comm, and the meaning of the UCSZ00 and UCZS01 bits I leave to the reader as a simple exercise to motive the reading of the datasheet.

To initialize our USART we just need to call the USART_init() function and its done(I said it was easy). Lets see the code that we need to use to send one char from the Arduino, this code is again provided by the datasheet, and here it is:

void USART_send( unsigned char data){

 while(!(UCSR0A & (1<<UDRE0)));
 UDR0 = data;

}

The first line is a bit odd, but it as its reasons, that line is checking if there is space in the Atmega send buffer(the atmega chip as a small 3 byte hardware buffer in the TX/send channel) to put a new char/byte, if yes the char/byte is loaded into the UDR0 register which makes part of the USART hardware and if something is loaded into that register it will be sent by the USART, again this is very simple, with only 2 lines we can already send data using the serial port!
And finally the function used to receive one char is also present in the datasheet and is again a two lines solution:

unsigned char USART_receive(void){

 while(!(UCSR0A & (1<<RXC0)));
 return UDR0;

}

In the first line the while loop is used to pool the receive register, and if there is new data in that register we return the data, as you can see its pretty simple. As an extra not shown in the datasheet I will show how to send one string via the serial comm, this is a useful function because there are plenty of situations where we need to send much more than one byte/char so lets build an USART_putstring function to help us, this functions takes advantage of the fact that in C every string is terminated with a null character, this means that the last char is always 0, so using this and our USART_send function here is the USART_putstring function:

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){    //Here we check if there is still more chars to send, this is done checking the actual char and see if it is different from the null char
 USART_send(*StringPtr);    //Using the simple send function we send one char at a time
 StringPtr++;}        //We increment the pointer so we can read the next char

}

Now we have all the necessary functions to have a simple yet usable serial interface between the Arduino and a computer or other sensor, so lets evolve to a more glorious “Hello world!!” program, the only thing left is a Serial Terminal so we can see what the Arduino is saying and we can also send it some commands, I recommend this simple to use Serial Terminal:

http://www.smileymicros.com/download/term20040714.zip?&MMN_position=42:42

As far as I know it is made by an AvrFreaks member and its easy to use and its only a single file, no install required, just download and open.
Lets grab in our stub code and our functions and pu then all together:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

//Declaration of our functions
void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr);

char String[]="Hello world!!";    //String[] is in fact an array but when we put the text between the " " symbols the compiler threats it as a String and automatically puts the null termination character in the end of the text

int main(void){
USART_init();        //Call the USART initialization code

while(1){        //Infinite loop
 USART_putstring(String);    //Pass the string to the USART_putstring function and sends it over the serial
 _delay_ms(5000);        //Delay for 5 seconds so it will re-send the string every 5 seconds
 }

return 0;
}

void USART_init(void){

 UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
 UBRR0L = (uint8_t)(BAUD_PRESCALLER);
 UCSR0B = (1<<RXEN0)|(1<<TXEN0);
 UCSR0C = (3<<UCSZ00);
}

unsigned char USART_receive(void){

 while(!(UCSR0A & (1<<RXC0)));
 return UDR0;

}

void USART_send( unsigned char data){

 while(!(UCSR0A & (1<<UDRE0)));
 UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
 USART_send(*StringPtr);
 StringPtr++;}

}

And that’s it, using this we can send data via the USART/serial port, so lets open AvrStudio and create a new project called USART.

Then in the next window we can verify that the project will be created inside our AVR folder, so just fill the Project Name with USART and font forget to choose the Avr-gcc as the compiler.

After pressing Next choose your Avr model, for the Arduino UNO/duemilanove its Atmega328p.

And finally press Finish and copy and paste the code given here to the editor, and to compile you can press F7 or click in the button marked in green in this image:

As you can see this code will compile with any errors or warnings and we can open the Command line to upload the program to the Arduino board, if you don’t remember how its done just go to the first tutorial and see again how its done, but this time the folder is called USART and not blinky, then go again to the default folder that is inside the USART folder, the default folder is where the compiler puts its file, including the .hex file which is the one that as the code compiled and ready to be programmed in the Arduino.

Now lets just call the avrdude and again check the .hex name and make sure you are using the correct COM port.

With the upload done we can now open our Terminal program, and again you need to choose the correct COM port, it will be the same as the one used in the avrdude, and lets configure the Terminal so it can listen to our Arduino, the baudrate is 9600, 8 data bits, 1 stop bit and no parity, see this image:

You just need to press the Connect button and press the Reset button in your Arduino so the Terminal can sync with the serial stream that is coming from the Arduino and you should see something like this:

And you are done, just remember one thing, if you have the Terminal connected you cant send any programs to the Arduino using the Avrdude, you must first disconnect and then send the program.

And here is the code ready to open in Avr Studio 4, hosted by the great Google Code:

http://code.google.com/p/avr-tutorials/downloads/detail?name=serial.zip

Happy programming!!

About these ads

37 responses to “Using the USART/serial [tutorial part 2]

  1. Thanks man. That’s what I´ve looking for. Exactly the information I need to fulfill my job. Obrigado e saudações do Brasil.

  2. Ups, only saw this now.
    Se quiseres em portugues, tenho os meus tutoriais tambem em portugues no site forum LusoRobótica, e lá estão um pouco mais avançados que aqui no blog.
    Eis o link:
    http://lusorobotica.com/index.php?topic=2838.0
    Claro que pode mandar as fotos, ainda bem que os tutoriais o ajudaram, passe pelo lusorobótica, que lá já falei tambem sobre timers e o conversor adc, tenho de acabar o tutorial sobre spi e pwm.

  3. Thanks a lot for this tutorial, the code above is working in a great way, but it does not work when I use the receive function, any idea why?

  4. Sorry, it is working now, I had something wrong with my hyper terminal

  5. Thank you so much!!! I am new to AVR programming, and was searching for days on the internet for an USART example that worked. Thank you, thank you, Thank You!! :-)

  6. Hi,
    I’m getting the not in sync error even after pressing the reset button.
    I assume the reset button is the “reset counter” button present on terminal under receive menu option.
    Pls. help.

  7. I have to double my baud rate in the terminal to get it working (to 19200)

    Does anybody know why? My code is at 9600.

    • The baud-rate values must be equal in both the micro-controller and the terminal, if you want to use the serial coms at 19200 change the value in the #define and recompile the code.

      • To clarify,

        When I have my baud rate at 9600 in my project, and 9600 in the terminal I get symbols displayed instead of Hello World!

        However, if I compile my project with 9600 and set my terminal to 19200 I get “Hello World!” displayed correctly.

        Weird??

      • Are you using the correct 8 data bits, 1 stop bit and no parity?
        It looks like you have a slower crystal in your board or you are not setting the F_CPU to 16000000Mhz, but yes its really strange, just to make sure, make a clean all before building I think the hotkey to do that is F11.

  8. Yeah, I’m using all the correct settings as shown in your figure.

    When I look at the data sheet for the atmega328p however… the frequency is said to be 20MHz.

    Do you know if setting it to 16MHz is messing it up?

    Thanks!

    • Goodnight, that 20Mhz is the maximum frequency that the chip can run inside specs, but what determines the frequency is the cristal that is attached to the chip, and in all the Arduino boards that is an 16Mhz crystal or an oscillator in the most recent UNO’s.

      So, what is your board in fact, so I can help you in a better way?

  9. Valentin Ramirez (Madrid Spain)

    Thanks for share your efforts…!
    I am trying to use your code to send text (and bytes, later…) from Arduino Uno to a “Processing” aplication.
    (Processing has very similar IDE to Arduino, but it is intended to computers), but Proccessing does not understand the received data.
    If I use the “Serial” library of arduino IDE to send data, it works properly, but I prefer use AVR IDE, so, my question is: Did you test the code with Proccessing?
    Do you know if they use different configuration??

    Thanks in advance….

    Valentin
    Madrid
    Spain

    • Hello Valentin,
      Yes I have used my code to send and receive data from processing and it working without any problems, are you setting the right baud-rate values in processing?

      • Valentin Ramirez (Madrid Spain)

        Hello hekilledmywire, I think so….
        println(Serial.list());
        // my Arduino is in COM7, so i open Serial.list()[2].
        myPort = new Serial(this, Serial.list()[2], 9600);
        If the Proccessing code is working in your machine, this is a very good news. I am going to test it in other computer….
        Now I am using Windows XP, and the other computer uses Windows 7.

  10. Valentin Ramirez (Madrid Spain)

    Hi,
    after reading the atmega328P datasheet, etc. I have modified the init function, to use it with my Arduino Uno:

    #define BAUDRATE 9600
    #define F_CPU 16000000UL
    #define setbit(port, bit) (port) |= (1 << (bit))
    #define clearbit(port, bit) (port) &= ~(1 <>8;
    UBRR0L = (uint8_t)baud_setting;
    setbit(UCSR0B, RXEN0);
    setbit(UCSR0B, TXEN0);
    setbit(UCSR0B, RXCIE0);
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
    UCSR0C = (3<<UCSZ00);
    }

    and now is running….!

  11. Valentin Ramirez (Madrid Spain)

    The code wich I have sent does not look good ..! this not my code….

  12. Thanks for the tutorial as it really helps clear things up.
    I am having trouble getting this working correctly. I’m using a 4MHz crystal and an ATMEGA48P, which has the same registers and values as the 328P. I copied and pasted your code EXACTLY how you have it, changing only the baud rate (38400) and F_CPU to match my frequency.

    #define F_CPU 4000000UL
    #include
    #include
    #define BAUDRATE 38400
    #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL)))-1)

    That is all I have changed in your code. I am using the same terminal program you mention in the tutorial, I set my baud rate for 38400, and set the others to
    8,N,1 and all I get is garbage on the terminal screen. I’ve tried changing the baud rate and reconnecting just to see, but nothing works.

    Is there anything else I could be checking?

    Thanks!!

  13. ignore the two empty “include” statements in my post above. those are avr/io and util/delay but for some reason they did not post correctly. they are correct in my code though.

    • Are you sure that you are running from the external cristal and not from the internal RC oscillator?
      Other thing, have you turned off the ckdiv8 fuse that divides the clock source by 8?
      I have looked up the datasheet and you need to enable the U2X0 register to be able to use that baud rate value using the 4Mhz clock, because using my code the baud error is 7% and thus it will not work.

  14. When I compile I get Error: conflicting types for ‘USART_receive’
    I assign like this: eceivedByte = USART_receive();
    and unsigned char ReceivedByte; is how I designate
    Any ideas???

  15. Hi! It`s great tutorial, but You show how to send “hello world” string and receive function only for char. How to recieve a string like “hello world” (unknown sized) from USART?

  16. Treehouse Projects

    Many thanks!

  17. Awesome Tutorial, many many thanks! I’m new to C programming in avr studio, and when I found your blog, I was like “Perfect!!”
    Keep up the excellent work!

  18. This is great! Thanks so much!

  19. i know this is stupid question, but where can i find that datasheet to atmega328p-pu? I just found on google some datasheets in whitch arent code examples and explained thing about usart etc. There are just some tables with registers. But i want “complete” datasheet with explanation and code examples.

  20. I want to get the data sent by the microcontroller to a c program running in my pc. i want to use the data sent by the UC in my c program. I have an arduino board which is connected to my pc using a usb drive

    could you guide me through codes and connection required

  21. Great blog, there’s an interessting thing I’ve found on an german homepage it’s about the value of BAUD_PRESCALLER. They added half of the divisor because if you have for example 29/30 you only get 2 because the rest isn’t seen as an integer but if you add 0.5 it’s like smart rounding ;)

  22. Hi, you from Brazil? I see you code in portuguese.

    Você pode me dá umas dicas de AVR? Sou de pernambuco

    uni.brunoead@hotmail.com

  23. Thank’s for this nice tuto… I try to use it to make the reive part but but I have some strange behaviour I want to share
    ************************partr of the code :
    while(1)
    {
    USART_Send_string(“send Test n= “);
    USART_Send_int(n) ;
    USART_Send_string(” \n”);

    UC = USART_Receive();
    if (UC != ’0′)
    {
    USART_Send_string(“Received Test “);
    USART_Send_byte(UC);
    USART_Send_string(” \n”);
    UC = ’0′ ;
    }
    n++ ;
    ….
    ************the output after having send a and b
    send Test n= 0
    Received Test a <————– I send a
    send Test n= 1
    Received Test

    send Test n= 2
    Received Test

    send Test n= 3 <———– it stops for a while
    Received Test b <————- I the send b
    send Test n= 4
    Received Test

    send Test n= 5
    Received Test

    send Test n= 6 <—————— it stops again

    ****** have you any clue what's going on
    Thank you for some reply

  24. while using aTmega 16 whats the code.

  25. Hello! I am defining my F_CPU as 8000000UL and loading 51 (0r 0×33) into UBRRL to set my baud rate as 9600. When i tested my code to transmit a simple character ‘a’ serially i can see the proper output on Proteus. But when tried it on the hardware, i can nothing on the hyperterminal. Is there anything i could possibly be doing wrong?
    much thanks!

  26. the controller i am using is atmega 16. also when i changed the hyperterminal baud rate to 2400 i can see some special character being transmitted instead of ‘a’

  27. Hi, i am using an Atmega32A chip, my external crystal is of 11.0592Mhz. So for my external crystal i changed my fusebits to hfuse=89 lfuse=DE. But when i try to load the flas using ProgISP i am getting a chip enable error(I have recovered though). But why am I getting this error? what shoud i change to access my external crystal on board to get a correcct frequency?? pls help. :(

  28. The problem with the BAUD rate setting might be bit-1 (“U2X0″) in the UCSR0A register. If set, it will double your baud rate. Try adding this line to the USART_init function:

    UCSR0A = 0;

    Perhaps your code download app is setting this bit and not clearing it after use.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s