GPS NMEA protocol 單晶片資訊解析與定時校正

GPS 通訊模組系統,透過RS232通訊介面可獲得衛星時間與方位
NMEA((National Marine Electronics Association)0183 ASCII 的格式
本人將使用收到的 RMC 資料串進行解析,取出衛星當下的時間



Message Structure:                                                                           

$GPRMC,hhmmss,status,latitude,N,longitude,E,spd,cog,ddmmyy,mv,mvE,mode*cs<CR><LF>

Example:                                                                                            

$GPRMC,083559.00,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A*57

Field No. Example Format Name Unit Description
0           $GPRMC string $GPRMC - Message ID, RMC protocol header
1           083559.00 hhmmss.sss hhmmss. - UTC Time, Time of position fix
2           A character Status - Status, V = Navigation receiver warning, A = Data
valid, see Position Fix Flags description
3           4717.11437 ddmm.mmmm Latitude - Latitude, Degrees + minutes, see Format description
4           N character N - N/S Indicator, hemisphere N=north or S=south
5           00833.91522 dddmm.
Mmmm
Longitude - Longitude, Degrees + minutes, see Format description
6           E character E - E/W indicator, E=east or W=west
7           0.004 numeric Spd knots Speed over ground
8           77.52 numeric Cog degrees Course over ground
9           091202 ddmmyy date - Date in day, month, year format
10          - numeric mv degrees Magnetic variation value, not being output by receiver
11          - character mvE - Magnetic variation E/W indicator, not being output by receiver
12          - character mode - Mode Indicator, see Position Fix Flags description
13          *57 hexadecimal cs - Checksum
14          - character <CR><LF> - Carriage Return and Line Feed
  


程式撰寫                                                                                          

  • 使用編譯器: CCS PCWHD
  • 使用單晶片:Microchip PIC18F45K22


透過剛剛介紹的$GPSRMC 接收來自衛星訊號的ASCII內容,裡面包含了有UTC標準時間,本文透過解析內容並轉為資料串再回傳給單晶片修正RTC時間
副程式除了解析出時間外,同時也將轉換經緯度座標位置
char *srg: 傳入接收來自於RS232資料串
TDateTime *DT: 傳入欲擺放時間日期等資訊的結構串
TCoordinate *Coordinate:傳入欲擺放經緯度等資訊的結構串
程序完成後成功傳為0
int GPS_GPRMC_stream_decoder(char *srg, TDateTime *DT, TCoordinate *Coordinate)
{   
  char st = 0, ed = 0, index = 0;
  //step1: find $GPRMC position,not found reutn value = -1
  if (strFind(srg, (char*)"$GPRMC", 0) == -1)
    return -1;
  
  //step2: find first ',' position in string
  st = charFind(srg, ',', 0);
  if (st == -1) 
    return -1;
    
  char str[16];
  char str_length = strlen(srg);
  while (st != -1 && index < str_length)
  {
    ed = charFind(srg, ',', st+1);
    switch (++index)
    {
      
      case 1 : DT->hour = atoi(StrmnCpy(str, srg, st+1, 2));
               DT->min  = atoi(StrmnCpy(str, srg, st+3, 2));
               DT->sec  = atoi(StrmnCpy(str, srg, st+5, 2));
               break;
      case 2 : if (*StrmnCpy(str, srg, st+1, 1) != 'A')
                 return -1;
               break;
      case 3 : StrmnCpy(str, srg, st+1, ed-st-1);
               Coordinate->Latitude = GPS_StrtoLatitude(&str, ed-st-1); 
               break;
      case 4 : StrmnCpy(str, srg, st+1, 1);
               Coordinate->N_S = str[0];
               break;        
      case 5 : StrmnCpy(str, srg, st+1, ed-st-1);
               Coordinate->Longitude = GPS_StrtoLongitude(&str, ed-st-1);
               break;
      case 6 : StrmnCpy(str, srg, st+1, 1);
               Coordinate->E_W = str[0];
               break; 
      case 7 : StrmnCpy(str, srg, st+1, ed-st-1);
               Coordinate->speed  = strtof(str, '0');
               break; 
      case 9 : DT->m_day   = atoi(StrmnCpy(str, srg, st+1, 2));
               DT->month   = atoi(StrmnCpy(str, srg, st+3, 2));
               DT->year    = atoi(StrmnCpy(str, srg, st+5, 2));
               DT->w_day   = RTC_Weekend_Transfer(20, DT->year, DT->month, DT->m_day); 
               break;
    }
    st = ed;
  }
  return 0;
}     

尋找字串中指定的字串內容處在位置
int strFind(char *srg, char *s, size_t st)
{
  BYTE pos; 
  for (pos=st, srg+=st; *srg != '\0'; srg++, pos++)
    if (strspn(srg, s) == strlen(s))  
      return pos;
  return -1;
}

尋找字元中指定的字串內容處在位置
int charFind(char *s, char c, size_t st)
{
  BYTE pos;
  for (pos=st, s+=st; *s != '\0'; s++, pos++)
    if (*s == c)  
      return pos;
  return -1; 
}

複製字串
char *StrmnCpy(char *str, char *srg, size_t m, size_t n)
{
  int i=0;
  char *s;
 
  for(s=str, i=m, srg+=m; i<m+n; i++)
    *s++ = *srg++;
  *s++ = '\0';
   
  return str;
}

沒有留言:

張貼留言

留言板