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

PIC18F2620 + GPS: Software rs232 problem (solved)

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



Joined: 06 Mar 2008
Posts: 14

View user's profile Send private message

PIC18F2620 + GPS: Software rs232 problem (solved)
PostPosted: Thu Mar 06, 2008 11:51 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 06, 2008 12:36 pm     Reply with quote

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








PostPosted: Thu Mar 06, 2008 1:30 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 06, 2008 1:48 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 06, 2008 2:01 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 06, 2008 2:19 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 06, 2008 2:35 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 07, 2008 5:28 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Fri Mar 07, 2008 5:39 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 07, 2008 5:56 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 07, 2008 12:25 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 07, 2008 1:13 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 07, 2008 1:35 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Mar 11, 2008 1:12 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 12, 2008 3:53 pm     Reply with quote

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
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