GPS EB-056 with Flowcode v3

Tips, Tricks and methods for programming, learn ways of making your programming life easier, and share your knowledge with others.

Moderators: Benj, Mods

Spanish_dude
Posts: 594
Joined: Thu Sep 17, 2009 7:52 am
Location: Belgium
Has thanked: 63 times
Been thanked: 102 times
Contact:

GPS EB-056 with Flowcode v3

Postby Spanish_dude » Thu Nov 11, 2010 2:16 am

Hi everyone,

As you might know, there's no GPS component in Flowcode v3 and I have the GPS E-Block.

So, I came up with this program that will allow you to use the GPS with Flowcode v3.
It is a bit based on the PIC_GPS.c code from v4 and it uses the RS232 (UART/USART) component, with a baudrate of 9600.

Note: If you want to change the baudrate you'll need to go to the properties of the RS232 component.
But it's already set at 9600 by default.

The program I'll explain later on this page is made for a 16F877A with a 4MHz oscillator.
The GPS is connected to PORTC, LCD (2x16) on PORTB.
The jumper J4 (C) needs to be set on the GPS E-Block and also the jumper J7 on position 3.

I'd like to thank Benj for helping me with some problems I had.

What you need to know:
The GPS uses NMEA protocol with UART/USART to send the data to the microcontroller.
The data sent by the GPS always begins with a different sentence.
The supported/programmed "sentences" are "GGA", "GSV" and "RMC".

Each data is separated by a ','.
Ex.: $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
(123519 is UTC Time, 4807.038 is latitude, North, 01131.000 is longitude, East, ...)

"GGA" is used for the altitude, ...
"GSV" is used to know how much satellites are in view, ...
"RMC" is used for UTC time, UTC date, latitude, longitude, ground speed in knots, course angle, ... (and data validity).

Note: The program does not convert the data to integers or bytes, it returns the string of data that you'll ask him.
Ex.:

Code: Select all

//pseudocode

if sentence is RMC then
    output = GPS_ReturnData(1);

This example will give you the UTC time but not like this HH:MM:SS(.MMM).
It will return the data as received from the GPS: HHMMSS.MMM. (=> MMM : milliseconds)

So, you'll need to edit the output buffer if you want the time to be displayed like HH:MM:SS(.MMM) or something else.

For more information about NMEA see links below:
- http://www.gpsinformation.org/dale/nmea.htm
- http://aprs.gids.nl/nmea/
- http://www.codepedia.com/1/NMEA+Reference+Guide

What does this program ?
This program will print the latitude and longitude on the 2x16 LCD screen.
It can be easily changed !

Let's start explaining the code:
First, I want to tell you that the code you'll see is not the original code generated by Flowcode.
I did remove the comments from Flowcode, the LCD and RS232 functions.
I did minor changes on the code and code that has been added by Flowcode has been removed (like setting the A/D or I/O registers and stuff like that).
The code shown won't compile !
Download the GPS.fcf file for the "full" code ;).


Prototypes of the 3 functions I made:

Code: Select all

void FCM_GPS_ReceiveData();
char FCM_GPS_DataSentence();
void FCM_GPS_ReturnData(char* FCR_RETVAL, char FCL_DATA);

See below.


Global Variables:

Code: Select all

#define FCSZ_OUTPUT 16
#define FCSZ_RECEIVE_BUFFER 80
char FCV_OUTPUT[FCSZ_OUTPUT];         // output[16]
char FCV_SENTENCE;            // sentence
char FCV_RECEIVE_BUFFER[FCSZ_RECEIVE_BUFFER];    // receive_buffer[80]
char FCV_EXIT;               // exit

- FCV_EXIT (byte) : is used to end the program.
- FCV_SENTENCE(byte) : is used to know which data has been received (either $GPGGA or $GPGSV or $GPRMC).
- FCV_OUTPUT[16] (string) : is used as display buffer for the LCD.
- FCV_REcEIVE_BUFFER[80] (string) : is used to "save" the data received from the GPS.


The main function :

Code: Select all

void main()
{
   FCV_SENTENCE = 0;
   FCV_EXIT = 0;

   // 500 ms delay
   delay_ms(255);
   delay_ms(245);

   FCD_LCDDisplay0_Start();
   FCD_LCDDisplay0_Clear();

The main function starts by setting exit, sentence and output to 0.
Then a 500 ms delay to give the LCD some time to startup.
Then the start and clear macro for the LCD.

Code: Select all

   while (FCV_EXIT == 0)
   {

We enter the main loop.
This loop will be executed if FCV_EXIT equals 0.

Code: Select all

      // Receive data string
      FCM_GPS_ReceiveData();
      // Detect received sentence [returns 1 - 3 or 255]
      FCV_SENTENCE = FCM_GPS_DataSentence();

FCM_GPS_ReceiveData();
This function is used to receive data from the GPS and to store it in the receive_buffer string.

FCM_GPS_DataSentence();
This one is used to detect which string of data we received.
It returns a number from 1 to 3 if the sentence is valid ("GGA", "GSV" and "RMC").
If not, it returns 255.

Code: Select all

      // Setting output to 0
      FCV_OUTPUT[0] = 0;
      FCV_OUTPUT[1] = 0;
      FCV_OUTPUT[2] = 0;
      FCV_OUTPUT[3] = 0;
      FCV_OUTPUT[4] = 0;
      FCV_OUTPUT[5] = 0;
      FCV_OUTPUT[6] = 0;
      FCV_OUTPUT[7] = 0;
      FCV_OUTPUT[8] = 0;
      FCV_OUTPUT[9] = 0;
      FCV_OUTPUT[10] = 0;
      FCV_OUTPUT[11] = 0;
      FCV_OUTPUT[12] = 0;
      FCV_OUTPUT[13] = 0;
      FCV_OUTPUT[14] = 0;
      FCV_OUTPUT[15] = 0;

Setting the display buffer to 0.
Note: I didn't want to use a for loop, so I did it one by one.

Code: Select all

      // if Sentence is GGA
      if (FCV_SENTENCE == 1)
      {
      }
      // if Sentence is GSV
      else if (FCV_SENTENCE == 2)
      {
      }
      // if Sentence is RMC
      else if (FCV_SENTENCE == 3)
      {
         //Latitude ($GPRMC -> n° 3)
         FCM_GPS_ReturnData(FCV_OUTPUT, 3);
         // Printing Latitude
         FCD_LCDDisplay0_PrintString(FCV_OUTPUT, FCSZ_OUTPUT);
         FCD_LCDDisplay0_Cursor(0, 1);

         // Setting output to 0
         FCV_OUTPUT[0] = 0;
         FCV_OUTPUT[1] = 0;
         FCV_OUTPUT[2] = 0;
         FCV_OUTPUT[3] = 0;
         FCV_OUTPUT[4] = 0;
         FCV_OUTPUT[5] = 0;
         FCV_OUTPUT[6] = 0;
         FCV_OUTPUT[7] = 0;
         FCV_OUTPUT[8] = 0;
         FCV_OUTPUT[9] = 0;
         FCV_OUTPUT[10] = 0;
         FCV_OUTPUT[11] = 0;
         FCV_OUTPUT[12] = 0;
         FCV_OUTPUT[13] = 0;
         FCV_OUTPUT[14] = 0;
         FCV_OUTPUT[15] = 0;
         
         // Longitude ($GPRMC -> n° 5)
         FCM_GPS_ReturnData(FCV_OUTPUT, 5);
         // Printing Longitude
         FCD_LCDDisplay0_PrintString(FCV_OUTPUT, FCSZ_OUTPUT);
         // End program by exiting main loop
         FCV_EXIT = 1;
      } //End if
   } // End of while
} // End of main

If the received data is "GGA" do ... nothing
If the received data is "GSV" do ... nothing again.
If the received data is "RMC", print latitude on the first row and longitude on the second one of the LCD.

FCM_GPS_ReturnData(FCV_OUTPUT, 3);
This function is used to write the latitude, 3rd data of the GPS data string, into the output buffer.
Then print the output buffer and set the cursor on the second row.

Set the output buffer to 0.

FCM_GPS_ReturnData(FCV_OUTPUT, 5);
This is the same function as the previous one, but now, it'll write the longitude, 5th data of GPS data string, into the output buffer.
Then print the output buffer.

Set the exit variable to 1.

Close if statement, close while loop and close the main function.


The FCM_GPS_ReceiveData function :

Code: Select all

void FCM_GPS_ReceiveData()
{
   
   //Local variable definitions
   char FCL_INPUT;      // GPS_ReceiveData.input
   char FCL_POS;      // GPS_ReceiveData.pos
   char FCL_EXIT;      // GPS_ReceiveData.exit

   FCL_POS = 0;
   FCL_INPUT = 0;
   FCL_EXIT = 0;

Declaration and initializing of local variables.
- FCL_INPUT (byte): is used to save the byte received from the GPS.
- FCL_POS (byte): is used for the receive_buffer string. We'll use that variable to write the received byte from the GPS in the receive buffer.
- FCL_EXIT (byte): is used to end the main loop of this function

Code: Select all

   //Loop while exit is equal 0
   while (FCL_EXIT == 0)
   {

We enter the main loop of this function.
This one will be executed if FCL_EXIT is equal to 0.

Code: Select all

      //Loop while the received byte isn't '$'
      while (FCL_INPUT != '$')
      {
         // Receive byte (nTimeout = 10)
         FCL_INPUT = FCD_RS2320_ReceiveRS232Char(10);
      }

This while is executed while FCL_INPUT is not '$'.
This is the begin char of the data sent by the GPS.

Code: Select all

      while (1)
      {
         // Receive byte (nTimeout = 10)
         FCL_INPUT = FCD_RS2320_ReceiveRS232Char(10);

         // if byte is LN or CR or if FCL_POS is higher than 80 (avoiding bufferoverflow) then we'll break.
         if (( FCL_INPUT == 13 ) || ( FCL_INPUT == 10 ) || ( FCL_POS >= 80 ))
         {
            break;
         }
         else
         {
            FCV_RECEIVE_BUFFER[FCL_POS] = FCL_INPUT;
            FCL_POS = FCL_POS + 1;
         }
      }

Infinite loop.

So, we receive the data from the FCD_RS2320_ReceiveRS232Char(10) function.
If the received byte is the LN or CR byte then we'll exit the loop (break).
Else we'll store the received byte in the receive_buffer and then we add 1 to the pos variable.

Code: Select all

      //if the two first chars are GP then we can exit, else we received a wrong data
      if (( FCV_RECEIVE_BUFFER[0] == 'G' ) && ( FCV_RECEIVE_BUFFER[1] == 'P' ))
      {
         FCL_EXIT = 1;
      }
      else
      {
         FCL_POS = 0;
         FCL_INPUT = 0;
         FCL_EXIT = 0;
      }
   } // End of while
} // End of function

To end the function, we'll check if the two first chars are 'G' and 'P'.
If not, we'll reset the local variables and "restart" the whole loop.
If it is, we'll exit the while loop by setting exit to 1.


The FCM_GPS_DataSentence function :

Code: Select all

char FCM_GPS_DataSentence()
{
   // Local variable definitions
   char FCR_RETVAL;   // GPS_DataSentence.Return

   // Sentence is GGA ?
   if (( FCV_RECEIVE_BUFFER[2] == 'G' ) && ( FCV_RECEIVE_BUFFER[3] == 'G' ) && ( FCV_RECEIVE_BUFFER[4] == 'A' ))
   {
      // return 1
      FCR_RETVAL = 1;
      

   }
   // Sentence is GSV ?
   else if (( FCV_RECEIVE_BUFFER[2] == 'G' ) && ( FCV_RECEIVE_BUFFER[3] == 'S' ) && ( FCV_RECEIVE_BUFFER[4] == 'V' ))
   {
      //return 2
      FCR_RETVAL = 2;
   }
   // Sentence is RMC ?
   else if (( FCV_RECEIVE_BUFFER[2] == 'R' ) && ( FCV_RECEIVE_BUFFER[3] == 'M' ) && ( FCV_RECEIVE_BUFFER[4] == 'C' ))
   {
      // return 3
      FCR_RETVAL = 3;
   }
   else
   {
      // Error : return 255
      FCR_RETVAL = 255;
      
   }

   return (FCR_RETVAL);
}

This function checks if the received data has the sentence/code/tag/... "GGA", "GSV" or "RMC".
If it's "GGA" then we'll return 1.
If it's "GSV" then we'll return 2.
If it's "RMC" then we'll return 3.
If it's either of them, we'll return 255 (error).


The FCM_GPS_ReturnData function :

Code: Select all

void FCM_GPS_ReturnData(char* FCR_RETVAL, char FCL_DATA)
{
   
   //Local variable definitions
   char FCL_COUNTER;      // GPS_ReturnData.counter
   char FCL_POS_RB;      // GPS_ReturnData.pos_rb
   char FCL_POS_OUT;      // GPS_ReturnData.pos_out

   FCL_COUNTER = 0;
   FCL_POS_RB = 0;
   FCL_POS_OUT = 0;

This function will write the asked data in the output buffer.

Declaration and initializing of local variables.
- FCL_COUNTER (byte) : is used to count the ','.
- FCL_POS_RB (byte): is used for the receive buffer string. It will allow us to copy the received data on position X in the buffer to the output buffer.
- FCL_POS_OUT (byte): is used to write data to the output buffer on the right position.

Code: Select all

   while (FCL_COUNTER < FCL_DATA)
   {
      // Is char a ','
      if (FCV_RECEIVE_BUFFER[FCL_POS_RB] == 44)
      {
         FCL_COUNTER = FCL_COUNTER + 1;
      }

      FCL_POS_RB = FCL_POS_RB + 1;
      
      // Avoiding overflow.
      if (FCL_POS_RB >= 80)
      {
         break;
      }
   }

This while loop will be executed until the FCL_COUNTER variable is equal or greater than the FCL_DATA parameter variable.

In this while, we check if the char of the receive buffer on position FCL_POS_RB is a ','.
If so, add one to FCL_COUNTER.

Then (after the if statement) add one to FCL_POS_RB.

The next if statement is to avoid a buffer overflow.

Code: Select all

   while (1)
   {
      FCV_OUTPUT[FCL_POS_OUT] = FCV_RECEIVE_BUFFER[FCL_POS_RB];
      FCL_POS_OUT = FCL_POS_OUT + 1;
      FCL_POS_RB = FCL_POS_RB + 1;
      
      // To avoid overflow : FCL_POS_OUT >= 16
      // To detect end of string, end of sentence (ends with LF or CR), end of data :
      // FCV_RECEIVE_BUFFER[FCL_POS_RB] == 0 || (FCV_RECEIVE_BUFFER[FCL_POS_RB] == 13 || FCV_RECEIVE_BUFFER[FCL_POS_RB] == 10) || FCV_RECEIVE_BUFFER[FCL_POS_RB] == 0
      if (FCL_POS_OUT >= 16 || FCL_POS_RB >= 80 || FCV_RECEIVE_BUFFER[FCL_POS_RB] == 44 || FCV_RECEIVE_BUFFER[FCL_POS_RB] == 0 || FCV_RECEIVE_BUFFER[FCL_POS_RB] == 13 || FCV_RECEIVE_BUFFER[FCL_POS_RB] == 10)
      {
         break;
      }
   } // End of while
} // End of function

Infinite loop.
We write the char from the receive buffer on position FCL_POS_RB in the output buffer on position FCL_POS_OUT.
Then we add 1 to FCL_POS_RB and FCL_POS_OUT.

Then we have an if statement.
If the FCL_POS_OUT is greater or equal 16 or if the FCL_POS_RB is greater or equal 80 then we'll exit the loop to avoid buffer overflow.
If the char of the receive buffer on position FCL_POS_RB is ',' or LN or CR or "\0" then we'll also exit the loop.

Close while and close function.


That's it !
Hope it'll be helpfull ;).

Regards,

Nicolas Lopez F.
Attachments
GPS.fcf
GPS v2.0 Flowcode file
(16.38 KiB) Downloaded 442 times
These users thanked the author Spanish_dude for the post:
Benj (Wed Mar 02, 2011 10:52 am)
Rating: 5.88%
 

singhdeol
Posts: 30
Joined: Sat Dec 18, 2010 6:07 am
Has thanked: 6 times
Been thanked: 2 times
Contact:

Re: GPS EB-056 with Flowcode v3

Postby singhdeol » Wed Mar 02, 2011 1:57 am

thx for the post :)