|
|
View previous topic :: View next topic |
Author |
Message |
talhahs
Joined: 14 Oct 2010 Posts: 14
|
GPS code help, PIC 16F877A |
Posted: Mon Mar 07, 2011 9:09 am |
|
|
Hi guys,
I have a Garmin consumer GPS that works at a baud rate of 4800 bps. There is no problem in getting the sentences when running on hyperterminal, PC<>GPS; But when i try to recive them using controller i just get garbage serial characters.
Since it is a consumer GPS that connects directly to PC (works on RS-232 levels), i have used MAX 232 (fully functional) to connect HW USART to GPS.
Here is the code i am using, kindly help.
Code: |
#include "D:\GPS\gps.h"
#include <stdlib.h>
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=20000000)
#use rs232(baud=4800,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=GPS) //hardware USART
#use rs232(baud=4800,parity=N,xmit=PIN_D6,rcv=PIN_D7,bits=8,invert,stream=PC) //software USART
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
output_high(PIN_B7); //flag LED
char gps_str[60]; //full sentence
char temp_str[10];
char lat_float[10];
char log_float[10];
char alt_float[10];
char rcv_chr;
int count;
fprintf(PC,"GPS code about to start::: \r\n");
if(kbhit(GPS))
rcv_chr=fgetc(GPS);
if (rcv_chr=='$'){
rcv_chr=fgetc(GPS);
if (rcv_chr=='G'){
rcv_chr=fgetc(GPS);
if (rcv_chr=='P'){
rcv_chr=fgetc(GPS);
if (rcv_chr=='G'){
rcv_chr=fgetc(GPS);
if (rcv_chr=='G'){
rcv_chr=fgetc(GPS);
if (rcv_chr=='A'){
rcv_chr=fgetc(GPS);
if (rcv_chr==','){
for (count=0;count<60;count++){
gps_str[count]=fgetc(GPS);
}
output_high(PIN_B7);
for (count=0;count<7;count++){
temp_str[count]=gps_str[13+count];
}
lat_float=atof(temp_str);
for (count=0;count<7;count++){
temp_str[count]=gps_str[26+count];
}
log_float=atof(temp_str);
for (count=0;count<7;count++){
temp_str[count]=gps_str[45+count];
}
alt_float=atof(temp_str);
}
}
}
}
}
}
}
fprintf(PC,"Latitude , = ");
for (count=0;count<10;count++){
fprintf(PC,lat_float[count]);
}
fprintf(PC,"\r\n");
fprintf(PC,"Longitutde , = ");
for (count=0;count<10;count++){
fprintf(PC,log_float[count]);
}
fprintf(PC,"\r\n");
fprintf(PC,"Altitude , = ");
for (count=0;count<10;count++){
fprintf(PC, alt_float[count]);
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Mon Mar 07, 2011 9:26 am |
|
|
So describe your connection to the PC from the PIC?. Just using 'invert', is not enough, though _may_ just about give a useable connection, to send data, depending on the buffering on the PC...
Some further comments:
1) Add 'ERRORS' to your GPS stream definition. Since you have long periods when the RS232 won't be receiving (when it is calculating, and sending data to the PC), without this, the UART _will_ get hung.
2) Change the setup_spi definition, to setup_spe(FALSE). SPI_SS_DISABLED, actually enables the port.....
3) Switch to defining your variables at the start of the code blocks. This is a _requirement_ in standard C, and though CCS, partially accepts the C++ layout with variables inline, it also leads to code errors, which can be a pig to track down. Keep to the standard syntax to avoid this.
4) Think about your code. There is nothing to say that the 'sentence is about to start'. Depending on how long the PIC takes to get to the first kbhit, you could be 'mid sentence'. You check for the '$', but should really keep looking till you find this. You also need to null terminate the strings before you call atof.
Best Wishes |
|
|
talhahs
Joined: 14 Oct 2010 Posts: 14
|
|
Posted: Mon Mar 07, 2011 9:30 am |
|
|
these are the sentences GPS sends every second or so. (all at once)
$GPRMC,,V,,,,,,,061210,0.0,E,N*3C
$GPRMB,V,,,,,,,,,,,,A,N*13
$GPGGA,121505,2485801,N,06726585,E,1,08,0,9,133.4,M,46.9,M,,*42
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,12,02,08,067,00,05,37,039,00,12,28,178,00,15,28,143,00*77
$GPGLL,,,,,,V,N*64
$GPBOD,,T,,M,,*47
$GPVTG,,T,,M,,N,,K*4E
$PGRME,,M,,M,,M*00
$PGRMZ,,f,1*29
$PGRMM,Dutch*27
$GPRTE,1,1,c,*37 |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Mar 07, 2011 12:24 pm |
|
|
Hi,
A couple of additional thoughts.
You might review which NMEA messages contain the data you actually want/need, and then turn all the other messages off. Most GPS receives can be configured to send only the data you want. This will help to free machine cycles for processing the data you want.
Realistically, you may only be happy with what you are trying to do once you implement an interrupt driven serial buffering scheme using a circular buffer. Believe me that I worked mightily to avoid using this technique (believing that the implementation was difficult) before succumbing, and just doing it. With this technique, each time a new character is received from the GPS, it's stuffed into a circular buffer (a buffer that "wraps around" when reaching the end). This happens automatically, leaving your main program to process the buffer contents. You simply need to look for the start character ('$'), and the end character ('CR'), and process everything in the middle. You can further refine your interrupt handler with a state machine to only buffer characters associated with the desired NMEA strings.
The example program EX_SISR.c will get you started on this technique.
John |
|
|
talhahs
Joined: 14 Oct 2010 Posts: 14
|
|
Posted: Mon Mar 07, 2011 1:48 pm |
|
|
Thanks guys
Well, John you are right, I would ultimately have to move to implementing interrupts. This is because I am building code for rover that moves in all directions, rotates camera using servo and GPS is just part of it. I cant hang my control waiting for GPS sentences. Therefore, using interrrupt #int_rda is a good idea.
Secondly my Garmin etrex GPS doesn't provide option to send only GPGGA sentence, it sends all NMEA sentences mentioned above at once. What i can do is to shift to some easier protocol that this GPS is offering like simple text for latitude and longitude only.
Have you got any idea how do i extract required GPGGA from others when they are placed in circular queue as in EX_SISR.c |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Mar 07, 2011 2:05 pm |
|
|
Hi,
You might want to consider using a GPS "engine", rather than the eTrex unit. A number of good modules can be found at Sparkfun.com for around $50 USD. These modules typically have TTL interfaces, and the NMEA data stream can be configured.......
To exclude all but the desired string from your circular buffer, you can implement a "state machine" in your serial interrupt handler. It starts with a State = 0, and stores no characters in this state. Once the '$' character is received, this character is stored, and then State is incremented. With State = 1, the next character must be a 'G', and if so, the character is stored, and the state is incremented. With State = 2, the next character must be a 'P', and if so, the character is stored, and the state is incremented. If at anytime, you don't have a match, reset State = 0. Keep doing this until you have enough of the NMEA string to ensure you've got the correct one. At that State value, just store all the incoming characters until the 'CR' character is received, and then start all over.
You'll learn a lot more if you code it yourself, but here is a small code fragment from my ISR to get you going:
Code: |
TempChar = fgetc(GPS);
switch (RxState)
{
Case 0:
if (TempChar == '$')
RxState++; //"$" received, so RxState = 1
break;
Case 1:
if (TempChar == 'G')
RxState++; //"G" received, so RxState = 2
else
RxState=0; //wrong character received, so we reset RxState
break;
|
John |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Mar 07, 2011 6:53 pm |
|
|
Oh gosh - yes. ISR is a must. I've done several GPS projects now and I can't emphasize enough...
Using an ISR to collect the serial stream is the way to go.
If all you have is the eTrex, then have at it - I don't think you NEED to go out and buy a specific GPS if the one you have puts out NMEA.
So far, I've coded against the following models:
Garmin GPS16/17
Garmin GPS296
DeLorme GPS2058
No problems.
The config strings might be different.. but the rest is the same.
Cheers,
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Mar 07, 2011 7:50 pm |
|
|
Hi Ben,
Was the project using the GPS296 aviation related??
John |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Mar 07, 2011 7:56 pm |
|
|
ezflyr wrote: | Hi Ben,
Was the project using the GPS296 aviation related??
|
Yes -- Why? _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Mar 07, 2011 8:09 pm |
|
|
Ben,
Oh, I'm a pilot and aviation junkie and your reference to the GPS296 caught my eye.
What was the project?
John |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Mar 07, 2011 8:15 pm |
|
|
ezflyr wrote: | Ben,
Oh, I'm a pilot and aviation junkie and your reference to the GPS296 caught my eye.
What was the project?
|
I wanted to make an auxilary display for some of the NMEA information that spews out of the 296.
I'm also a pilot. It's for my Grumman AA1B...
I need to finish putting it in a case and install it... When I have something to show for, I'll post pictures of what it is and what it does.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Mar 07, 2011 8:22 pm |
|
|
Hi Ben,
Great stuff, I'm definitely interested!
I fly a Beech A-36 Bonanza, but my GPS project is for my other passion, R/C modeling. I'm making an airborne telemetry and autonomous control system for one of my models.
John |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Tue Mar 08, 2011 12:54 am |
|
|
ezflyr wrote: | Hi Ben,
Great stuff, I'm definitely interested!
I fly a Beech A-36 Bonanza, but my GPS project is for my other passion, R/C modeling. I'm making an airborne telemetry and autonomous control system for one of my models.
|
I'll keep you posted when it's finally complete...
A-36 -- fun! I've been in those... Especially the drop-down speed brakes. ;)
However, the AA-1's with o320's are hard to beat on the cheap vs. fun factor. If I had all the cash in the world, I'd still fly an AA-1. They're a blast.
Cheers,
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
talhahs
Joined: 14 Oct 2010 Posts: 14
|
|
Posted: Tue Mar 08, 2011 8:23 am |
|
|
Ben and John,
Kindly be informed this forum is not for your supersonic aircrafts discussion, I started this thread for my surveillance rover GPS
http://www.lynxmotion.com/c-111-no-electronics-kit.aspx
Well, one question has sprung up in my mind.
The rover performs differential drive in real time as instructed my VB application.
so the code is of this type
Code: |
#define H bridge pins
void forward(int speed)
{
code;
}
void backward(int speed)
{
code;
}
void left(int speed)
{
code;
void right(int speed)
{
code;
}
void reset()
{
code;
}
void main()
{
char cmd;
do{
if(kbhit())
{ cmd=getch();
output_high(LED);
switch (cmd)
{
case 'q': //backward 100% speed
code;
break;
case 'w': //backward 75% speed
code;
break;
case 'e': //backward 50% speed
code;
break;
case 'r': //backward 25% speed
code;
break;
case 't': //backward low speed
code;
break;
case 'z': //forward 100% speed
code;
break;
.
.
.
.
.
code continues;
.
.
.
.
}
output_low(LED2);
} while(1) ;
}
|
So, in this sort of code when I have to integrate GPS, the MCU might be busy getting GPS sentences via interrupt, while the user might be pressing keys for the rover to move, the MCU control wont be in switch case statement, so how can GPS be integrated?.. Kindly guide me.. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Tue Mar 08, 2011 9:32 am |
|
|
Hi talhahs,
Yeah, sorry for the "off frequency" chatter, I guess I got carried away !
I think you need to take a step-by-step approach to this project rather than jumping ahead. You are right, integrating other tasks into your code will be a challenge, and it's good to consider everything from the outset, but I think your 1st priority should be to establish rock solid reception from your GPS.
Is this going to be an autonomous robot, or one that is remote controlled? If it's remotely controlled, what is the purpose of the GPS?
If you plan to integrate something like an Xbee module for command/control, you'll have to use a 2nd serial port. If the data packets are small, and (relatively) infrequent, you can probably get away with using a software serial port for this purpose. I'd connect it to input B0 and use the INT_EXT interrupt. As always the devil is in the details of your project!
John |
|
|
|
|
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
|