Advertisement

Implementing GPS in a radiosonde design

Kumar B

May 30, 2018

Kumar BMay 30, 2018

In the previous article, I have explained how often are radiosondes launched using wireless RF module AX5042?

This article covers the most exciting part of the High Altitude Weather balloon. I'll describe how to implement GPS for RadioSonde design and load GPS time into a Real Time Clock (DS3231). Moreover, I'll show how to write a code for the working of GPS.

Most of you are aware of the Global Positioning System (GPS) used in smartphones, but an interesting thing is it is often used in medical and environmental embedded systems.

More details in a moment.  

To achieve the timing signal from satellite I have selected Max7c GPS from the Ublox.

To get the accurate time stamp, RTC with ±2ppm is preferred. In this case, I have used DS3231 interface with 8051.

Block Diagram   


Source: Kumar B

Algorithm for GPS  

  1. Search for 1PPS signal.

  2. Send the GPS commands

  3. Wait for GPS to sync with the satellite.

  4. Get the data from the GPS.

Interfacing GPS with Microcontroller

To power up the GPS module, a 3.3V power supply is built.

Due to its adjustable output, this can be used in various applications.


Source: Codrey Electronics


Source: Kumar B


Source: Codrey Electronics

Embedded C code for GPS

This code explains how to got date and time from the satellite using a GPS interface with a microcontroller.

#include <REG52.H>                      
#include <at892051.h
#include <stdio.h>
#define GPS_Poweron   1                   /*to enable the GPS */
#define GPS_Receive     P3_0             /*to receive GPS data*/         
#define GPS_Transmit    P3_1           /*to transmit data*/                
#define GPS_Poweroff 0                     /*to disable GPS */
#define gps_enable    P3_4                 /*to enable GPS */
#define ONE_PPS P1_2                   /*input pin for 1PPS */
gps_enable=0;                                    /*Configured as output */ 
char initial_sync=1;                            /*to sync for first time */
volatile int gps_interrupt_flag;             /*flag for detecting the rising input*/
GPS_Receive=1;                              /*Configured as input*/
GPS_Transmit=0;                           /*Configured as output*/
char gps_timer_flag, rtc_flag_change;
void RTC_Configuration ( );
void gps_interrupt_1PPS ( );
void Gps_Init( );
void GPS_Write (const unsigned char *str);   
void GPS_Write_SendByte (unsigned char data);
void SYNC_GPS( );
void Baudrate_9600 ( );
void Baudrate_4800 ( );
void Convert_Int_To_String(u32 intvalue, u8 *inttoascii );
u8 Get_leapsecond ();
u8 GetDataFromGPS( );


 Here are the UBLOX GPS Commands for Initializing the MAX7C module. 

/*max7c UBLOX commands*/
#define GSVON                             "$PUBX, 40,GSV,0,1,0,0,0,0*58
"
#define GSVOFF                           "$PUBX,40,GSV,0,0,0,0,0,0*59
"
#define GGAON                           "$PUBX,40,GGA,0,1,0,0,0,0*5b
"
#define GGAOFF                          "$PUBX,40,GGA,0,0,0,0,0,0*5a
"
#define GLLON                             "$PUBX,40,GLL,0,1,0,0,0,0*5d
"
#define GLLOFF                            "$PUBX,40,GLL,0,0,0,0,0,0*5c
"       
#define RMCON                            "$PUBX,40,RMC,0,1,0,0,0,0*46
"     
#define RMCOFF                           "$PUBX,40,RMC,0,0,0,0,0,0*47
"
#define ZDAON                              "$PUBX,40,ZDA,0,1,0,0,0,0*45
"     
#define ZDAOFF                             "$PUBX,40,ZDA,0,0,0,0,0,0*44
"
#define GSAON                               "$PUBX,40,GSA,0,1,0,0,0,0*4f
"
#define GSAOFF                              "$PUBX,40,GSA,0,0,0,0,0,0*4e
"
#define VTGON                                "$PUBX,40,VTG,0,1,0,0,0,0*5f
"
#define VTGOFF                               "$PUBX,40,VTG,0,0,0,0,0,0*5e
"
#define LEAP_SECOND_COMMAND                    "$PUBX,04*37
"
#define BAUD_4800                          "$PUBX, 41, 1, 0007, 0003, 4800,0*13
"  
#define BAUD_9600                          "$PUBX,41,1,0007,0003,9600,0*10
"  
void ex1_isr (void) interrupt 1
{
     P3_3 = 1;
/*
User code............
*/
}
/*The application code starts from here*/
void main( )
{
gps_proper = 0;            //Valid GPS
Gps_Catch = 0;
GPS_insert = 0;
Gps_hour=0;
Gps_min=0;
Gps_sec=0;
initial_sync=1;
Baudrate_4800 ( );                                      
external_RTC_init ( );
RTC_Configuration ( );
SYNC_GPS ( );                            
Alarm_Interrupt_RTC ( );
clear_alarm1 ( );
}
/*Function to configure RTC as falling edge*/
void RTC_Configuration ( )
{
EA=1                 //Enable Global interrupts
IE=0x84;           //Enable interrupt 1 for RTC
IT1= 1;              //Set Falling edge interrupt
}
/*Function to get 1PPS signal from the satellite*/
void gps_interrupt_1PPS ( )
{
ONE_PPS =1;                                    /*1PPS Configured as input*/
while(1)
    {
      if(!ONE_PPS) 
         {                      
           gps_interrupt_flag=1;       /*interrupt flag set when input 1PPS is high */
    if(gps_interrupt_flag && ONE_PPS )      /*Detecting low to high pulse  */
        {
            GPS_insert = 1;                       /*Load the GPS*/           
            gps_interrupt_flag=0;                 /*Clear the interrupt flag */
        }
      }
 }
/*Function to initialize the GPS module*/
void Gps_Init( )
{
   gps_enable=GPS_Poweron;             /*Enable GPS*/  
   getTime( );
   t0 = ( RTC_hour * 3600L ) + ( RTC_min * 60 ) + RTC_sec ;
}
/* A function to send a string to GPS module */
void GPS_Write (const unsigned char *str)
 { 
   while(1)
   { 
      if(*str == '’) break;
      GPS_Write_SendByte (*str++);     
   }
}
   /*function to send a byte */
 void GPS_Write_SendByte (unsigned char data)
     { 
        SBUF=data;         // Put byte in SBUF to send to GPS
        while(TI==0);      //wait until the byte trasmission
        TI=0;                  //clear TI to send next byte.                    
   }
/*Function to sync the GPS module with the satellite*/
void SYNC_GPS( )
{
        unsigned char temp, firsttime_gps, buff1[4];
        u32 index, i, j, k;
        timeout = 0;
        gpsvalid = 0;
       Gps_= 0;
       GPS_insert= 0;
        EX1 = 0;                                 //Disable External Interrupt
        external_RTC_init ( );
        Gps_Init( );  
        msdelay(100);                        
        Baudrate_9600 ( );                 //start the timer
        for(k=0; k<2; k++)
         {          
          GPS_Write(GSVOFF);            
     msdelay(100);
          GPS_Write(GLLOFF);           
      msdelay(100);
          GPS_Write(VTGOFF);            
       msdelay(100);
          GPS_Write(ZDAOFF);            
       msdelay(100);
          GPS_Write(GSAOFF);            
       msdelay(100);
          GPS_Write (RMCOFF);           
       msdelay(100);   
          GPS_Write(GGAOFF);            
       msdelay(100);
        }
     for(k=0; k<2; k++)
     {
             GPS_Write (BAUD_4800);        
              msdelay(100);
         }  
     Baudrate_4800 ( );
      for(k=0; k<2;k++)
     {        
          GPS_Write (GSVOFF);
     msdelay(100);
          GPS_Write (GLLOFF);
       msdelay(100);
          GPS_Write (VTGOFF);
       msdelay(100);
       
          GPS_Write (ZDAOFF);   
       msdelay(100);
          GPS_Write (GSAOFF);  
       msdelay(100);
          GPS_Write (RMCOFF);  
       msdelay(100);   
          GPS_Write (GGAOFF);  
       msdelay(100);
        }
     gps_interrupt_1PPS ( );      /*enable only ex-interrupts 1PPS*/                      
      if(initial_sync)
            { 
               /*getting 1PPS signal from the satellite*/   
         }
     while (1)
        {
               if(GetDataFromGPS( )==5)
                   {
                    break;
                   }
           }
              else
                   break;
      
                if (GPS_status_Fix)
                      break;               
        }      
        if(initial_sync && rtc_flag_change)
        {
           /*RTC updated with GPS time*/
            msdelay(3000);
           initial_sync=0;
           rtc_flag_change =0;
        } 
     /*Condition for checking the Gps time out*/
        if(timeout &&  Gps_Catch && initial_sync)
        {
            msdelay(3000); 
            firsttime_gps=0;
        }
         TR1=0;                              //stop the timer
        Alarm_Interrupt_RTC ( );        
        IE=0x84;                           //enable all ex-interrupts except 1PPS
        clear_alarm1 ( );
}
/*Function to set 9600 baud rate*/
void Baudrate_9600 ( )
{
        /*--------------------------------------
     Set serial port for 9600 baud at
     11.0592 MHz.  Note that we use Timer 1
     For the baud rate generator.
     --------------------------------------*/
     SCON = 0x50;
     TMOD |= 0x20;
     TH1   = 0xFD;
     TR1   = 1;
     RI    = 1;
     TI    = 1;
     PCON |= 0x80;
      }
/*Function to set 4800 baud rate*/
void Baudrate_4800 ( )
{
        /*--------------------------------------
     Set serial port for 4800 baud at
     11.0592 MHz.  Note that we use Timer 1
     for the baud rate generator.
     --------------------------------------*/
     SCON  = 0x50;
     TMOD |= 0x20;
     TH1   = 0xFA;
     TR1   = 1;
}
void Convert_Int_To_String(u32 intvalue, u8 *inttoascii )
{
u8 i=0, k=0, finalstring[10], j;
  unsigned char g1=0, g2=0;
 do
       {
            finalstring[i] = (intvalue%10) + 0x30;
            intvalue = intvalue/10;
            i++;  
        }while(intvalue!=0);  
for (g1 = i-1; g1 >= 0; g1--)
     {
          inttoascii [g2] = finalstring [g1];
     g2++;
        if (g1 == 0)
          break;
     }
     inttoascii [g2] = '';
}
u8 Get_leapsecond()
{
unsigned char arr_index,gpsinfo[100] ,seperate,leap=0,tempbit,len;
unsigned long i,p,temptime;
u16 temp;
u32 in,g=0,k;
GPS_insert=0;                 /*Load the GPS*/ 
   
 while( 1)
     {
  /*Syncing GPS*/
 while (GPS_insert)
  {
     GPS_Write(LEAP_SECOND_COMMAND);         
        g=0;
        do
        {
         TR1=0;
         while(GPS_Receive);    //looking for the start bit
         TR1=1;                 //Start timer  
         TF1= 0;             //Clear the timer flag
         timerstatus=TF1;
         TR1=0;                 //Stop the timer
      for (arr_index = 0, temp = 0; arr_index <10; arr_index ++)
              {
               while(!TF1);  
               TF1=0; 
               if(GPS_Receive))      //looking for start bit
               {
                 tempbit=1;
               }
                else  
                {
                    tempbit=0;
                }
                temp |=(tempbit<< arr_index);
                }
         
                  temp >>= 1;
                  gpgga[g++]= temp & 0xff;
            }  while(gpgga[g - 1] != '
');
       
        if(gpgga[arr_index -1]=='D')
       {  
           
        //This will get the Leap second         
   leapsec=(((gpgga[arr_index -3]-0x30) * 10)+ (gpgga[arr_index -2]-0x30));      
   msdelay(5000);
  return 1;
           }
        else
       {
            leapsec=(((gpgga[41]-0x30) * 10)+ (gpgga[42]-0x30));
            msdelay(5000);
            return 1;
           }
  g=0;
  memset(gpgga, 0, sizeof(gpgga));
  }
       if( !GPS_insert )                        //Loading GPS time into RTC                                                       
        {
        getTime();
        temptime = ( RTC_hour * 3600L ) + ( RTC_min * 60 ) + RTC_sec;    
                if( temptime > t0 )
                { 
                    GPS_Poweroff;       
                    GPS_status_Fix = 1;
                    timeout = 1;
                    return 0;
                }
        }
 }
return 5;
}
u8 GetDataFromGPS( )
{
unsigned char arr_index,gpsinfo[100] ,seperate,leap,tempbit,timerstatus;
unsigned long temptime;
u32  g=0;
u16 temp;
leap= 0;
timeout=0;
GPS_insert=0;                   // To get the GPS signal
in=0;
if(Get_leapsecond( )==1)
{
GPS_insert=0;
msdelay(2000);
timeout=0;
GPS_Write(GGAON);
msdelay(200);
while(1)
{
while (!timeout && GPS_insert)
  {
      g=0;
      /* Got Leap Second from GPS satellite /*
do
{
TR1   = 0;                                    //Stop the timer
while(GPS_Receive);
TR1   = 1;                                   //Start the Timer
TF01= 0;                                     //Clear the timer flag
timerstatus=TF01;
for (arr_index = 0, temp = 0; arr_index <10; arr_index ++)
{
while(!timerstatus);
TF01=0;
if(GPS_Receive )                      //looking for start bit
{
tempbit=1;
}
else
{
tempbit=0;
}
temp |= (tempbit<< arr_index);
}
temp >>= 1;
gpgga [g++]= temp & 0xff;
}
while (gpgga [g - 1]! = '
');
memcpy (gpsinfo, gpgga, 70);
memset (gpgga, 0, sizeof (gpgga));
if(gpsinfo [4]=='G')&& gpsinfo[5]=='A'))
{
memcpy( gpsdata, gpsinfo,70 );
if gpsinfo[44] == '2')|| gpsinfo[44] == '1'))
{
GPS_Write(GGAOFF);
msdelay(100);
GPS_Write(GGAOFF);
msdelay(100);
GPS_Write(ZDAON);
msdelay(100);
GPS_Write(ZDAON);
msdelay(100);
thour = gpsinfo[7] - 0x30) * 10) + gpsinfo[8] - 0x30);
tmin =  ((gpsinfo[9] - 0x30) * 10) + (gpsinfo[10] - 0x30);
tsec =  ((gpsinfo[11] - 0x30) * 10) + (gpsinfo[12] - 0x30);
    }
}
else if((gpsinfo[4]=='D') && (gpsinfo[5]=='A'))
{
thour = ((gpsinfo[7]  - 0x30) * 10)  + (gpsinfo[8]  - 0x30);
tmin =  ((gpsinfo[9]  - 0x30) * 10)  + (gpsinfo[10] - 0x30);
tsec =  ((gpsdata1[11] - 0x30) * 10) + (gpsdata1[12] - 0x30);
days =     ((gpsinfo[17] - 0x30) * 10)   + (gpsinfo[18] - 0x30);
month =    ((gpsinfo[20] - 0x30) * 10)   + (gpsinfo[21] - 0x30);
year =     ((gpsinfo[25] - 0x30) * 10)   + (gpsinfo[26] - 0x30);
if(tsec>0 && tsec<5)                  //Add the leap second in the current minute
{
tsec=tsec +leapsec;
leap= 1;
}
}
if( leap==1 )               
{
leap=0;
gps_enable= GPS_Poweroff;           //Power off GPS
Gps_Catch= 1;
getDate( );
getTime ( );
RTC_SetTime (readtime);
RTC_SetDate (readdate);
setTime( thour,    tmin,   tsec,     0, 0);
setDate(    days,  month,   year);
rtc_flag_change =1;
//GPS synced with the satellite//
Gps_year = year;
Gps_days = days;
Gps_month = month;
Gps_hour  = thour;
Gps_min   = tmin;
Gps_sec   = tsec;
g=0;
GPS_Poweroff ( );
return 0;
}
}          //while loop close load gps flag condition
if( !GPS_insert)
{
ReadTimeFromRTC ( );
temptime = (hours * 3600L) + ( minutes * 60) + seconds;
if( temptime > t0 )
{
GPS_Poweroff ( );
Gps_Catch=1;
timeout = 1;
return 0;
}
  }
     }
        }       //Condition to verify the leap second
            }  


Bottom Line

I hope this helps you understand how to use GPS and write code for using a GPS, in this case in a radiosonde application.

Ublox GPS modules are best suited for radiosonde design. To sync with satellite or to get the signal from the satellite Active/Passive antennas are used.

The current drawn by GPS when syncing with the satellite is nearly 30mA.

Suggested Resources:

[1]  U-blox Max7c GPS receiver   

[2] 3.3v microcontroller Power supply   

[3] DS3231 datasheet    

[4] What is 1PPS in GPS?

 

Loading comments...