Pic Lab, PIC18, Experiment #1, UART in PIC18

This was a time to switch to XC8 compiler, it was not hard at all, but appeared that using of UART in PIC18 series has some peculiarities.

At the moment of this article the XC8 compiler had libraries for work with a periphery in the folder /includes/plib. Now they got rid of it and experimenting with a different approach. Anyway the legacy support looks like quite a strong side for microchip. Well I used then usart.h library which now I regret I did.

Out tasks are:

  • To write a single symbol
  • To write a string
  • To read 1 symbol = 1 byte
  • To read a couple of bytes

I will be working with PIC18F14K50.

Firstly we need to configure the uart (or the usart, whatever), to do so there is a function called OpenUSART(Config, baud) where config this is setup similar in some kind to the _CONFIG macros and baud, obviously, a variable for baud rate setup:

FOSC/[16 (baud+1)]

Assume we want baudrate 9600 and the quartz 12 MHz

baud = 12M/(9600*16) – 1 = 77.125 ~ 77

To check how the config should look like, I recommend to eyeball the file pic18_plib.pdf, which is located in docs directory of the XC compiler, it really throughout and intuitive.

Starting from the writing of a single byte, we have the dedicated function:

void WriteUSART(char data)

Looks really simple:

#include <xc.h>
#include <plib/usart.h>

#define _XTAL_FREQ 12000000 //The speed of your internal(or)external oscillator

#pragma config WDTEN = OFF, LVP = OFF, FOSC = HS

unsigned char UARTConfig = 0; baud = 0;
char txbyte = 'U';         //наш байт для пересылки

void main()
{
 TRISB7 = 0; //TX pin set as output
 TRISB5 = 1; //RX pin set as input

 UARTConfig = USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH ;    //прерывания выключены, асинхронный режим, 8 бит, высокоскоростной режим
 baud = 77;                 //Focs/(9600*16) - 1
 OpenUSART(UARTConfig,baud);

 WriteUSART(txbyte);        //Пишем наш байт

 while(1)
  {
  }//while(1)

}//main

Next in a row – the string, we have a function handy as well:

void putsUSART( char *data)

I saw the function and immediately got a question – can I send any symbol by this function, and more specifically – numbers.

Symbols are not the issue – \r\n stuff getting thru, without any single problem. The numbers are not that easy, it is not like printf where you can throw %d and happily observe the result. But no worries, on a bright side – the memory is not wasted to keep this capability just in case. We rather will create own function for this purpose.

void NumToUart(unsigned int Num) //Число в уарт
{

 unsigned int bignum = 10000;    //максимальный делитель
 unsigned char numtemp = 5;      //максимальное количество разрядов

while(numtemp>0)                 //Определяем сколько разрядов имеет наше число
 {
   if (Num/bignum)
     break;
   numtemp--;
   bignum = bignum / 10;
 }

for (unsigned char i = numtemp; i>0; i--)
 {
    WriteUSART( (Num - (Num/(bignum*10))*bignum*10 )/bignum + '0'); //Выталкиеваем все разряды - от старшего к младшему
    while(BusyUSART());                                             //Ждем пока освободится модуль иначе будут прострелы
    bignum = bignum/10;
 }

}

By the way, I recommend to use macros while(BusyUSARTO()) each time, otherwise the information might be lost.

Time to experiment.

putsUSART( (char *) "Welcome to Diymicro.ru \r\n" );
putsUSART( (char *) "The number is " );
NumToUart(1283);

The reading from uart.

I’m using a pic18f14k50, which has the RB5 as an analog channel, i.e. we need to turn on the digital mode first.

ANSEL = 0;
ANSELH = 0;

Now, we can work.

As usual, we have two ways – the bad one and the interruptions, but since it is just an experiment I chosen the bad one.

We can read one byte with a function:

char ReadUSART(void)

while(!DataRdyUSART());
rxbyte=ReadUSART();
while(BusyUSART());

And that should done the trick – the usart context should be inside of the rxbyte variable. Again, using while(busyuart) to clean the clutter and let the module to finish work smoothly.

If we want to read more info, then we could use this function:

void getsUSART(char *buffer, unsigned char len)

The function read len amount of bytes

#include <xc.h>
#include <plib/usart.h>

#define _XTAL_FREQ 12000000 //The speed of your internal(or)external oscillator

#pragma config WDTEN = OFF, LVP = OFF, FOSC = HS  

unsigned char UARTConfig = 0;
unsigned char baud = 0;
char txbyte = 'U';         //наш байт для пересылки
unsigned char Rxdata[10];

void NumToUart(unsigned int Num)                                                //Число в уарт
{

  unsigned int bignum = 10000;
  unsigned char numtemp = 5;

  while(numtemp>0)                                                             //Определяем сколько разрядов имеет наше число
  {
    if (Num/bignum)
        break;
    numtemp--;
    bignum = bignum / 10;
  }  

  for (unsigned char i = numtemp; i>0; i--)
    {
      WriteUSART( (Num - (Num/(bignum*10))*bignum*10 )/bignum + '0');         //Выталкиеваем все разряды - от старшего к младшему
      while(BusyUSART());                                                       //Ждем пока освободится модуль иначе будут прострелы
      bignum = bignum/10;
    }

}

void main()
{

 ANSEL = 0;                                                                   //Отключаем аналоговые буфера
 ANSELH = 0;

 TRISB7 = 0; //TX pin set as output
 TRISB5 = 1; //RX pin set as input
 TRISB6 = 1; //RX pin set as input

 UARTConfig = USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH ;    //прерывания выключены, асинхронный режим, 8 бит, высокоскоростной режим
 baud = 77;                 //Focs/(9600*16) - 1
 OpenUSART(UARTConfig,baud);

 WriteUSART(txbyte);        //Пишем наш байт
 putsUSART( (char *) "\r\nputs test\r\n" );
 putsUSART( (char *) "Welcome to Diymicro.ru\r\n" );
 putsUSART( (char *) "The number is " );
 NumToUart(1283);

 getsUSART(Rxdata, 10);
 while(BusyUSART());
 putsUSART( (char *) "\r\nAll bytes have recieved, your message is - \r\n" );
 putsUSART(Rxdata);

 putsUSART( (char *) " \r\nNow, just print what you want :) \r\n" );

 while(1)
 {
      while(!DataRdyUSART());
      txbyte=ReadUSART();
      while(BusyUSART());
      if (txbyte)
        {
          WriteUSART(txbyte);
          while(BusyUSART());
        }

  }//while(1)

}//main()

The sources

Leave a Reply

Your email address will not be published.