|
|
View previous topic :: View next topic |
Author |
Message |
analog_world
Joined: 16 Sep 2008 Posts: 26
|
Problem with GPS parsing |
Posted: Fri Sep 26, 2008 1:31 pm |
|
|
I have written this sample code to read in gps data and parse it. However, since I do not have a GPS yet, I did not include any code to take in data from the USART. So, I just created my own array of sample gps strings that will be parsed. When I compiled the file for pic 16f877a, it gives me an error saying "not enough ram for variables". I am confused as to how can I make this program more effective. Also, how can I view my results in CCS PIC (for ex: the conventional C compiler have an output window to view results instantaneously. Does CCS C have any capability to view the results on a window immediately). I would really appreciate help with this. Here is the code I wrote.
Code: |
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlibm.h>
#include <string.h>
typedef struct _GPRMC
{
char validity;
float latitude;
char latitudeDir;
float longitude;
char longitudeDir;
} GPRMC;
int hex2dec(char c);
int readGpsStr();
int parseGPRMC(char* inGpsStr, GPRMC* gprmc);
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define TEST_MODE 1
#ifdef TEST_MODE
char* inGpsStrArray[] =
{
"$GPZDA,033243.841,08,09,2008,00,00*55",
"$GPGGA,033243.841,0000.000000,N,00000.000000,E,1,0,0,0,M,0,M,,*4A",
"$GPGLL,0000.000000,N,00000.000000,E,033243.841,A,A*51",
"$GPVTG,0,T,0,M,0,N,0,K,A*23",
"$GPRMC,033243.841,A,0000.000000,N,00000.000000,E,0,0,080908,0,E,A*1A",
"$GPGSA,A,3,,,,,,,,,,,,,0,0,0*2C",
"$GPRTE,1,1,C,0,*0B",
""
};
int8 inGpsStrArrayIndex = 0;
#endif
int main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
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);
while (inGpsStrArrayIndex > 0)
readGpsStr();
return 0;
}
char* getStr(char* inGpsStr, int len)
{
#ifdef TEST_MODE
inGpsStr = inGpsStrArray[inGpsStrArrayIndex];
++inGpsStrArrayIndex;
if ((inGpsStrArray[inGpsStrArrayIndex])[0] == '\0')
inGpsStrArrayIndex = -1;
#else
gets(inGpsStr);
#endif
return inGpsStr;
}
int hex2dec(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return 10 + (c - 'A');
if (c >= 'a' && c <= 'f')
return 10 + (c - 'a');
return -1;
}
int verifyChecksum(char* str)
{
int calcChecksum = 0;
int readChecksum = 0;
int i, c1, c2;
for (i = 1; str[i] != '\0'; ++i)
{
if (str[i] == '*')
break;
calcChecksum ^= str[i];
}
if (str[i+1] == '\0' || str[i+2] == '\0')
return FALSE;
c1 = hex2dec(str[i+1]);
c2 = hex2dec(str[i+2]);
if (c1 == -1 || c2 == -1)
return FALSE;
readChecksum = (c1 << 4) + c2;
if (calcChecksum != readChecksum)
{
printf("checksum failed for %s\n", str);
}
else
{
printf("checksum is valid: %x\n", readChecksum);
}
return TRUE;
}
int readGpsStr()
{
char inGpsStr[100];
char tmpGpsStr[sizeof(inGpsStr)];
char* tmpGpsStrPtr = NULL;
char* nextToken;
GPRMC gprmc;
int result;
char* delimitter = ",";
while (1)
{
tmpGpsStrPtr = getStr(tmpGpsStr, sizeof(tmpGpsStr));
if (tmpGpsStrPtr == NULL)
continue;
// Save the read string as strtok modifies tmpGpsStr
strcpy(inGpsStr, tmpGpsStr);
printf("Read: %s", inGpsStr);
/*
* $GPRMC,033244.885,A,0000.016667,N,00000.016667,E,0,0,080908,0,E,A*15
*/
nextToken = strtok(tmpGpsStr, delimitter);
if (nextToken == NULL)
continue;
if (strcmp(nextToken, (char*)"$GPRMC") == 0)
{
if (!verifyChecksum(inGpsStr))
continue;
result = parseGPRMC(inGpsStr, &gprmc);
if (result == FALSE)
continue;
printf("%c,%f,%c,%f,%c\n", gprmc.validity, gprmc.latitude,
gprmc.latitudeDir,gprmc.longitude, gprmc.longitudeDir);
return TRUE;
}
if (strcmp(nextToken, (char*)"$GPGLL") == 0)
{
continue;
}
}
}
int parseGPRMC(char* inGpsStr, GPRMC* gprmc)
{
/*
* $GPRMC,033244.885,A,0000.016667,N,00000.016667,E,0,0,080908,0,E,A*15
*/
char* nextToken;
// time
nextToken = strtok(NULL, (char*)",");
if (nextToken == NULL)
return FALSE;
// A
nextToken = strtok(NULL, (char*)",");
if (nextToken == NULL)
return FALSE;
if (strcmp(nextToken, (char*)"A") != 0)
return FALSE;
gprmc->validity = nextToken[0];
nextToken = strtok(NULL, (char*)",");
if (nextToken == NULL)
return FALSE;
gprmc->latitude = (float)atof(nextToken);
nextToken = strtok(NULL, (char*)",");
if (nextToken == NULL)
return FALSE;
gprmc->latitudeDir = nextToken[0];
nextToken = strtok(NULL, (char*)",");
if (nextToken == NULL)
return FALSE;
gprmc->longitude = (float)atof(nextToken);
nextToken = strtok(NULL, (char*)",");
if (nextToken == NULL)
return FALSE;
gprmc->longitudeDir = nextToken[0];
nextToken = strtok(NULL, (char*)"*");
return TRUE;
} |
Last edited by analog_world on Tue Oct 21, 2008 2:15 am; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 26, 2008 2:05 pm |
|
|
The largest RAM array size for that PIC is 96 bytes.
I suggest that you make one small GPS string for your tests.
See if you can parse that one string.
Also, I assume you've got the #device *=16 statement in your program,
which allows the use of all RAM in the 16F series PICs. Example:
Quote: | #include <16F877A.H>
#device *=16
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS) |
|
|
|
analog_world
Joined: 16 Sep 2008 Posts: 26
|
|
Posted: Fri Sep 26, 2008 2:24 pm |
|
|
Hi,
that was helpful. I can compile, but how do I know if it is parsing it right. I was wondering how can I view if the variables are correctly storing the parsed values. Also, when I am reading in GPS data, How is that data stored in the PIC to be read by my program. Since the GPS will be refreshing constantly every second, should it be read as strings or characters. And Where is the location that I need to read these strings or characters from. (The GPS is connected to the serial USART port)
Thank you so much for your help. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 26, 2008 2:50 pm |
|
|
If you're parsing the sub-strings into smaller arrays, you can use
printf to display the smaller strings.
You should do a search for GPS code on this forum.
Use this search string:
That will find most of the code examples.
http://www.ccsinfo.com/forum/search.php |
|
|
analog_world
Joined: 16 Sep 2008 Posts: 26
|
|
Posted: Fri Sep 26, 2008 3:00 pm |
|
|
Thank you so much for your help. I am indeed using Printf to display the parsed string and the individual components extracted such as lat, long..etc. My only question was how can I view this output? Because since the program compiles, where is the option in CCS to view the output of printf. Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 26, 2008 3:18 pm |
|
|
Are you running this program on a board ? If so, connect the RS-232
output to the COM port on the back of your PC. Then view it on a
terminal program, such as HyperTerminal or SIOW (the CCS terminal
program). |
|
|
analog_world
Joined: 16 Sep 2008 Posts: 26
|
|
Posted: Fri Oct 03, 2008 12:25 am |
|
|
Hi,
When I used the above program with the 18F4550, it compiled. I did use your suggestion of reducing the array size by just using one string. However, the size of my hex file was 16KB!!!. I guess the only reason the program compiled was because of the generous memory on the 18 series. When I tried recompiling using the 16F877A, it still keeps telling me that there isn't enough RAM for variables. Do you think this is because I am using the String functions such as Strtok. I do not see why it is not working. Do you think I should just write my own string functions instead of linking the C libraries as it would link all the functions of the string library thereby consuming too much memory. Or am I just doing it wrong. I really appreciate help with this. Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 03, 2008 1:13 am |
|
|
The 18F4550 has over 5x more RAM than the 16F877A. Also, the
16F PIC has its RAM segmented into pages. An array can't be larger
than the size of one page. This will be 96 bytes or less. For large
projects, it's recommended that you use the 18F PICs. Then you don't
have these limitations. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Oct 03, 2008 8:30 am |
|
|
If you don't have a GPS receiver to play with yet you can simply have a PIC transmit a few sentences each second to similate a receiver. Your receiving PIC could try to massage the data coming in and you could sort of debug your code that way.
Ronald |
|
|
|
|
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
|