megaAVR® USART Example (Polled)

Last modified by Microchip on 2023/11/10 11:09

Objective

This page provides a simple project demonstrating polled operation of the Universal Synchronous Asynchronous Receiver Transmitter (USART) peripheral on megaAVR® devices. The code example runs on the ATmega328PB MCU.

The project configures the Timer/Counter1 module to operate in Clear-Timer-On-Compare (CTC) mode, and, on a period match, generates a tick interrupt every 100 mS. The main loop monitors these tick signals to implement a time-of-day clock (HH:MM:SS format). LED0 is also toggled at every tick event.

The clock display is sent out USART0 TX every second and is controlled by user input 'control' characters received on USART0 RX:

  • 'u' enables updates to the clock display every second
  • 'f' freezes updates to the display

The clock interface is displayed using a Terminal Emulator program, such as Tera Term.

Reference Materials

ATMEGA328PB Xplained Mini

Microchip Studio

Tera Term

Project Files

We recommend extracting the .zip file to your C:\ folder.

You should see the folder C:\MTT\8avr\mega\code-examples\usart-example-polled\8avr-mega-usart-example-polled containing the solution 8avr-mega-usart-example-polled.atsln here.

Connection Diagram

The USART0 module on the target ATmega328PB device is connected to the USART interface on the mEDBG chip. The mEDBG chip performs USB-serial conversion by enumerating as a CDC-class virtual COM port on the PC and presenting the target USART data on this interface. Note that the mEDBG also controls the programming/debug interface, as well as supplying a 16 MHz clock when the Xplained board is connected via USB cable to a PC.

Connection Diagram

Back to Top

Procedure

Attach the ATmega328PB Xplained Mini board:

Using a USB-A-male-to-Micro-B-male cable, attached the Xplained Mini to your computer. Start MPLAB X IDE. If the board has been successfully enumerated, you should see the board image come up in Studio as shown in the accompanying image:

MPLAB X IDE​​

Back to Top


Create a New Project 

In MPLAB X IDE, select File > New Project.

New Project Dialog Box

Back to Top


Choose Project 

Select Microchip Embedded and then Standalone Project and then select Next.

Standalone Project selection

Back to Top


Select Device

Use the pulldown or type into the boxes to indicate the Family,  ATmega328PB, and Tool. Then Select Next.

Device Selection Dialog

Back to Top


Select Compiler

Select the XC8 Compiler and then Next.

Compiler Selection Dialog

Back to Top


Name the Project

Choose a name for the project, browse to a location to save it, and select Finish.

Project Name Dialog Box

Back to Top


Create a New main.c file

Right-click on Source Files in the file explorer window and select New>avr-main.c and rename the File Name to main.  Then select Finish.

New mail.c dialog box

Back to Top


Add the Code

Delete the contents of the newly created main.c file. Copy and Paste the following code into it.

/*******************************************************************************
 * File:  main.c
 *
 * Project:  8avr-mega-usart-example-polled
 *
 * Description: Demonstrate basic polled usart configuration/usage
 *    
 *    100mS Timer1 ISR is used to create tick events.
 *
 *    Main loop monitors tick events to toggle the LED and track time.
 *    
 *    Elapsed time (HH:MM:SS) is output to a terminal via USART0 once
 *    every second. "u" command updates the clock display, "f" command
 *    freezes the clock display (time is still incremented).
 *
 * Date:  08-June-2017
 * Revision:
 * Author:
 *
 * Hardware: ATmega328PB Xplained Mini PCB Rev 3
 *
 *    Clock:  16MHz (External - from EDBG IC)
 *    LED0:  PB5
 *    SW0:  PB7
 *    UART_TX: TXD/PD1 (Connected to EDBG IC RXD)
 *    UART_RX: RXD/PD0 (Connected to EDBG IC TXD)
 *
 * Fuses:  High:  0xDF
 *    Low:  0xC0
 *    Ext:  0xFC
 ******************************************************************************/


/*** MACROS *******************************************************************/

#define F_CPU 16000000UL   // required for setbaud & other libraries
#define BAUD 38400UL    // desired baud
#define BAUD_TOL 2     // desired baud rate tolerance (+/- %)

/*** INCLUDES *****************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <avr/io.h>     // SFR/Bit identifiers
#include <avr/interrupt.h>   // ISR macro
#include <util/setbaud.h>   // Baud rate calculation macro helpers

/*** GLOBAL VARIABLES *********************************************************/

char g_OutString[80];    // output buffer used with sprintf
volatile uint8_t g_TickSignal = 0; // define shared variable used for signaling
uint8_t g_Hours, g_Minutes, g_Seconds, g_Tenths; // time variables
enum TIMEOUTPUT {DISABLED, ENABLED} g_TimeControl; // control for time output
char g_Command;      // control character to enable/disable output    

/*** LOCAL FUNCTION PROTOTYPES ************************************************/

void SYSTEM_Init(void);    // Initialize HW and variables
void TIMER1_Init(void);    // Timer/Counter1 initialization
void USART0_Init(void);    // USART0 initialization
void USART0_Put(uint8_t data);  // Transmit a byte
void USART0_PutString(char *ptr); // Transmit a string
char USART0_GetChar(void);   // Receive a character (if available)    

/*** main() *******************************************************************/

int main(void)
{
   // Initialization
SYSTEM_Init()

// Enable global interrupts
sei();                    

   USART0_PutString("megaAVR USART0 Example (Polled)\r\n\r\n");
USART0_PutString("Press 'u' to update the clock display,\r\n");
USART0_PutString("Press 'f' to freeze the clock display.\r\n\r\n");
sprintf(g_OutString, "%02d:%02d:%02d\r", g_Hours, g_Minutes, g_Seconds);
USART0_PutString(g_OutString);

while(1){
 
 // Look for 100mS event signal
 if(g_TickSignal){
  
  // Toggle LED0
  PORTB ^= (1 << PORTB5)
  
  // Update the clock
  g_Tenths++;
  if(g_Tenths == 10){
   g_Tenths = 0;  
   if(g_TimeControl == ENABLED){
    sprintf(g_OutString, "%02d:%02d:%02d\r", g_Hours, g_Minutes, g_Seconds);
    USART0_PutString(g_OutString);
    }
   g_Seconds++;
   if(g_Seconds == 60){
    g_Seconds = 0;
    g_Minutes++;
    }
   if(g_Minutes == 60){
    g_Minutes = 0;
    g_Hours++;
    }  
   }
  
  // Acknowledge event signal
  g_TickSignal = 0;
  }
 
 // Look to enable/disable the updating of the clock output
 g_Command = USART0_GetChar();
 switch(g_Command){
  case 'u':
   g_TimeControl = ENABLED;
   break;
  
  case 'f':
   g_TimeControl = DISABLED;
   break;
  
  default:
   break;
  }
 }
} // main()

/*** SYSTEM_Init() ****************************************************************/

void SYSTEM_Init(void){

// Set LED as output
DDRB |= (1<<PORTB5);   // Configure PB5 as digital output
PORTB &= ~(1<<PORTB5);   // Set initial level for PB5

// Timer1
TIMER1_Init();

// USART0
USART0_Init();

// Initialize global variables
g_Hours = 0;
g_Minutes = 0;
g_Seconds = 0;
g_Tenths = 0;

} // SYSTEM_Init()

/*** TIMER1_Init() *************************************************************/

void TIMER1_Init(void){

// Set up Timer/Counter1
TCCR1B |= (1 << WGM12);   // Configure timer 1 for CTC mode
OCR1A = 25000;     // Set CTC compare value to 10Hz (100mS) at
        // 16MHz AVR clock , with a prescaler of 64
TIMSK1 |= (1 << OCIE1A);  // Enable CTC interrupt
TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start Timer/Counter1 at F_CPU/64

} // TIMER1_Init()

/*** USART0_Init() *************************************************************/

void USART0_Init(void){

// Set the BAUD rate
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
 #if USE_2X     // USE_2X defined by setbaud.h based on inputs
UCSR0A |= (1 << U2X0);
 #else
UCSR0A &= ~(1 << U2X0);
 #endif

// Set the Mode & Frame Parameters
// Asynchronous, 8-data, No parity, 1 stop
UCSR0C = 0x06;

// Enable USART0 Transmitter and Receiver
UCSR0B = (1 << TXEN0) | (1 << RXEN0);

} // USART0_Init()

/*** USART0_Put() **************************************************************/

void USART0_Put(uint8_t data){

//Checking to see if USART TX buffer is empty for new data
while(!(UCSR0A & (1<<UDRE0)));

//Initiating transfer
UDR0 = data;

} // USART0_Put()

/*** USART0_PutString() ********************************************************/

void USART0_PutString(char *ptr){

while(*ptr){   // Loop until end of string (*s = '\0')
 USART0_Put(*ptr++); // Send the character and point to the next one
 }

} // USART0_PutString()

/*** USART0_GetChar() **************************************************************/

char USART0_GetChar(void){

char rxdata;

if(UCSR0A & (1<<RXC0)){  // checking if USART RX data is available
 rxdata = UDR0;   // reading the received byte (clears RXC0)
 return rxdata;   // return the data
 }

return 0x00;    // return NUL char ('/0') if no data available

} // USART0_GetChar()

/*** Interrupt Handler for TIMER1_COMPA Interrupt (Nesting Disabled) **********/

ISR(TIMER1_COMPA_vect, ISR_BLOCK)
{
g_TickSignal++;     // signal "tick" event
        // Timer1 CTC flag auto-cleared by hardware
}

/*******************************************************************************

SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP TECHNOLOGY INC OR ITS LICENSORS BE LIABLE OR
OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF
WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR
EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT,
PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD
PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR
COSTS.

*******************************************************************************/

Back to Top


Program the Device

At the top of the MPLAB X IDE, select the Make and Program device button

Program the Device​​​

There are several key hardware configuration settings that need to be configured. The following fuse settings need to be programmed into the device:

  • HIGH: 0xDF
  • LOW: 0xC0
  • EXT: 0xFC

While still in the Device Programming dialog box, select the Memories sub-section as shown. The path to the solution's hex file should already be listed in the dialog. Press Program as shown.

Back to Top


Start the Tera Term application

Select the correct mEDBG COM port in the dialog box that appears:

Tera Term New Connection​​​​

Back to Top


Set the serial port parameters to match the project defaults

38400 baud, 8-data, no parity, 1-stop, no flow-control as shown:

Tera Term Serial port Setup​​​​

Back to Top


Observe the Results

Tera Term COM4 Window​​​​

​You may see gibberish on the display after resetting the communication parameters. Simply perform a board reset by shorting RST to GND, or by re-programming the hex file into the board again (see step 4 above).

Back to Top

Conclusions

This project has provided an example of how to setup and use the USART module on the megaAVR® MCU.

Back to Top

Learn More

megaAVR® USART Overview
megaAVR® USART Configuration
 

Back to Top