GPS 简单实用-GPRMC
/*
* GPS 模块使用相关说明
* NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为
* 海用电子设备制定的标准格式。
* 目前业已成了GPS导航设备统一的标准协议。
* RTCM(Radio Technical Commission for Maritime services)
* NMEA-0183协议采用ASCII码来传递GPS定位信息。
* 帧格式形如:$aaccc,ddd,ddd,…,ddd*hh(CR)(LF)
* 1、“$”:帧命令起始位
* 2、aaccc:地址域,前两位为识别符(aa),后三位为语句名(ccc)
* 3、ddd…ddd:数据
* 4、“*”:校验和前缀(也可以作为语句数据结束的标志)
* 5、hh:校验和(check sum),$与*之间所有字符ASCII码的校验和
* (各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符)
* 6、(CR)(LF):帧结束,回车和换行符
*
* $GPRMC(推荐定位信息,Recommended Minimum Specific GPS/Transit Data)
* $GPRMC语句的基本格式如下:
* $GPRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)
* (1) UTC时间, hhmmss(时分秒)
* (2) 定位状态, A=有效定位, V=无效定位
* (3) 纬度ddmm.mmmm(度分)
* (4) 纬度半球N(北半球)或S(南半球)
* (5) 经度dddmm.mmmm(度分)
* (6) 经度半球E(东经)或W(西经)
* (7) 地面速率(000.0~999.9节)
* (8) 地面航向(000.0~359.9度, 以真北方为参考基准)
* (9) UTC日期, ddmmyy(日月年)
* (10) 磁偏角(000.0~180.0度, 前导位数不足则补0) empty
* (11) 磁偏角方向,E(东)或W(西) empty
* (12) 模式指示(A=自主定位, D=差分, E=估算, N=数据无效)
* $GPRMC,082006.000,A,3852.9276,N,11527.4283,E,0.00,0.0,261009,,,A*38
*
* 1. 东经正数,西经负数(0-180), 经度的每一度被分为60分, 每一分被分为60秒
* 2. 北纬正数,南纬负数(0- 90), 经度的每一度被分为60分, 每一分被分为60秒
*
*/
#include
#include
#include
#define GPS_RMC_TRACE 1
#if (GPS_RMC_TRACE == 1)
#define T_D(_fmt,...) \
fprintf(stderr, "%s/%d:"_fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__);
#define __DEBUG_FUN /* trace func section */
#else
#define T_D(_fmt,...)
#define __DEBUG_FUN
#endif
typedef struct {
/* +1 for '\0', ez to snprintf */
uint8_t utc_time[6+1]; /* hhmmss.xxx but only xxx=000 */
uint8_t status; /* A/V */
uint8_t latitude[9+1]; /* ddmm.mmmm */
uint8_t NS; /* N/S */
uint8_t logitude[10+1]; /* dddmm.mmmm */
uint8_t EW; /* E/W */
uint8_t speed[5+1]; /* 000.0~999.9 */
uint8_t course[5+1]; /* 000.0~999.9 */
uint8_t utc_date[6+1]; /* ddmmyy */
/* <10>: empty */
/* <11>: empty */
uint8_t indicator; /* A/D/E/N */
} gps_rmc_t;
static char *box_strsep(char **stringp, const char *delim)
{
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp)== NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc =*spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
static char *box_next_token(char **p_cur)
{
char *ret = NULL;
if (*p_cur == NULL) {
ret = NULL;
} else {
ret = box_strsep(p_cur, ",");
}
return ret;
}
static int box_token_has_more(char **p_cur)
{
return ! (*p_cur == NULL || **p_cur == '\0');
}
__DEBUG_FUN void rmc_show(gps_rmc_t *gps_rmc)
{
fprintf(stderr, "<1>utc_time :%s\r\n", gps_rmc->utc_time);
fprintf(stderr, "<2>status :%c\r\n", gps_rmc->status);
fprintf(stderr, "<3>latitude :%s\r\n", gps_rmc->latitude);
fprintf(stderr, "<4>NS :%c\r\n", gps_rmc->NS);
fprintf(stderr, "<5>logitude :%s\r\n", gps_rmc->logitude);
fprintf(stderr, "<6>EW :%c\r\n", gps_rmc->EW);
fprintf(stderr, "<7>speed :%s\r\n", gps_rmc->speed);
fprintf(stderr, "<8>course :%s\r\n", gps_rmc->course);
fprintf(stderr, "<9>utc_date :%s\r\n", gps_rmc->utc_date);
fprintf(stderr, "<12>indicator:%c\r\n", gps_rmc->indicator);
}
/*****************************************************************************
* Name: gps_rmc_isvaild
*
* Description:
* GPS RMC Data is vaild and a tiny parser
*
* Input Parameters:
* data - string end with '\0'
* Output Parameters:
* gps_rmc
* Returned Value:
* 1: vaild 0:unvaild
****************************************************************************/
uint8_t gps_rmc_isvaild(char *data, gps_rmc_t *gps_rmc)
{
uint8_t i;
char *str;
if (!data)
return 0;
/* $GPRMC */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
} else if (strncmp(str, "$GPRMC", sizeof("$XXRMC")) &&
strncmp(str, "$GPRMC", sizeof("$XXRMC")) &&
strncmp(str, "$GPRMC", sizeof("$XXRMC"))) {
return 0;
}
T_D("str:%s", str);
/* (1) UTC时间, hhmmss(时分秒) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
strncpy(gps_rmc->utc_time, str, sizeof(gps_rmc->utc_time));
gps_rmc->utc_time[sizeof(gps_rmc->utc_time) - 1] = '\0';
/* (2) 定位状态, A=有效定位, V=无效定位 */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
} else if (strcmp(str, "A")) {
T_D("Not 'A'");
return 0;
}
T_D("str:%s", str);
gps_rmc->status = str[0];
/* (3) 纬度ddmm.mmmm(度分) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
strncpy(gps_rmc->latitude, str, sizeof(gps_rmc->latitude));
/* (4) 纬度半球N(北半球)或S(南半球) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
gps_rmc->NS = str[0];
/* (5) 经度dddmm.mmmm(度分) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
strncpy(gps_rmc->logitude, str, sizeof(gps_rmc->logitude));
/* (6) 经度半球E(东经)或W(西经) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
gps_rmc->EW = str[0];
/* (7) 地面速率(000.0~999.9节) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
strncpy(gps_rmc->speed, str, sizeof(gps_rmc->speed));
/* (8) 地面航向(000.0~359.9度, 以真北方为参考基准) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
strncpy(gps_rmc->course, str, sizeof(gps_rmc->course));
/* (9) UTC日期, ddmmyy(日月年) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
strncpy(gps_rmc->utc_date, str, sizeof(gps_rmc->utc_date));
/* (10) 磁偏角(000.0~180.0度, 前导位数不足则补0) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
/* (11) 磁偏角方向,E(东)或W(西) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
}
T_D("str:%s", str);
/* (12) 模式指示(A=自主定位, D=差分, E=估算, N=数据无效) */
if (!(str = box_next_token(&data))) {
T_D("str null");
return 0;
} else if (str[0] == 'N') {
T_D("'N'");
return 0;
}
T_D("str:%s", str);
gps_rmc->indicator = str[0];
/* last data has more token (12)*hh */
if (box_token_has_more(&data)) {
T_D("last data has more token (12)*hh");
return 0;
}
T_D("done");
return 1;
}
int main(void)
{
gps_rmc_t gps_rmc;
char gprmc_data[] = "$GNRMC,083505.000,A,3037.3890,N,10402.3510,E,0.32,163.24,250216,,,A*7F";
if (gps_rmc_isvaild(gprmc_data, &gps_rmc)) {
rmc_show(&gps_rmc);
} else {
fprintf(stderr, "%s: unvaild\r\n", gprmc_data);
}
return 0;
}