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

RS232 Communication between two PICs

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ritchie



Joined: 13 Sep 2003
Posts: 87

View user's profile Send private message

RS232 Communication between two PICs
PostPosted: Tue Mar 02, 2004 5:00 am     Reply with quote

Hello,

I have a system which uses two PICs both 18F452 at 20Mhz. The other one is a master were its TX pin is directly connected to the slave thru the RB2 pin which is configured to use #int_ext2 interrupt. I use the scope to check the TX pin status if it is high during normal condition.. with that yes it is a high such I configured the #int_ext2 to detect on falling edge.

I guess you might ask why? I didn't use the RX pin of slave.. is because I have another use for this pin.

My problem really is that I only received data on the second transmission and it is a garbage data also. I need your help to comment, suggest or maybe reveiw my code below for the slave.

The Code list:
Code:


#include <18F452.H>           // Target PIC Microcontroller IC
#device  *=16                 // use a 16-bit pointer

#fuses HS,NOPROTECT,NOWDT     // PIC MCU Configuration
#use delay(clock=20000000)    // 20MHz Crystal clock speed

// software based UART for #INT_EXT1 and #INT_EXT2 (RS485 Comm from Slave)
#use rs232(baud=115200,parity=N,xmit=PIN_B1,rcv=PIN_B2,bits=8,stream=SL485Com)

// hardware based UART for #INT_RDA and #INT_TBE (RS485 Communication)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7, \
           bits=8,stream=PCHost,enable=PIN_B4)

#bit INTEDG2 = 0xFF1.4
#bit INT2IF  = 0xFF0.1

#define SRX_SIZE 32
byte SRXbuffer[SRX_SIZE];
byte SRXin = 0;
byte SRXout = 0;

int1 glSL485RXReady;
int1 glSL485RXdata;

unsigned int8 srxchksm=0;
char gcSL485data[SRX_SIZE];
           
#int_ext2
void sl485_isr()
{
   if (glSL485RXReady)
   {
      SRXbuffer[SRXin] = fgetc(SL485Com);
      srxchksm ^= SRXbuffer[SRXin];
      SRXin++;
     
      if (SRXin==21){
         glSL485RXReady=0;
         glSL485RXdata=1; }
   }
   else fgetc(SL485Com);
}

void NULL_SRXbuf()
{
   unsigned int8 i;
   
   for (i=0; i<SRX_SIZE; i++){
      SRXbuffer[i]=0;
      gcSL485data[i]=0; }
}

void init_mcu()
{
   INTEDG2 = 0;
   INT2IF  = 0;

   setup_adc_ports(NO_ANALOGS);
   enable_interrupts(int_ext2);
   enable_interrupts(global);
}

void display_data()
{
   unsigned int8 i;
   
   for (i=0; i<SRXin; i++)
      fprintf(PCHost,"%c",SRXbuffer[i]);
}


main()
{
   init_mcu();
   NULL_SRXbuf();
   
   glSL485RXReady=1;
   glSL485RXdata=0;

   while (true)
   {
      if (glSL485RXdata)
      {
         glSL485RXdata=0;
         display_data();
         glSL485RXReady=1;
         SRXin=0;
      }
   }
}



BTW, the fprintf routine is just to check if I get the data correctly.

Thnx
mpfj



Joined: 09 Sep 2003
Posts: 95
Location: UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Tue Mar 02, 2004 5:54 am     Reply with quote

I think your problems might come down to using a software uart ... basically the s/w uart is not an intelligent beast, and just uses loops for its timing.

Do you *really* want to have huge loops in your interrupt routines ?

Also, since it's relying on it's own timings to sample the incoming datastream, is your clock stable / accurate enough to work at 115kbps ?
ritchie



Joined: 13 Sep 2003
Posts: 87

View user's profile Send private message

PostPosted: Tue Mar 02, 2004 7:33 am     Reply with quote

mpfj wrote:
I think your problems might come down to using a software uart ... basically the s/w uart is not an intelligent beast, and just uses loops for its timing.

Do you *really* want to have huge loops in your interrupt routines ?

Also, since it's relying on it's own timings to sample the incoming datastream, is your clock stable / accurate enough to work at 115kbps ?


I am using a 20MHz ceramic resonator from murata if I am right the part number is CSTCG20M0V53 with a +/- 2ppm.

The code listed above especially the routine to capture data from external interrupt is widely use with other projects that I have. I guess the difference is that I use the 9600bps. With this project I decided to use the 115200bps for the software uart using external interrupt.

My recent project will utilize a two UART since the 18F452 has one hardware uart that's why I decided to use external interrupt.

Are there any alternative I can have?

Thank you.
mpfj



Joined: 09 Sep 2003
Posts: 95
Location: UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Tue Mar 02, 2004 8:23 am     Reply with quote

If you really want to run at 115kbps with a s/w uart, I would recommend doing your own using timers !!

It may sound over the top, but it is relatively straight forward. The basic idea is this ...

It requires 2 timers for full duplex or 1 timer for half-duplex ... these are set to 1 (or a 1/2) bit time @ 115kbps.

RX
---
1. Use the external interrupt to tell you when comms has started (as you already are).
2. At this point kick off a timer with a 1/2 bit time.
3. When the timer interrupt occurs ...
3a. Sample the rx pin, shift and store.
3b. If more bits are required, set the timer's timeout to a whole bit time, and wait for the next timer irq.
3c. If no more bits a required, stop the timer. Data byte now complete.
3d. Exit timer irq

TX
---
1. Set output pin to "start" bit value
2. Set timer to 1 bit time
3. On timer irq ...
3a. Output next data bit.
3b. If more bits to send, reset timer to 1 bit time
3c. If no more bits to send, stop timer.
3d. Exit timer irq.

Since you're using a timer, most of the software overheads (all those nasty delay loops) are removed. Thus everything will run smoother, with less CPU time, and probably smaller code !!

You can also get clever, and keep the timer trained to the incoming bitstream by resetting the timer to a 1/2 bit time whenever you detect another H-to-L (or L-to-H) change on the "external" irq. It's not strictly needed since you're only receiving 10 or so bits at a time ... it's mandatory when you're capturing 100s of bits, but that's another story !!

Mark
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Mar 02, 2004 9:34 am     Reply with quote

For my 2 cents,.. If you have the option, try to find a part with 2 hardware UARTS. At that speed, the 2 byte buffer is very helpfull.
Ttelmah
Guest







Re: RS232 Communication between two PICs
PostPosted: Tue Mar 02, 2004 11:04 am     Reply with quote

ritchie wrote:
Hello,

I have a system which uses two PICs both 18F452 at 20Mhz. The other one is a master were its TX pin is directly connected to the slave thru the RB2 pin which is configured to use #int_ext2 interrupt. I use the scope to check the TX pin status if it is high during normal condition.. with that yes it is a high such I configured the #int_ext2 to detect on falling edge.

I guess you might ask why? I didn't use the RX pin of slave.. is because I have another use for this pin.

My problem really is that I only received data on the second transmission and it is a garbage data also. I need your help to comment, suggest or maybe reveiw my code below for the slave.

The Code list:
Code:


#include <18F452.H>           // Target PIC Microcontroller IC
#device  *=16                 // use a 16-bit pointer

#fuses HS,NOPROTECT,NOWDT     // PIC MCU Configuration
#use delay(clock=20000000)    // 20MHz Crystal clock speed

// software based UART for #INT_EXT1 and #INT_EXT2 (RS485 Comm from Slave)
#use rs232(baud=115200,parity=N,xmit=PIN_B1,rcv=PIN_B2,bits=8,stream=SL485Com)

// hardware based UART for #INT_RDA and #INT_TBE (RS485 Communication)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7, \
           bits=8,stream=PCHost,enable=PIN_B4)

#bit INTEDG2 = 0xFF1.4
#bit INT2IF  = 0xFF0.1

#define SRX_SIZE 32
byte SRXbuffer[SRX_SIZE];
byte SRXin = 0;
byte SRXout = 0;

int1 glSL485RXReady;
int1 glSL485RXdata;

unsigned int8 srxchksm=0;
char gcSL485data[SRX_SIZE];
           
#int_ext2
void sl485_isr()
{
   if (glSL485RXReady)
   {
      SRXbuffer[SRXin] = fgetc(SL485Com);
      srxchksm ^= SRXbuffer[SRXin];
      SRXin++;
     
      if (SRXin==21){
         glSL485RXReady=0;
         glSL485RXdata=1; }
   }
   else fgetc(SL485Com);
}

void NULL_SRXbuf()
{
   unsigned int8 i;
   
   for (i=0; i<SRX_SIZE; i++){
      SRXbuffer[i]=0;
      gcSL485data[i]=0; }
}

void init_mcu()
{
   INTEDG2 = 0;
   INT2IF  = 0;

   setup_adc_ports(NO_ANALOGS);
   enable_interrupts(int_ext2);
   enable_interrupts(global);
}

void display_data()
{
   unsigned int8 i;
   
   for (i=0; i<SRXin; i++)
      fprintf(PCHost,"%c",SRXbuffer[i]);
}


main()
{
   init_mcu();
   NULL_SRXbuf();
   
   glSL485RXReady=1;
   glSL485RXdata=0;

   while (true)
   {
      if (glSL485RXdata)
      {
         glSL485RXdata=0;
         display_data();
         glSL485RXReady=1;
         SRXin=0;
      }
   }
}



BTW, the fprintf routine is just to check if I get the data correctly.

Thnx

Your problem is (unfortunately), latency.
Even if there are no other interrupt sources in use, the interrupt response time from receiving an 'edge', to actually entering the handler routine, will typically be as much as 40 instruction times on the 18 family chips. At 20MHz, this means that you don't get to the serial code, till about 1/125000th of a second has passed. At this point, your start bit will have allready probably passed (you add a few more instruction times with your logic test), and the call to fgetc, then waits for the next falling bit, before starting to receive data. Hence the result is garbage.
If you want to do this, work another way. Add one extra wire between the chips, and connect this to the interrupt input. Then have the transmitting routine set this signal, and wait for about 10uSec, before starting to send data. In the receiving chip, have the interrupt triggered the same way, and immediately call the read routine (using another pin). This way, the receiving chip gets a 'warning' to go to the receive routine.

Best Wishes
ritchie



Joined: 13 Sep 2003
Posts: 87

View user's profile Send private message

PostPosted: Tue Mar 02, 2004 6:03 pm     Reply with quote

Quote:

Your problem is (unfortunately), latency.
Even if there are no other interrupt sources in use, the interrupt response time from receiving an 'edge', to actually entering the handler routine, will typically be as much as 40 instruction times on the 18 family chips. At 20MHz, this means that you don't get to the serial code, till about 1/125000th of a second has passed. At this point, your start bit will have allready probably passed (you add a few more instruction times with your logic test), and the call to fgetc, then waits for the next falling bit, before starting to receive data. Hence the result is garbage.
If you want to do this, work another way. Add one extra wire between the chips, and connect this to the interrupt input. Then have the transmitting routine set this signal, and wait for about 10uSec, before starting to send data. In the receiving chip, have the interrupt triggered the same way, and immediately call the read routine (using another pin). This way, the receiving chip gets a 'warning' to go to the receive routine.


Do you have a sample snippet and a schematics on how I can connect an extra wire? I'll appreciate any help.

Thank you.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion 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