Pages

Thursday 19 March 2015

Programming With AVR Microcontroller: Chapter 4

SERIAL COMMUNICATION:

What is the USART?

The vast majority of devices in the current AVR family lineup contain a USART hardware subsystem. The USART hardware allows the AVR to transmit and receive data serially to and from other devices - such as a computer or another AVR.


The USART transmission system differs to most other digital busses in that it does not utilize a separate pin for the serial clock. An agreed clock rate is preset into both devices, which is then used to sample the Rx/Tx lines at regular intervals. Because of this, the USART requires only three wires for bi-directional communication (Rx, Tx and GND).

Setting up the Hardware


  • Connect your USART to a computer via the Com port.
  • You need to first identify which pins of your AVR(ATmega 16) are responsible for serial communication.
  • For ATmega 16 Pin 14 and Pin 15 are used for receiving and transmission.
  • Connect tx pin of usart to rx pin of ATmega 16 and rx pin of usart to the tx pin of the ATmega 16 .
  • Now to see the transmitted word back in pc you need to use HyperTerminal  (it’s a free software you need to download it)
  • set the Baud rate in the HyperTerminal
Setting up HyperTerminal
  1. open the HyperTerminal



2.Add name here I have added serial

    

3.Select your com port which you are using and press ok (to check the com port go to device manger and check in which com port is the usart connected)         















4.select the baud rate that you have set or just click Restore default it will set the default valve  and press ok

  
5.serial HyperTerminal will get open 



 

Initializing the USART
        

First off, you need to enable both the USART's transmission and reception circuitry. For the MEGA16, these are bits named RXEN and TXEN, and they are located in the control register UCSRB. When set, these two bits turn on the serial buffers to allow for serial communications

    Code:



int main (void)
{
UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
}

 Next, we need to tell the AVR what type of serial format we're using. Looking again at the MEGA16 datasheet, we can see that the bits responsible for the serial format are named UCSZ0 to UCSZ2, and are located in the USART control register C named UCSRC.

    Code:


UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes - URSEL bit set to select the UCRSC register

 
    The last thing to set for basic serial communications is the baud rate register. The baud rate register is 16-bit, split into two 8-bit registers as is the case with all 16-bit registers in the AVR device family. For this the baud valve need to be found for that we have a formula



BaudValue = (((F_CPU / (USART_BAUDRATE * 16))) - 1)
Where F_CPU is your AVR's system clock frequency (in Hz), and USART_BAUDRATE is the desired communication baud rate.
Given my example project using a system clock of 7372800Hz and a baud rate of 9600, our formula gives:

BaudValue = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) BaudValue = (7372800 / (9600 * 16) - 1)
BaudValue = (7372800 / 153600 - 1)
BaudValue = (48 - 1)
BaudValue = 47
    This avoids "magic numbers" (unexplained constants) in our source code, and makes changing the baud rate later on very easy - just change the BAUD_RATE macro value. Now, we need to load this into the baud rate registers, named UBRRH (for the high byte) and UBRRL (for the low byte). This is simple via a simple bit shift to grab the upper eight bits of the BAUD_PRESCALE constant: 

UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register


Sending and receiving data
    We do this by the special register named UDR - short for "USART I/O Data Register”. On the MEGA16, the Transmission Complete flag is located in the control register UCSRA, and it is named TXC. Using this information we can construct a simple wait loop which will prevent data from being written to the UDR register until the current transmission is complete.



UDR = ByteToSend; // Send out the byte value in the variable "ByteToSend"
while ((UCSRA & (1 << TXC)) == 0) {}; // Do nothing until transmission complete flag set
 
    However this is non-optimal. We spend time waiting after each byte which could be better spent performing other tasks - better to check before a transmission to see if the UDR register is ready for data. We can do this by checking the USART Data Register Empty flag instead (called UDRE), also located in the UCSRA control register of the MEGA16
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ByteToSend; // Send out the byte value in the variable "ByteToSend"


    Now we can move on to receiving data. we need to check to see if we have received a byte.
To do this, we can check the USART Receive Complete (RXC) flag to see if it is set. Again, this is located in the UCSRA control register of the MEGA16:


while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ReceivedByte"


CODE:

#include <avr/io.h>
#include <avr/delay.h>
#define    F_CPU ((unsigned long)8000000)
#define F_OSC 8000000// for 8mhz


#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / ( USART_BAUDRATE * 16UL))) - 1)

unsigned char

int main (void)
{
    char ReceivedByte;

    UCSRB = (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes

    UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

    for (;;) // Loop forever
    {
        while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR; // Fetch the received byte value into the variable                                          "ByteReceived"
        //_delay_ms(1000);

        while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte; // Echo back the received byte back to the computer
    }
}




Related Products: 

Atmega 16/32/64 Project Board                                      
                                                                                  

      
                                                               Product Code: G89S52     

Atmega 16/32/64 Development Board-USB 
                
                                                     Product Code: ATM-U

Atmega Programmer-USB  
         
                                                             Product Code: AVR     

ISP Atmel Programmer 

   

                                                       Product Code: UAB