|
|
View previous topic :: View next topic |
Author |
Message |
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
PIC18F2620 + GPS: Software rs232 problem (solved) |
Posted: Thu Mar 06, 2008 11:51 am |
|
|
Hi all,
I am trying to receive data from a GPS unit (at 4800 bits/s) and trough a software rs232 interface.
The problem is that the data received from the software rs-232 has errors (garbage). Some bytes arrive OK, but others arrive with errors.
I already tested the GPS unit with one PC and it worked fine.
As may be seen in the code, I am using a interrupt-driven receive procedure.
I already tried to use a loop/kbhit structure to receive the data by the problem gets even worse.
The hardware USART is already in use and it can not be used (GSM module) for this purpose.
Here is the code:
Code: |
[--- HEADER ----]
#include <18F2620.h>
#device adc=8
#FUSES NOWDT
#FUSES WDT128
#FUSES HS
#FUSES NOPROTECT
#FUSES NOIESO
#FUSES NOBROWNOUT
#FUSES BORV21
#FUSES NOPUT
#FUSES NOCPD
#FUSES NOSTVREN
#FUSES NOLVP
#FUSES NOWRT
#FUSES NOWRTD
#FUSES NOEBTR
#FUSES NOCPB
#FUSES NOEBTRB
#FUSES NOWRTC
#FUSES NOWRTB
#FUSES NOFCMEN
#FUSES NOXINST
#FUSES NOPBADEN
#FUSES NOLPT1OSC
#FUSES MCLR
#use delay(clock=20000000,RESTART_WDT, xtal)
#use rs232(STREAM=GPS, baud=4800,parity=N,xmit=PIN_A0,rcv=PIN_A1, STOP=1, BITS=8) // software rs-232
[--- APPLICATION ---]
#include "sitel.h"
#include <string.h>
#include <stdlib.h>
#include "ura.h"
#ZERO_RAM
char acDados[513],
vcValor;
byte vbIndice = 0;
byte vbIndice2 = 0;
char str[] = "$GPRMC";
#int_ext2
void vISR_GPS(void)
{
if ( !kbhit(GPS) )
return;
vcValor = fgetc(GPS);
acDados[vbIndice] = vcValor;
if ( vbIndice > 200 )
vbIndice = 0;
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
set_tris_b( 0b00001111 );
set_tris_c( 0b11111001 );
output_high(LED_OPE);
ext_int_edge( 2, H_TO_L );
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT2);
do{}while( true );
}
|
In my opinion, there may be something wrong with the software rs-232 implementation, because some bytes arrive fine and others don't.
I guess it may be some kind of timing problem, but all the tests I have already done were unsuccessful .
Any help would be appreciated!
Last edited by rprodrigues on Wed Mar 12, 2008 3:51 pm; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 06, 2008 12:36 pm |
|
|
Code: | acDados[vbIndice] = vcValor;
if ( vbIndice > 200 )
vbIndice = 0;
} |
I don't see any code to increment the 'vbIndice' variable. It will
always stay at 0.
Also, I don't see any code to display or test that you are receiving
the correct values from the GPS. There is no code that displays
the GPS string in the acDados[] array after it has been received. |
|
|
Guest
|
|
Posted: Thu Mar 06, 2008 1:30 pm |
|
|
PCM programmer wrote: | Code: | acDados[vbIndice] = vcValor;
if ( vbIndice > 200 )
vbIndice = 0;
} |
I don't see any code to increment the 'vbIndice' variable. It will
always stay at 0.
Also, I don't see any code to display or test that you are receiving
the correct values from the GPS. There is no code that displays
the GPS string in the acDados[] array after it has been received. |
Hi, PCM,
That was my fault. I forgot the "vbIndice++" when I copied the code.
It is:
Code: |
#int_ext2
void vISR_GPS(void)
{
if ( !kbhit(GPS) )
return;
vcValor = fgetc(GPS);
acDados[vbIndice] = vcValor;
vbIndice++;
if ( vbIndice > 200 )
vbIndice = 0;
}
|
About the testing code, I use the debugger and/or another serial port do forward the received chars.
By the way, here there is an example of an NMEA string received by the software USART:
$GPRMC,000653.00,V,2328.2329,.Y&.Vf..6&..Vc,,150fF....SFV..
As we can see, after the "2328.2329," value, the others values are wrong.
Any idea?
Thank you |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 06, 2008 1:48 pm |
|
|
Do you have any interrupts active, in code that is not shown ?
If so, those interrupts will probably disrupt the software UART. |
|
|
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
|
Posted: Thu Mar 06, 2008 2:01 pm |
|
|
PCM programmer wrote: | Do you have any interrupts active, in code that is not shown ?
If so, those interrupts will probably disrupt the software UART. |
No, I don't have any interrupts active. |
|
|
gribas
Joined: 21 Feb 2008 Posts: 21
|
|
Posted: Thu Mar 06, 2008 2:19 pm |
|
|
I think that even if he had other interrupts they would have been disabled because he's reading from inside an interrupt routine.
What drives the external interrupt? How do you know how many bytes were actually read? What if the GPS's answer is splitted in two or more chunks of bytes? |
|
|
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
|
Posted: Thu Mar 06, 2008 2:35 pm |
|
|
gribas wrote: | I think that even if he had other interrupts they would have been disabled because he's reading from inside an interrupt routine.
What drives the external interrupt? How do you know how many bytes were actually read? What if the GPS's answer is splitted in two or more chunks of bytes? |
Hi, Gribas,
The external interrupt is driven by the pin R1OUT (12) of an MAX232N trough the pin RB2 of the MCU. The pin R1OUT (12) is also connected to the pin RA1 of the PIC18F2620, which is used by the software USART.
I use an counter to know the amount of bytes that were read.
It is not a problem if the GPS's answer is splitred in more than one chunk.
Could the connection between the pins RA1 and RB2 be the problem?
Thank you |
|
|
gribas
Joined: 21 Feb 2008 Posts: 21
|
|
Posted: Fri Mar 07, 2008 5:28 am |
|
|
Try this to check the connection:
Code: |
#include <18F2620.h>
#device adc=8
#FUSES NOWDT, WDT128, HS, NOPROTECT, NOIESO, NOBROWNOUT, BORV21, NOPUT, NOCPD,\
NOSTVREN,NOLVP,NOWRT,NOWRTD,NOEBTR,NOCPB,NOEBTRB,NOWRTC,NOWRTB,NOFCMEN,\
NOXINST,NOPBADEN,NOLPT1OSC,MCLR
#use delay(clock=20000000)
#use rs232(STREAM=GPS, baud=4800,parity=N,xmit=PIN_A0,rcv=PIN_A1, STOP=1, BITS=8) // software rs-232
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SERIAL)
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
while(1) {
if(kbhit(GPS)) {
fputc(fgetc(GPS),SERIAL);
}
}
}
|
|
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Fri Mar 07, 2008 5:39 am |
|
|
Most GPS units speak when they want. They also say what they want.
This means the PIC has to be able to receive any sentence at any time.
That means its best to have a circular buffer to capture a sentence. Now sentences are typically NMEA and will have some repeated info in the various sentences. Further not all sentences will have data since the GPS may not have the info yet or has lost the signal. Now to the circular buffer. The PIC has limited RAM and typically the PIC only needs to get data from one or more of the many sentences. The isr design should only allow the sentences you need to get into your isr's circular buffer. For example assume $GPRMC is the only sentence you need. Inside the isr only if the first 6 chars are $GPRMC does it get in. Set a state flag if the first char is $ move to state 1 if on the next interrupt the state flag is 1 and the char is G move to state 2 and so forth. If the state flag reaches 6 you have a sentence you need so let it into the buffer. After a complete sentence is received set a flag to let your main routine start parsing it. While your GPS speaks other sentences that you don't need your isr is rejecting them conserving RAM space and giving the PIC more time to parse before the next sentence arrives. Your buffer typically then holds the sentence you are currently decoding and just maybe ( a GPS leaves time between sentences) the next sentence starting to come in. |
|
|
gribas
Joined: 21 Feb 2008 Posts: 21
|
|
Posted: Fri Mar 07, 2008 5:56 am |
|
|
Here's an interrupt driven version.
Code: |
#include <18F2620.h>
#device adc=8
#FUSES NOWDT, WDT128, HS, NOPROTECT, NOIESO, NOBROWNOUT, BORV21, NOPUT, NOCPD,\
NOSTVREN,NOLVP,NOWRT,NOWRTD,NOEBTR,NOCPB,NOEBTRB,NOWRTC,NOWRTB,NOFCMEN,\
NOXINST,NOPBADEN,NOLPT1OSC,MCLR
#use delay(clock=20000000)
#use rs232(STREAM=GPS, baud=4800,parity=N,xmit=PIN_A0,rcv=PIN_A1, STOP=1, BITS=8) // software rs-232
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SERIAL)
char buffer[256];
int b_in = 0;
int b_out = 0;
int b_n = 0;
#int_ext2
void ext2_irq(void) {
if (kbhit(GPS)) {
buffer[b_in] = fgetc(GPS);
b_in++;
b_n++;
}
}
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
ext_int_edge( 2, H_TO_L );
enable_interrupts(INT_EXT2);
enable_interrupts(GLOBAL);
while(1) {
if (b_n) {
fputc(buffer[b_out],SERIAL);
b_out++;
b_n--;
}
}
} |
|
|
|
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
|
Posted: Fri Mar 07, 2008 12:25 pm |
|
|
gribas wrote: | Here's an interrupt driven version.
Code: |
#include <18F2620.h>
#device adc=8
#FUSES NOWDT, WDT128, HS, NOPROTECT, NOIESO, NOBROWNOUT, BORV21, NOPUT, NOCPD,\
NOSTVREN,NOLVP,NOWRT,NOWRTD,NOEBTR,NOCPB,NOEBTRB,NOWRTC,NOWRTB,NOFCMEN,\
NOXINST,NOPBADEN,NOLPT1OSC,MCLR
#use delay(clock=20000000)
#use rs232(STREAM=GPS, baud=4800,parity=N,xmit=PIN_A0,rcv=PIN_A1, STOP=1, BITS=8) // software rs-232
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SERIAL)
char buffer[256];
int b_in = 0;
int b_out = 0;
int b_n = 0;
#int_ext2
void ext2_irq(void) {
if (kbhit(GPS)) {
buffer[b_in] = fgetc(GPS);
b_in++;
b_n++;
}
}
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
ext_int_edge( 2, H_TO_L );
enable_interrupts(INT_EXT2);
enable_interrupts(GLOBAL);
while(1) {
if (b_n) {
fputc(buffer[b_out],SERIAL);
b_out++;
b_n--;
}
}
} |
|
Hello again, Gribas,
I tested both the codes but they didn't work, but I am sure they should had worked since they are right.
Anyway, after some more tests, I realized that even with the GPS disconnected from the circuit, the INT_EXT2 is triggered and enters in loop (triggered always). This may be the reason why the incoming GPS data has been corrupted.
The same problem occurs (INT_EXT2 triggering) when I connect the software USART to the PC.
I'm not sure, but I think that this INT_EXT2 triggering loop should not occur when there is no receiving signal.
Any idea?
Thank you |
|
|
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
|
Posted: Fri Mar 07, 2008 1:13 pm |
|
|
Douglas Kennedy wrote: | Most GPS units speak when they want. They also say what they want.
This means the PIC has to be able to receive any sentence at any time.
That means its best to have a circular buffer to capture a sentence. Now sentences are typically NMEA and will have some repeated info in the various sentences. Further not all sentences will have data since the GPS may not have the info yet or has lost the signal. Now to the circular buffer. The PIC has limited RAM and typically the PIC only needs to get data from one or more of the many sentences. The isr design should only allow the sentences you need to get into your isr's circular buffer. For example assume $GPRMC is the only sentence you need. Inside the isr only if the first 6 chars are $GPRMC does it get in. Set a state flag if the first char is $ move to state 1 if on the next interrupt the state flag is 1 and the char is G move to state 2 and so forth. If the state flag reaches 6 you have a sentence you need so let it into the buffer. After a complete sentence is received set a flag to let your main routine start parsing it. While your GPS speaks other sentences that you don't need your isr is rejecting them conserving RAM space and giving the PIC more time to parse before the next sentence arrives. Your buffer typically then holds the sentence you are currently decoding and just maybe ( a GPS leaves time between sentences) the next sentence starting to come in. |
Hello Douglas,
Your advices are great!
I'm going go use then as soon as I get my problem solved.
Thank you verry much,
rprodrigues |
|
|
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
|
Posted: Fri Mar 07, 2008 1:35 pm |
|
|
gribas wrote: | Here's an interrupt driven version.
Code: |
#include <18F2620.h>
#device adc=8
#FUSES NOWDT, WDT128, HS, NOPROTECT, NOIESO, NOBROWNOUT, BORV21, NOPUT, NOCPD,\
NOSTVREN,NOLVP,NOWRT,NOWRTD,NOEBTR,NOCPB,NOEBTRB,NOWRTC,NOWRTB,NOFCMEN,\
NOXINST,NOPBADEN,NOLPT1OSC,MCLR
#use delay(clock=20000000)
#use rs232(STREAM=GPS, baud=4800,parity=N,xmit=PIN_A0,rcv=PIN_A1, STOP=1, BITS=8) // software rs-232
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SERIAL)
char buffer[256];
int b_in = 0;
int b_out = 0;
int b_n = 0;
#int_ext2
void ext2_irq(void) {
if (kbhit(GPS)) {
buffer[b_in] = fgetc(GPS);
b_in++;
b_n++;
}
}
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
ext_int_edge( 2, H_TO_L );
enable_interrupts(INT_EXT2);
enable_interrupts(GLOBAL);
while(1) {
if (b_n) {
fputc(buffer[b_out],SERIAL);
b_out++;
b_n--;
}
}
} |
|
Gribas, PCM,
I did some more tests and I realized that the MAX232 output is really triggering the USART (software) ISR even when there is no signal to receive.
Should the max232 act that way or may be something wrong if it?
The same MAX232 IC has been used by the RS232 hardware interface and the related output also is noisily when there is no signal to receive, but there is no problem with the hardware USART. It works fine.
Any idea?
Thank you again |
|
|
gribas
Joined: 21 Feb 2008 Posts: 21
|
|
Posted: Tue Mar 11, 2008 1:12 pm |
|
|
rprodrigues wrote: |
Should the max232 act that way or may be something wrong if it?
|
It shouldn't oscillate when nothing is being transmitted. |
|
|
rprodrigues
Joined: 06 Mar 2008 Posts: 14
|
|
Posted: Wed Mar 12, 2008 3:53 pm |
|
|
gribas wrote: | rprodrigues wrote: |
Should the max232 act that way or may be something wrong if it?
|
It shouldn't oscillate when nothing is being transmitted. |
Hi, gribas,
Thank you very much for your help!
The problem was solved after I realized that I should had put a capacitor between the pins 2 and 6 of the MAX232 IC and after I wrote a bitbang USART for my application.
Regards,
rprodrigues |
|
|
|
|
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
|