Experiment #14. USART module.

Lets look at USART module in pic microcontroller (uart module).

I’m going to move by two ways:

1. Using existing functions from hi-tech compiler.

2. Writing my own functions.

USART = UART = SCI – the universal data transmitting/recieving protocol, which can work in synchronous and asynchronous mode. We pay attention to the second mode at the moment, this one is used for communications mostly.

Data transmitting example:

Some remarks about an asynchronous mode:

  • There is a high logic level at the line at standby.
  • New data transmission has a zero bit at the start.
  • LSB is transmitted first.
  • All transmissions has stop bit with high logic level.

For start, let me deal with baud rate generator (BRG).

A SPBRG register and BRGH bit determines period of BRG. Here is equation for rate:

BRG_rate

For example, I’m going to calculate SPBRG value for the next conditions:

Fosc = 16 MHz

Baud rate = 9600

BRGH = 0

SYNC = 0

Calculation:

9600 = 16 000 000/(64(Х+1)) => X = 25.042 = 25

Ok, seems like we’ve done with BRG, now what about trasmitter and reciever?

TXSTA register – transmitter


CSRC Clock source
Synchronous mode
1 master, clock from BRG
0 slave, clock from CK
Asynchronous mode
Not used
TX9 9-bit transmission enable?
1 enabled
0 disabled
TXEN Tramsmission on/off
1 on
0 off
SYNC 1 synchronous mode
0 asynchronous mode
BRGH High-speed mode
Synchronous mode
Irrelevant
Asynchronous mode
1 high speed
0 low speed
TMRT TSR clear flag
1 TSR is empty
0 TSR is full
TX9D 9-th data bit

Transmitter functional diagramm:


The main part of transmitter is shifr register TSR, which gets the data from transmitter’s buffer TXREG. When stop bit is transmitted, TSR loaded by new data from TXREG (if there is something), after that TXIF interrupt flag is set. There is a one feature with interrupts – TXIF flag clears only when data has been loaded to TXREG, so you cann’t clear it by yourself in code.

Recommended sequencing for transmitting at asynchronous mode:

  1. Setup rate with SPBRG and BRGH bit.
  2. Choose asynchronous mode by clearing SYNC bit and setup SPEN to 1.
  3. Enable interrupts if you need it.
  4. If transmission has 9 bits, setup TX9 to 1.
  5. Switch on transmission mode (TXEN = 1).
  6. If transmission has 9 bits, move each 9 bit to TX9D.
  7. Write your data to TXREG.

Here is time diagramm for one byte transmission:


RCSTA register – reciever:


SPEN Enabling bit
1 USART is enabled
0 USART is disabled
RX9 9-bit recieving
1 allowed
0 not allowed
SREN One-byte receiving permission
Synchronous mode
1 allowed
0 not allowed
Asynchronous mode
Irrelevant
CREN Receiving permission
Synchronous mode
1 allowed
0 not allowed
Asynchronous mode
1 allowed
0 not allowed
ADDEN Address detection permission
Asynchronous 9-bit receiving
1 allowed
0 not allowed
FERR Frame error
1 Error has occurred
0 Error hasn’t occurred
OERR Buffer overflow error
1 Error has occurred
0 Error hasn’t occurred
RX9D 9-th bit of data

Receiver functional diagramm:

rec

For receiver the main part is shift register RSR, data from input RB1 loads direct into it. After receiving a stop bit, data will be loaded to RCREG, which has two buffers. So, receiver get three bytes – two bytes in FIFO buffers and one in the shift register. There is OERR in “1” when third byte has been received. After that you need to clear OERR by switching OFF/ON CREN.

Recommended sequencing for receiving at asynchronous mode:

  1. Setup rate with SPBRH and BRGH bit.
  2. Choose asynchronous mode by clearing SYNC bit and setup SPEN to 1.
  3. Enable interrupts if you need it.
  4. If transmission has 9 bits, set RX9 to 1.
  5. Allow recieving mode by setting CREN to 1.
  6. Wati for RCIF or interrupt event.
  7. Read 9-th data bit.
  8. Read whole RCREG.
  9. If error has occured set CREN to 0.

Receiver work timing diagramm:

Let’s move to practise. I have two ways for testing:

  1. Proteus.
  2. Checking with my devboard, connecting it by max232 to rs232 level converter.

For a start, I’m going to move by first way, and in the end I just write big test programm and check it at terminal of a PC.

Transmitting. Go to the compiler work directory and find “examples” folder. There are 3 files for this part:

  • main.c
  • usart.c
  • usart.h

usart.h:


#ifndef _SERIAL_H_

#define _SERIAL_H_

#define BAUD 9600           //baud rate

#define FOSC 4000000L       //xtall frequency

#define NINE 0              //9-bit?

#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1)) //SPBRG register

#define HIGH_SPEED 1        //high speed communications

#if NINE == 1

#define NINE_BITS 0x40

#else

#define NINE_BITS 0

#endif

#if HIGH_SPEED == 1

#define SPEED 0x4

#else

#define SPEED 0

#endif

#define RX_PIN TRISB1        //RX pin
#define TX_PIN TRISB2        //TX pin

/* Initialization */

#define init_comms()

RX_PIN = 1;

TX_PIN = 1;

SPBRG = DIVIDER;

RCSTA = (NINE_BITS|0x90);

TXSTA = (SPEED|NINE_BITS|0x20)

void putch(unsigned char);      //One symbol transmitting

unsigned char getch(void);      //One symbol receiving

unsigned char getche(void);     //I don't know for a what this function :)

#endif

usart.c:


#include <htc.h>

#include <stdio.h>

#include "usart.h"

void

putch(unsigned char byte)

{

/* One byte transmission */

while(!TXIF)	/* TXIF = 1 when register is empty */

continue;

TXREG = byte;

}

unsigned char

getch() {

/* one byte receiving */

while(!RCIF)

continue;

return RCREG;

}

unsigned char      //again I don't know :)

getche(void)

{

unsigned char c;

putch(c = getch());

return c;

}

And now, we’ll write main.c. For example, we want to transmit symbol ‘K’=0b01001011

a little piece of a code:


#include <stdio.h>

#include <htc.h>

#define _XTAL_FREQ 4000000

#include "usart.h"

__CONFIG(LVPDIS & WDTDIS & MCLREN & UNPROTECT & HS);

void main(void){

unsigned char input;

INTCON=0;       //interrupts disabled

init_comms();	// usart initialization

putch('K');     // transmit K symbol

while(1){

}

}

The result:

result

Seems like it works, let’s transmit this one by existing functions.


#include <htc.h>

#define _XTAL_FREQ 4000000

__CONFIG(LVPDIS & WDTDIS & MCLREN & UNPROTECT & HS);

void main(void){

TRISB = 0xFF;   //B input

BRGH = 0;           //low speed mode

SPBRG = 0x05;      //calculated value

SYNC = 0;          //asynchronous mode

SPEN = 1;

TXEN = 1;          //transmission is allowed

TXREG =0b01001011;           //push К symbol

while(1){

}

}

Here is output (don’t forget that 7 bit is second) :

And for receiver I’ve used existing functions too:


#include <stdio.h>

#include <htc.h>

#define _XTAL_FREQ 4000000

#include "usart.h"

__CONFIG(LVPDIS & WDTDIS & MCLREN & UNPROTECT & HS);

void main(void){

unsigned char input;

INTCON=0;	// purpose of disabling the interrupts.

init_comms();	// set up the USART - settings defined in usart.h

// Output a message to prompt the user for a keypress

printf("\rPress a key and I will echo it back:\n");

while(1){

input = getch();	// read a response from the user

printf("\rI detected [%c]",input);	// echo it back

}

}

This code waits if any button is pressed, value of button will be returned immediately:

 

 

 

 

 

 

I will not write about own function for receiving, because settings are the same as for transmitter and function will be look like existing one in a example file:


unsigned char

getch() {

/* retrieve one byte */

while(!RCIF)	/* set when register is not empty */

continue;

return RCREG;

}

That's all, this portion of information is enough for successful use of USART module in PIC microcontrollers.

Sources.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.