Monday, July 18, 2011

Interfacing the LS20031 GPS Receiver

This system currently gets GPS data from an LS20031 GPS receiver, interfaced to the Olimex I2C client. In order to configure the GPS, it is convenient to use the MiniGPS software available on the SparkFun site for this product.

Here is a configuration arrangement where a CP2102 USB converter is used for communication to the PC running MiniGPS, as well as a 3.3 V power supply to the GPS.





The MiniGPS software has been used to configure the $GPRMC NMEA 0183 sentence at a baud rate of 9600, with an update rate of 5 Hz, and WAAS enabled ( I am currently using an older 5 Hz LS20031 version, soon to be replaced by the 10 Hz one).

Here is the format of the output sentence:
               $GPRMC,180846.600,A,4659.9999,N,07059.9999,W,6.00,45.00,050210,,,D*77
where the 6 numbers to be extracted are highlighted. The latitude and longitude are each read as 2 integer values to avoid rounding errors here, followed by the SOG and COG floating point values.

WARNING: the onboard battery will keep the configuration up to several weeks if the GPS is not powered during this time, and will then revert to the default configuration with a 57600 baud rate. After a winter season on the dry, the configuration step has to be repeated.
 
Once configured, here is how the GPS is interfaced to the microcontroller, using a logic level converter to step up the NMEA output from 3.3 to 5 V. This is a good illustration of the kind of punishment you deserve when you mix 3.3 V sensors with 5 V microprocessors.


Here is the part of the code used by the Olimex microprocessor to parse the NMEA data from the GPS.
unsigned static char buf0[500];
volatile unsigned char temprec0;
volatile unsigned char idx0 = 0;
typedef union
{
   unsigned char messageBuf[36];
   struct
   {
      double heading;   // magnetic heading from gyrocompass
      double heel;   // heel angle from gryrocompass
      double pitch;   // pitch angle from gyrocompass
      double rot;    // rate of turn from gyrocompass
      double cog;    // COG from GPS
      double sog;    // SOG from GPS
      int long1;    // longitude (1st part) from GPS
      int long2;    // longitude (2nd part) from GPS
      int lat1;    // latitude (1st part) from GPS
      int lat2;    // latitude (2nd part) from GPS
      double speed2;    // boat speed from port transducer
   };
} package;

volatile package pack;

/* This interrupt routine is called each time a new character
   is received from the GPS NMEA stream. When the end of
   a NMEA sentence is detected (by the '\n' character), the
   complete sentence accumulated in the 'buf0[]' buffer is deciphered,
   the desired numbers are extracted and put in the 'pack' repository,
   that is used for the I2C transfer to the main controller.
*/
ISR(USART0_RX_vect)
{
   temprec0 = UDR0;
   if(temprec0 != '\n')
   {
      buf0[idx0++] = temprec0;
   }
   else
   {
     buf0[idx0] = '\0';
     idx0 = 0;
     if(buf0[0] == '$')
     {
        // $GPRMC,180846.600,A,4659.9999,N,07059.9999,W,6.00,45.00,050210,,,D*77
        sscanf(&(buf0[20]), "%d", &pack.lat1);
        sscanf(&(buf0[25]), "%d", &pack.lat2);
        sscanf(&(buf0[33]), "%d", &pack.long1);
        sscanf(&(buf0[38]), "%d", &pack.long2);
        sscanf(&(buf0[45]), "%lf,%lf", &pack.sog, &pack.cog);
     }
   }
}
int main(void)
{
   ...
   /* USART0 */
   /* Set baud rate : 9600 @ 16MHz */
   UBRR0L = (unsigned char)(103);
   /* Enable receiver and interrupt on received characters */
   UCSR0B = _BV(RXEN) | _BV(RXCIE);
   idx0 = 0;
 
   ...
}

No comments:

Post a Comment