CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Timer interrupt based serial receive routine

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 19495

View user's profile Send private message

Timer interrupt based serial receive routine
PostPosted: Thu Oct 31, 2013 2:56 am     Reply with quote

This is based on a post I made a long time ago in the forums, showing a way of having async serial receivable on any PIC pin using a time interrupt.

Code:

//Timer interrupt based serial rx - timer values shown at 9600bps on a 20MHz PIC4520
//demonstrates a way of retrieving characters from any pin, without having to sit waiting in the main code
//and buffers these for when they are needed....
//9600bps, is about the fastest 'comfortable' with the approach and clock speeds shown.

#include <18F4520.h>
#use delay(crystal=20MHz)
//Pic configuration here for whatever chip you use.

#define RX_INPUT_LINE PIN_A0 //choose the pin you want

#define BUFF_SIZ 16 //definitions for serial buffer
int8 rx_buffer[BUFF_SIZ];
int8 rx_in=0;
int8 rx_out=0;
#define rx_has_data() (rx_in!=rx_out)
#define increment(x) if (++x>=BUFF_SIZ) x=0
char rx_getc(void) //gets a character from the RX buffer if available - return zero if not
{
   char temp_chr=0;
   if (rx_has_data())
   {
      temp_chr=rx_buffer[rx_out];
      increment(rx_out);
   }
   return temp_chr;
}

//Remember like all things _get out of the ISR quickly_ This code does this, and any other
//interrupts in use, must also be written this way, if they are not going to interfere.
#int_timer2 //For whatever timer you are using - easiest for timer2 to give accurate times
void timer_int(void) {
   static int8 state=0;
   static int8 incoming=0;
   static int8 bitmask=1;

   //any other timer code wanted here
   switch (state) {
   case 0:
       if (input(RX_INPUT_LINE)==0) state=1; //start bit
       break;
   case 1:
   case 2:
       if (input(RX_INPUT_LINE)==0) state++; //test again
       else state=0; //and error restart
       break;
   case 3: //since bit time is four interrupts, for three out of four
   case 4: //loops, simply advance one state and exit
   case 5: //This keeps work in the interrupt small
   case 7:
   case 8:
   case 9:
   case 11:
   case 12:
   case 13:
   case 15:
   case 16:
   case 17:
   case 19:
   case 20:
   case 21:
   case 23:
   case 24:
   case 25:
   case 27:
   case 28:
   case 29:
   case 31:
   case 32:
   case 33:
   case 35: //These last three, are delaying to the middle of the stop
   case 36: //bit
   case 37:
       state++; //all that is done in three out of four interrupts....
       break;
   //Now sample at four interrupt intervals from the 'double checked'
   //start bit edge - 8 bits
   case 6: 
   case 10:
   case 14:
   case 18:
   case 22:
   case 26:
   case 30:
   case 34:
       if (input(RX_INPUT_LINE)==1) incoming|=bitmask; //set the received bit
       bitmask*=2; //next bit
       state++;
       break;
   case 38:
       //Here should be in the stop bit - save received byte
       rx_buffer[rx_in]=incoming;
       increment(rx_in);
       if (rx_in==rx_out)
          increment(rx_out); //throw oldest character if buffer overflows
       state=incoming=0;
       bitmask=1;
       break;
   }
}

//Now this is based on using a timer interrupt at 4* the baud rate. So for 9600bps, 38400ips
//main stuff
void main(void)
{
   int8 val_rx;
   //remember you may need to turn things off on the pin you want to use. analogs?.
   setup_comparator(NC_NC_NC_NC);
   setup_adc_ports(NO_ANALOGS);
   //needs to suit the pin you are using.....
   
   //start with the clock rate - say 20MHz. Instruction rate is 5Meg. For 9600bps require
   //38400 samples per second, and divider of : (5000000/38400) = 130.2 - nearest integer = 130
   //If this is above 256, use a 'divisor' other than one. Otherwise program as:
   setup_timer_2(T2_DIV_BY_1,129,1); //remember one less than the divider required.
   
   //For 4800bps (5000000/19200) = 260.4, so T2_DIV_BY_4,64,1 etc...
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);
   
   do
   {
      if (rx_has_data())
      {
         //you will get here when characters have been received
         val_rx=rx_getc(); //retrieves the received character.
         //Do what you want with it......
         
      }
   }
   while (TRUE);
}

Makes something much closer to a hardware receive only UART with buffering.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group