Splitting Functions Into USART.h and .c Files

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

In This Video

  • Reference Tutorial on "AVR® Freaks: Modularizing C Code: Managing Large Projects (by Dean Camera)"
  • Grey out code that will not compile as part of your project (e.g. through #IFDEF), using Naggy (Available from the extension manager)
  • Move defines and function prototypes, used in relation to the USART, to a header file: USART_irq.h.
  • Move USART functions and variables to USART_irq.c.
  • Use of the Extern keyword is highlighted for global variables.
  • Add include files.
  • Add USART_irq.h to both main.c and USART_irq.h.

Back to Top

Procedure

Identify Code Sections

Identify these parts of your code

  • #defines
  • #includes
  • Function Definitions
  • Functions
  • Variables

Create a New Header File

New Header File​​

Name this new header file  USART_irq.h and then select Finish. 


Clean up the Newly Created File

The new file will have some content in it but it is not needed in our application.  Delete everything below the #include <xc.h> line. 


Populate the New Header File

Copy/Paste the #defines and Function definitions into this file. 

Your file should look similar to this...

// This is a guard condition so that contents of this file are not included
// more than once.  
#ifndef XC_HEADER_TEMPLATE_H
#define XC_HEADER_TEMPLATE_H

#include <xc.h> // include processor files - each processor file is guarded.  

#define F_CPU 16000000UL // Clock Speed
#define BAUD 9600
#define MYUBRR ((F_CPU / (BAUD * 16UL)) - 1)

/* USART Buffer Defines */
#define USART_RX_BUFFER_SIZE 128     /* 2,4,8,16,32,64,128 or 256 bytes */
#define USART_TX_BUFFER_SIZE 128     
/* 2,4,8,16,32,64,128 or 256 bytes */
#define USART_RX_BUFFER_MASK (USART_RX_BUFFER_SIZE - 1)
#define USART_TX_BUFFER_MASK (USART_TX_BUFFER_SIZE - 1)

/* Prototypes */
void USART0_Init(unsigned int baudrate);
unsigned char USART0_Receive(void);
void USART0_Transmit(unsigned char data);

Create a new .c file

This new .c file will contain the variables and the Functions themselves.  We also need to add in the #includes from the top of the main and the newly created header file.  We will also call this file USART_irq except it will have a different file extension.  It should look similar to the following:

 "USART_irq.h" is in quotes because it is stored in the projects directory

#include <avr/io.h>
#include
<avr/interrupt.h>
#include
"USART_irq.h"


/* Static Variables */
static unsigned char USART_RxBuf[USART_RX_BUFFER_SIZE];
static volatile unsigned char USART_RxHead;
static volatile unsigned char USART_RxTail;
static unsigned char USART_TxBuf[USART_TX_BUFFER_SIZE];
static volatile unsigned char USART_TxHead;
static volatile unsigned char USART_TxTail;

/* Initialize USART */
void USART0_Init(unsigned int baudrate)
{
unsigned char x;

/* Set the baud rate */
 UBRR0H = (unsigned char) (baudrate>>8);                  
 UBRR0L = (unsigned char) baudrate;

/* Enable USART receiver and transmitter */
 UCSR0B = ((1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0));

/* For devices in which UBRRH/UCSRC shares the same location
 * eg; ATmega16, URSEL should be written to 1 when writing UCSRC
 *
 */

/* Set frame format: 8 data 2stop */
 UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //CHANGED ADDRESS and 1 stop bit

/* Flush receive buffer */
 x = 0;        

 USART_RxTail = x;
 USART_RxHead = x;
 USART_TxTail = x;
 USART_TxHead = x;
}


ISR(USART0_RX_vect)  //CHANGE ISR
{
unsigned char data;
unsigned char tmphead;

/* Read the received data */
 data = UDR0;                 
/* Calculate buffer index */
 tmphead = (USART_RxHead + 1) & USART_RX_BUFFER_MASK;
/* Store new index */
 USART_RxHead = tmphead;

if (tmphead == USART_RxTail) {
 /* ERROR! Receive buffer overflow */
 }
/* Store received data in buffer */
 USART_RxBuf[tmphead] = data;
}


ISR(USART0_UDRE_vect)
{
unsigned char tmptail;

/* Check if all data is transmitted */
if (USART_TxHead != USART_TxTail) {
 /* Calculate buffer index */
  tmptail = (USART_TxTail + 1) & USART_TX_BUFFER_MASK;
 /* Store new index */
  USART_TxTail = tmptail;      
 /* Start transmission */
  UDR0 = USART_TxBuf[tmptail];  
 } else {       
 /* Disable UDRE interrupt */
  UCSR0B &= ~(1<<UDRIE0);         
 }
}

unsigned char USART0_Receive(void)
{
unsigned char tmptail;

/* Wait for incoming data */
while (USART_RxHead == USART_RxTail);
/* Calculate buffer index */
 tmptail = (USART_RxTail + 1) & USART_RX_BUFFER_MASK;
/* Store new index */
 USART_RxTail = tmptail;                
/* Return data */
return USART_RxBuf[tmptail];          
}

void USART0_Transmit(unsigned char data)
{
unsigned char tmphead;

/* Calculate buffer index */
 tmphead = (USART_TxHead + 1) & USART_TX_BUFFER_MASK;
/* Wait for free space in buffer */
while (tmphead == USART_TxTail);
/* Store data in buffer */
 USART_TxBuf[tmphead] = data;
/* Store new index */
 USART_TxHead = tmphead;               
/* Enable UDRE interrupt */
 UCSR0B |= (1<<UDRIE0);                    
}


Final main.c File

The main.c file is now much more manageable

#include <avr/io.h>
#include
<avr/interrupt.h>  //ADDED
#include
"USART_irq.h"



int main(void)
{
/* Set the baudrate to 9600 bps using 8MHz internal RC oscillator */
 USART0_Init(MYUBRR);    //CHANGED to PASS MYUBRR from calculation

 sei();


for( ; ; ) {
 /* Echo the received character */
  USART0_Transmit(USART0_Receive());
 }
}


Back to Top

Previous Lesson

Next Lesson

Back to Top