PIC18f with GPS to the LCD, small issue--need help

Thread Starter

chillcat

Joined Jan 23, 2018
15
I have a pic18f4520, mplab xc8. Trying to find my problem, but no luck. So far I have Lat: and Lon: showing up on lcd, but no actual data. I was debugging earlier and had some small amount come in, but not the entire string. At this point I have just LAT: (line 1) LON: (line 2). Could someone look over my code and show me where I'm going wrong. It's located in the GetGpsdata after the $GPGGA string is filtered. thanks!!!
C:
#define _XTAL_FREQ 8000000 // subject to change

#include <stdint.h> // width values
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <string.h> // string readout data

void LCDinit(), LCDcmd(int unicorn), LCDstring(char *unicorn), LCDdata(int unicorn);

char LAT[15];
char LON[15];
char UART_Init(const long int baudrate);
#pragma config BOREN = ON,LVP = OFF,CPD = OFF,OSC = INTIO7


void LCDinit(){
LCDcmd(0x33); // 4b Mode
LCDcmd(0x32); // E
LCDcmd(0x2C); // 2-L mode
LCDcmd(0x0C); // Disp On,Curs Off,Blink On
LCDcmd(0x01);} // clear

void LCDcmd(int unicorn){ // LCD CMD 4-BIT, E(bit7),RS(bit4)
PORTD = 0; // E=0 RS=0
int temp = unicorn;
_delay(2000);
unicorn = ((unicorn >> 4) & 0x0F)|0x80; // E=1 RS=0, writes UPPER NIB to LCD: S.R. 4 bits, clears upper bits, bitmask
PORTD = unicorn, _delay(2000);
unicorn = unicorn & 0x0F; // E=0, preserve lower (lower nib is to be sent)
PORTD = unicorn, _delay(2000);
PORTD = 0; // E=0 RS=0
unicorn = temp;
unicorn = (unicorn & 0x0F)|0x80; // E=1 RS=0, writes LOWER NIB to LCD: clears upper bits, bitmask
PORTD = unicorn, _delay(2000);
unicorn = unicorn & 0x0F; // E=0, preserve lower (lower nib is to be sent)
PORTD = unicorn, _delay(2000);}

void LCDdata(int unicorn){ // LCD CMD 4-BIT, E(bit7),RS(bit4)
PORTD = 0; // E=0 RS=0
int temp = unicorn;
_delay(1000);
unicorn = ((unicorn >> 4) & 0x0F)|0x90; // E=1 RS=1, writes UPPER NIB to LCD: S.R. 4 bits, clears upper bits, bitmask
PORTD = unicorn, _delay(1000);
unicorn = (unicorn & 0x0F)|0x10; // E=0 RS=1, preserve lower (lower nib is to be sent)
PORTD = unicorn, _delay(1000);
PORTD = 0; // E=0 RS=0
unicorn = temp;
unicorn = (unicorn & 0x0F)|0x90; // E=1 RS=1, writes LOWER NIB to LCD: clears upper bits, bitmask
PORTD = unicorn, _delay(1000);
unicorn = (unicorn & 0x0F)|0x10; // E=0 RS=1, preserve lower (lower nib is to be sent)
PORTD = unicorn, _delay(1000);}

void LCDstring(char *unicorn){
int I = 0;
int temp;
int count = strlen(unicorn); // count = the length of the string john
while(I < count){ // While loop to determine the length of data for LCD string
temp = unicorn[I++]; // temp = part2LCD increment for the null value places
LCDdata(temp);}} // Move this final value to LCD data

char UART_Init(const long int baudrate){
unsigned int x;
x = (_XTAL_FREQ - baudrate*64)/(baudrate*64);
if(x>255){
x = (_XTAL_FREQ - baudrate*16)/(baudrate*16);
BRGH = 1;}
if(x<256) {
SPBRG = x;
SYNC = 0;
SPEN = 1;
TRISC7 = 1;
TRISC6 = 1;
CREN = 1;
TXEN = 1;
// LCDstring("ME ME ME");
return 1;}
return 0;}

char UART_Data_Ready(){
return RCIF;}

char UART_Read(){
while(!RCIF);
return RCREG;}

void UART_Read_Text(char *Output, unsigned int length){
int i;
for(int i=0;i<length;i++)
Output[i] = UART_Read();}

void GPS_GetDataAndDisplayIt(void){
int i;
i=0;
char Temp = 0, Index = 0;
while(!UART_Data_Ready());
Temp = UART_Read();
if (Temp == '$'){
while(!UART_Data_Ready());
Temp = UART_Read();
if (Temp == 'G'){
while(!UART_Data_Ready());
Temp = UART_Read();
if (Temp == 'P'){
while(!UART_Data_Ready());
Temp = UART_Read();
if (Temp == 'G'){
while(!UART_Data_Ready());
Temp = UART_Read();
if (Temp == 'G'){
while(!UART_Data_Ready());
Temp = UART_Read();
if (Temp == 'A'){
while(!UART_Data_Ready());
Temp = UART_Read(); // skipping ','
while(!UART_Data_Ready());
Temp = UART_Read();

while (Temp != ','){
while(!UART_Data_Ready());
Temp = UART_Read();
i ++;}
i = 0;
LCDcmd(0x01),LCDstring("LAT:"); // cursor to 1st line with message
while(!UART_Data_Ready());
Temp = UART_Read();
while (Temp != ','){
LAT[i] = Temp;
LCDstring(Temp); // Displaying latitude on LCD
while(!UART_Data_Ready());
Temp = UART_Read();
i ++;
if (i == 2){
LCDstring("°"); // Displaying degree sign
LAT[i] = Temp;}}
i = 0;
while(!UART_Data_Ready());
Temp = UART_Read();
LCDstring(' ');
LCDstring(Temp); // Display Direction on LCD
LCDcmd(0xC0),LCDstring("LON:"); // cursor to 2nd line with message
while(!UART_Data_Ready());
Temp =UART_Read();
while(!UART_Data_Ready());
Temp = UART_Read();
while (Temp != ','){
LCDstring(Temp); // Display Longitude on LCD
LON[i] = Temp;
while(!UART_Data_Ready());
Temp = UART_Read();
i ++;
if (i == 3){
LCDstring("°"); // Displaying degree sign
LON[i] = Temp;}}




while(!UART_Data_Ready());
Temp = UART_Read(); // Skip ','

while(!UART_Data_Ready());
Temp = UART_Read(); // Skip ','

while(!UART_Data_Ready());
Temp = UART_Read(); // Skip ','

while(!UART_Data_Ready());
Temp = UART_Read(); // Skip ','

while(!UART_Data_Ready());
Temp = UART_Read(); // Skip ','

while(Temp != ','){
while(!UART_Data_Ready());
Temp = UART_Read();
// LCDdata(Temp);
}
}}}}}}}

int main(void) {
OSCCON = 0x76; // Sets internal oscillator to 8MHz

TRISA = 0b11111110;
TRISD = 0x00;
TRISC = 0b11111111; // GPS(RC7)

LCDinit();
LCDcmd(0x01);
UART_Init(9600);

while(1){

PORTAbits.RA0 = 1;
// PORTAbits.RA0 = 0, _delay(1000);
GPS_GetDataAndDisplayIt();
_delay(1000);
//LCDcmd(0x80),LCDstring("hello TED"),LCDcmd(0xC0),LCDstring("Lat: 148.0000"),LCDcmd(0x94),LCDstring("LON: anything"),LCDcmd(0xD4),LCDstring("Anything");

}
return 0;
}
Mod edit: code tags
 

Attachments

Last edited by a moderator:

spinnaker

Joined Oct 29, 2009
7,815
You need to break your code up into much smaller pieces then build from there.

Forget about the display for now. Write a small program that does nothing but query the GPS and get the data. Once you have that you can move on.
 

spinnaker

Joined Oct 29, 2009
7,815
And you code is very confusing. It looks to me like you are reading a character at a time then testing if it is a valid character. Forget about all of that. Read in a whole string at once then check if it is valid. You could then use strcmp to see if it is the string you want as opposed to checking character by character. I assume this is NEMA. It has been a while but doesn't the string contain a CRC byte?
 

ericgibbs

Joined Jan 29, 2010
8,744
hi chill,
I agree with @spinnaker , get the complete string, then parse out the Lat,Long and Alt values.
I test for the $ at the message start, then the 'G' in the 5th position, to pick out the GPGGA message.
You can then parse out the values you want by using the 'commas', counting from the string start.

I find loading all the GPGGA string characters into buffer array works for me,

E
 

Picbuster

Joined Dec 2, 2013
982
Use interrupt to read the header ($GPGGA) set flag
Then read port the whole message till terminator (cr or lf). ( Received_Buffer)
Disable read port.
Break Received_Buffer into the fields you need.
When received in decimal format ==> calculate to the correct lat and long in hexagesimal format. (base 60)
print @ display
do some other things
Enable read port.

Picbuster
 

MMcLaren

Joined Feb 14, 2010
842
Processing a single character at a time from the GPS works fine, too. The pseudo C code example below simply copies each character from a qualified 'sentence' to the LCD but you could just as easily save the characters into a string array (no parsing necessary).

There may be a performance advantage when processing a character-at-a-time instead of bunching up all of the processing after capturing an entire 'sentence'. Take advantage of that ~1-ms between characters (9600 baud) to distribute processing across the entire GPS 'sentence' instead of at the end of 'sentence'.

Regards, Mike

Code:
;
;  #define line1   128+0           // line 1 tab 0 'ddram' address
;  #define line2   128+64          // line 2 tab 0 'ddram' address
;  #define line3   128+20          // line 3 tab 0 'ddram' address
;  #define line4   128+84          // line 4 tab 0 'ddram' address
;
;  const rom char hdr[] = { "GPRMC" };
;  const rom char tab[] = { line1 + 5,      // HDR: ^
;                           line2 + 5,      // UTC: ^
;                           line1 + 18,     // FIX: ^
;                           line3 + 6,      // LAT: ^
;                           line3 + 16,     // cardinal char
;                           line4 + 5,      // LON: ^
;                           line4 + 16,     // cardinal char
;                           line1 + 5 };    // wrap
;
;  #define parser (field <= 6)  // parser on (1) or off (0)
;
;  void main()
;  { initmcu();                     // setup uC ports
;    initlcd();                     // initialize 4x20 LCD
;
;    while(1)                       //
;    { data = Get232();             // get gps character
;      if(data == '$')              // if new 'sentence'
;      { field = 0; ndx = 0;        // reset field and index
;        putcmd(tab[field]);        // set lcd 'ddram' address
;      }                            //
;      else                         // not new sentence, so
;      { if(parser)                 // if parser 'on'
;        { if(data == ',')          // if new field
;          { field++; ndx = 0;      // bump field, reset index
;            putcmd(tab[field]);    // set lcd 'ddram' address
;          }                        //
;          else                     // not new field
;          { if(field == 0)         // if header field
;            { if(data!=hdr[ndx])   // if not "GPRMC"
;                field |= 8;        // turn parser off
;            }                      //
;            putdat(data);          // print char to lcd
;            ndx++;                 // bump field index
;          }                        //
;        }                          //
;      }                            //
;    }                              //
;  }                                //
;
GPS Monitor.png
 
Last edited:

MMcLaren

Joined Feb 14, 2010
842
Is anyone up to the task of showing us a "state machine" example for the logic in that character-at-a-time example pseudo code in the previous post? It might be simpler and easier to understand as well as providing a relatively simple way to build a string variable for fields you may want to keep between updates.

Cheerful regards, Mike
 
Last edited:

spinnaker

Joined Oct 29, 2009
7,815
Sorry it took me awhile to check back, I've been working so hard on this. Ok I implemented the strmp and arranged the data in buffer array. Hoping I did this correct. Something is not correct in my variable count (integer) because my lcd data is wacky.

It isn't the data that is wacky. It is your code that is wacky.

Use your debuggers, step through the code and try to figure our where it is going wrong. It is what every embedded developer does when things don't go as desired.
 

Thread Starter

chillcat

Joined Jan 23, 2018
15
I feel like i've run out of debugging options, lol. I'm just at the point I'll compensate someone's time, too much time put into this. I don't do this for a living.
 

spinnaker

Joined Oct 29, 2009
7,815
I feel like i've run out of debugging options
.
No such thing. My suspicion, you really haven't even got started.

I'm just at the point I'll compensate someone's time, too much time put into this.
It isn't any fun if someone does it for you. Having someone do it for you would be difficult. You would need to send them all of the hardware.

I don't do this for a living.
[/QUOTE]

Neither do I or many of the people on this forum.
 

Thread Starter

chillcat

Joined Jan 23, 2018
15
Well I put my debugging skills to work and eventually found the problem. I thought I was filtering out $GPRMC properly, was not. So my data reading out was pieces from 1 of the many $ strings available. lol. I just have to restructure my strcmp.
 

Thread Starter

chillcat

Joined Jan 23, 2018
15
Spinnaker, so I have my gps all finished, now I need to add a gsm to the controller, can you recommend an inexpensive one ? Something that will work in the US. Apparently the one I bought does not nor did it come with a manual nor can I find any documentation online, very weird.

I think the manuf is Reland Tech. Can't even wire it up with pinout sheet.
 

Attachments

Picbuster

Joined Dec 2, 2013
982
Careful; Sim 900 series are obsolete.
I used Sim900b with the mounted sim cardholder.
AT set working fine used it for raw position, sms, ftp and e-mail but it needs a sw update and the correct hardware level to do mail and ftp.
However setting up a tcp/ip connection is slow.

Connectors / pinning differ for later types implies: PCB modification mandatory.

Picbuster
 

Picbuster

Joined Dec 2, 2013
982
NO mechanical replacement or mounted Sim card holder.
SIM800H S2-1065N-Z142F select the correct software level this is always a problem with Simcom.
it's 18 x 16 mm approx.
I am looking into making a pcb with 800H and simcard holder which fit the 900 connector producing a convertor pcb.
Allowing the usage of 800H and 900b
When modified it carry a short haul modem in stead of the SIm800


Picbuster
 
Top