Overview
For a small embedded controller, UART(Universal Asynchronous Receiver-Transmitter) is a communication module inside the controller that send and receive serial data to or from its peripheral device. Its data format and speed are configurable.
A Conventional UART Module |
This communication module is commonly come with many popular micro-controller such as, AT89S52, ATMega32, or PIC16F877A, etc.
A Simple Connection Between Two Devices |
Connecting device may use one of there three communication modes:
- simplex
- full duplex
- haft duplex
A UART frame consists of 5 elements:
- Idle (logic high)
- Start bit (logic low)
- Data bits
- Parity bit
- Stop bit (logic high)
In most common settings of 8 data bits, on parity and 1 stop bit (aka 8N1).
UART Signal |
Signal could be transmitter or receiver signal. BCLK is a clock source inside each devices.
Baud or bits per second (bit/s) is the number of bits that processed per unit of time. Each data bits duration could be calculated a:
Where,
- Ts : symbol duration
- fs : Baud or pits per second
For example, we select a 9600 baud. Hence,
Ts = 1 / 9600 = 0.000104 second = 104 microseconds.
So each data bits (1's or 0's) must be around 104 microseconds.
For any controller that come with UART module, the programmer can set its baud by hardware setting and calculation.
However some controller doesn't have UART module inside (e.g PIC16F84A). So we can emulate UART by bit banging GPIO pins in software (Assembly or C language).
PIC16F84A UART Bit Banging
Bit banging of serial communication could be done easily using software routine in most of programming languages. It requires additional program space. The programmer can select any microcontroller digital I/O pin to transmit or receiving data bits. Data processing takes a little period to send and receive serial data. However data errors may occur in some situation.
Some C compiler such as MikroC, CCS PICC have a software driver for bit banging. But we write our own function to process this task.
In this example, I select a 9600 baud, no parity and one stop bit (8N1). Start bit triggers from a high to low transition. Logic low signal should be delayed for around 100 microseconds. Each data bits should be sampled at the middle of data bits duration. The program samples receiving data bits around 60 microseconds.
Sample Data Bits For A 9600 Baud |
The program listens to serial data start of transmission. Whenever the high to low transition start the serial data reception will process.
Received ASCII Data Showed On Port B |
/* for 9600 baud rate * 1/9600 = 104uS per bit * we can use 102.5uS per bit */ #include <xc.h> // PIC16F84A Configuration Bit Settings // CONFIG #pragma config FOSC = XT // Oscillator Selection bits (XT oscillator) #pragma config WDTE = OFF // Watchdog Timer (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (Power-up Timer is disabled) #pragma config CP = OFF // Code Protection bit (Code protection disabled) #define _XTAL_FREQ 4000000 #define TX RA0 #define RX RA1 void sendChar(char data){ TX=0; __delay_us(100); for(int i=0;i<8;i++){ TX=data&(1<<0); data>>=1; __delay_us(75); } TX=1; __delay_us(100); } char myChar=0,temp=0; void receiveChar(void){ if(RX==0){ __delay_us(100); for(char i=0;i<8;i++){ __delay_us(60); if(RX==1) myChar|=(1<<i); else myChar&=~(1<<i); } __delay_us(50); } } void sendText(char *text){ while(*text) sendChar(*text++); } void softUARTInit(void){ PORTA=0x00; TRISA=0x02; PORTB=0; TRISB=0; TX=1; } void main(){ softUARTInit(); sendText("HELLO WORLD!\r\n"); while(1){ receiveChar(); if(myChar!=0){ PORTB=myChar; sendChar(myChar); //sendText("\r\n"); if(myChar=='0') { RA2^=1; sendText(" Toggle RA2.\r\n");} if(myChar=='1') { RA3^=1; sendText(" Toggle RA3.\r\n");} myChar=0; } } }
Click here to download this example.
PIC16F84A UART Bit Banging And Character LCD Example
A character LCD is very easy to control using a small micro-controller. Now I will send ASCII characters over UART terminal to the micro-controller. Those character will show on a 20x4 character LCD.
Program Simulation |
This example program consume half of program memory.
/* Software UART LCD Example 1 */ #include <xc.h> #include "LCD4Bits.h" // PIC16F84A Configuration Bit Settings // CONFIG #pragma config FOSC = XT // Oscillator Selection bits (XT oscillator) #pragma config WDTE = OFF // Watchdog Timer (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (Power-up Timer is disabled) #pragma config CP = OFF // Code Protection bit (Code protection disabled) #define _XTAL_FREQ 4000000 #define TX RA0 #define RX RA1 void sendChar(char data){ TX=0; __delay_us(100); for(int i=0;i<8;i++){ TX=data&(1<<0); data>>=1; __delay_us(75); } TX=1; __delay_us(100); } char myChar=0,temp=0; void receiveChar(void){ if(RX==0){ __delay_us(100); for(char i=0;i<8;i++){ __delay_us(60); if(RX==1) myChar|=(1<<i); else myChar&=~(1<<i); } __delay_us(100); } } void sendText(char *text){ while(*text) sendChar(*text++); } void softUARTInit(void){ PORTA=0x00; TRISA=0x02; PORTB=0; TRISB=0; TX=1; } void main(){ uint8_t line=1,charNum=1; softUARTInit(); lcdInit(); sendText("PIC16F84A Software UART And Character LCD\r\n"); lcdString("PIC16F84A 20x4 LCD"); lcdXY(1,2); lcdString("Software Delay UART"); lcdXY(1,3); lcdString("Programming Example"); lcdXY(1,4); lcdString("MPLABX IDE And XC8"); __delay_ms(2000); lcdClear(); while(1){ receiveChar(); if(myChar!=0&&myChar!=0x08){ sendChar(myChar); if(myChar=='0') { RA2^=1; sendText(" Toggle RA2.\r\n");} if(myChar=='1') { RA3^=1; sendText(" Toggle RA3.\r\n");} if(myChar==0x0D) { line+=1; lcdXY(1,line); charNum=1; }else{ lcdData(myChar); } charNum+=1; if(charNum>20) {charNum=1; line+=1; lcdXY(charNum,line);} if(line>4){line=1;lcdXY(charNum,line);} myChar=0; } } }
Click here to download its source file.