|
|
View previous topic :: View next topic |
Author |
Message |
ritchie
Joined: 13 Sep 2003 Posts: 87
|
RS232 Communication between two PICs |
Posted: Tue Mar 02, 2004 5:00 am |
|
|
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
|
|
Posted: Tue Mar 02, 2004 5:54 am |
|
|
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
|
|
Posted: Tue Mar 02, 2004 7:33 am |
|
|
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
|
|
Posted: Tue Mar 02, 2004 8:23 am |
|
|
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
|
|
Posted: Tue Mar 02, 2004 9:34 am |
|
|
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 |
Posted: Tue Mar 02, 2004 11:04 am |
|
|
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
|
|
Posted: Tue Mar 02, 2004 6:03 pm |
|
|
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. |
|
|
|
|
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
|