C语言解析GPS的NMEA格式

公共的函数

typedef unsigned char   uint8_t;

/** 
 * @brief		时间
 * @details	    定位数据解算的时间 
 */
typedef struct _nmeaTIME
{
	int year;       /**< Years since 1900 */
    int mon;        /**< Months since January - [0,11] */
    int day;        /**< Day of the month - [1,31] */
    int hour;       /**< Hours since midnight - [0,23] */
    int min;        /**< Minutes after the hour - [0,59] */
    int sec;        /**< Seconds after the minute - [0,59] */
    int hsec;       /**< 秒的百分之一 - [0,99] */
}nmeaTIME;

/**
 * @brief		计算 UTC 
 * @details	    将 UT C时间解算成整数
 * @param[in]	buff 需要解算的时间  stat 0:时分秒 1:年月日
 * @param[out]	time 解算后的 UTC 
 * @retval		NULL
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
void GetTime(const char *buff, nmeaTIME *time, int stat)
{
	int num;
	if(stat == 0){
		sscanf(buff, "%d.%d", &num, &(time->hsec));
		time->hour	= num/10000;
		time->min	= (num%10000)/100;
		time->sec	= num%100;
	}else{
		sscanf(buff, "%d", &num);
		time->day   = num/10000;
		time->mon   = (num%10000)/100;
		time->year  = num%100;
	}
}

/**
 * @brief		char to double
 * @details	    字符串转 double
 * @param[in]	str 字符串
 * @param[out]  NULL
 * @retval		double 数值
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
double CharToDou(char str[])
{
	double start = 0, num = 0;
	int i = 0;

	for(; str[i] != '\0'; i++)
		if(str[i] <= '9' && str[i] >= '0'){
			if(start == 0){
				num = num*10 + str[i] - '0';
			}else{
				num = num + (str[i] - '0')/start;
				start = start*10;
			}
		}else
			start = 10;

	return num;
}

		
/**
 * @brief 从buf里面得到第cx个逗号所在的位置
 * 
 * @param buf 
 * @param cx 
 * @return 0~0XFE,代表逗号所在位置的偏移.
 *         0XFF,代表不存在第cx个逗号
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
uint8_t NMEA_Comma_Pos(uint8_t *buf, uint8_t cx)
{
	uint8_t *p = buf;
	while(cx)
	{
		if(*buf=='*'||*buf<' '||*buf>'z')
			return 0XFF;//遇到'*'或者非法字符,则不存在第cx个逗号
		if(*buf==',')
			cx--;
		buf++;
	}
	return buf-p;
}

解析GPRMC

/** 
 * @brief		GPRMC
 * @details	    解算的 GPRMC  
 */
typedef struct _nmeaGPRMC
{
    nmeaTIME utc;       /**< 位置UTC */
    char    status;     /**< 地位 (A = 定位 or V = 未定位) */
    double  lat;        /**< NDEG 中的纬度 - [度][min].[sec/60] */
    char    ns;         /**< [N]北方 or [S]南方 */
    double  lon;        /**< NDEG 中的经度 - [度][min].[sec/60] */
    char    ew;         /**< [E]东方 or [W]西方 */
    double  speed;      /**< 以节为单位在地面上的速度 */
    double  direction;  /**< 轨迹角度(以度为单位) */
    double  declination; /**< 磁变化度(从实际航向减去东风变化) */
    char    declin_ew;  /**< [E]东方 or [W]西方 */
    char    mode;       /**< 固定式模式指示器 (A = 自主, D = 差分, E = 估测, N = 数据无效, S = 模拟机) */
 
}nmeaGPRMC;

/***********************************************************************
 *     			推荐最小特定GPS / TRANSIT数据(RMC)推荐定位信息
 * 格 式:
 *		$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<CR><LF>
 *		$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
 * 说 明:
 *		字段 0:$GPRMC,语句ID,
 *		字段 1:UTC时间,hhmmss.sss格式
 *		字段 2:状态,A=定位,V=未定位
 *		字段 3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
 *		字段 4:纬度N(北纬)或S(南纬)
 *		字段 5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
 *		字段 6:经度E(东经)或W(西经)
 *		字段 7:速度,节,Knots(一节也是1.852千米/小时)
 *		字段 8:方位角,度(二维方向指向,相当于二维罗盘)
 *		字段 9:UTC日期,DDMMYY格式
 *		字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
 *		字段11:磁偏角方向,E=东,W=西
 *		字段12:模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)
 *		字段13:校验值
 *
 ***********************************************************************/
/**
 * @brief		解算RMC数据
 * @details	    将导航定位数据解算成 RMC 数据 
 * @param[in]	buff 需要解算的字符串内容
 * @param[out]	Date 解算后的 RMC 数据 
 * @retval		0: 解算成功
 * @retval		1:没有 $GPRMC 数据
 * @retval	    2:无定位数据
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
int GPRMCSolution(nmeaGPRMC *Date, const char *buff)
{
	char *buf, time[20]={0};
	int i;

	buf = strstr(buff, "$GPRMC");
	if(buf == NULL)
		return 1;
	buf += 7;
	if(*buf == '*' || *buf == ',')
		return 2;

	/*** 字段 0:时分秒 time ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			GetTime(time, &(Date->utc), 0);
			break;
		}
		time[i] = *buf;
	}
	
	/*** 字段 1:状态,A=定位,V=未定位 ***/
	Date->status = *buf; 
	if(Date->status == 'V'){
		return 2;
	}else{
		buf += 2;
	}

	/*** 字段 3:纬度ddmm.mmmm ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->lat = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}

	/*** 字段 4:纬度N(北纬)或S(南纬) ***/
	if(*buf == ','){
		buf++;
	}else{
		Date->ns = *buf; buf += 2;
	}

	/*** 字段 5:经度dddmm.mmmm ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->lon = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}

	/*** 字段 6:经度E(东经)或W(西经) ***/
	if(*buf == ','){
		buf++;
	}else{
		Date->ew = *buf; buf += 2;
	}

	/*** 字段 7:速度,节,Knots ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->speed = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}

	/*** 字段 8:方位角,度 ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->direction = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}

	/*** 字段 9:UTC日期,DDMMYY格式 ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			GetTime(time, &(Date->utc), 1);
			break;
		}
		time[i] = *buf;
	}

	/*** 字段10:磁偏角,(000 - 180)度 ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->declination = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}

	/*** 字段11:磁偏角方向,E=东,W=西 ***/
	if(*buf == ','){
		Date->declin_ew = 'V';
		buf++;
	}else{
		Date->declin_ew = *buf; buf += 2;
	}

	/*** 字段12:模式,A=自动,D=差分,E=估测,N=数据无效 ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->mode = time[0];
			break;
		}
		time[i] = *buf;
	}

	return 0;
}

解析GPGGA

/***********************************************************************
 * 					全球定位系统定位数据(GGA)GPS定位信息
 * 格式
 * 		$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11> ,<12> * hh
 * 		$GPGGA,024040.00,2310.82644,N,11324.94929,E,2,06,1.30,-40.3,M,-5.2,M,,0000*5F
 * 说明
 * 		<1> UTC时间,hhmmss(时分秒)格式
 * 		<2> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
 * 		<3> 纬度半球N(北半球)或S(南半球)
 * 		<4> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
 * 		<5> 经度半球E(东经)或W(西经)
 * 		<6> GPS状态:0 =未定位,1 =非差分定位,2 =差分定位,6 =正在采样
 * 		<7> 正在使用解算位置的卫星数量(00~12)(前面的0也将被传输)
 * 		<8> HDOP水平精度因子(0.5~99.9)
 * 		<9> 海拔高度(-9999.9~99999.9)
 * 		<10>地球沥青球面相对大地水准面的高度
 * 		<11>差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空)
 * 		<12>差分站ID号0000~1023(前面的0也将被传输,如果不是差分定位将为空)
 ***********************************************************************/

/**
 * @brief       GPGGA
 * @details	    解算的 GPGGA  
 */
typedef struct _nmeaGPGGA
{
    int     utc;        /**< UTC时间,hhmmss(时分秒)格式 */
    double  lat;        /**< 纬度ddmm.mmmm(度分)格式(前面的0也将被传输) */
    char    ns;         /**< 纬度半球N(北半球)或S(南半球) */
    double  lon;        /**< 经度dddmm.mmmm(度分)格式(前面的0也将被传输) */
    char    ew;         /**< 经度半球E(东经)或W(西经) */
    int     mode;       /**< GPS状态:0 =未定位,1 =非差分定位,2 =差分定位,6 =正在采样 */
    int     sateNum;    /**< 正在使用解算位置的卫星数量(00~12)(前面的0也将被传输) */
    double  HDOP;       /**< HDOP水平精度因子(0.5~99.9) */
    double  Altitude;   /**< 海拔高度(-9999.9~99999.9) */
    double  Leveheght;  /**< 地球沥青球面相对大地水准面的高度 */
    int     DiffTime;   /**< 差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空) */
    int     DiffID;     /**< 差分站ID号0000~1023(前面的0也将被传输,如果不是差分定位将为空) */
}nmeaGPGGA;

/**
 * @brief		解算 GGA 数据
 * @details	    将导航定位数据解算成 GGA 数据 
 * @param[in]	buff 需要解算的字符串内容
 * @param[out]	Date 解算后的 GGA 数据 
 * @retval		0: 解算成功
 * @retval		1:没有 $GPGGA 数据
 * @retval	    2:无定位数据
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */

int GPGGASolution(nmeaGPGGA *Date, const char *buff)
{	
	char *buf, time[20]={0};
	int temp;
	uint8_t posx;

	buf = strstr(buff, "$GPGGA");
	if(buf == NULL)
		return 1;

	posx = NMEA_Comma_Pos(buf, 1);  // UTC时间,hhmmss(时分秒)格式
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->utc));
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 2);  // 纬度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->lat));
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 3);  // 纬度半球
	if(posx != 0XFF)
		Date->ns = *(buf + posx);
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 4);  // 经度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->lon));
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 5);  // 经度半球
	if(posx != 0XFF)
		Date->ew = *(buf + posx);
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 6);  // GPS状态
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->mode));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 7);  // 正在使用解算位置的卫星数量
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->sateNum));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 8);  //  HDOP水平精度因子
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->HDOP));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 9);  // 海拔高度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->Altitude));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 11); // 地球沥青球面相对大地水准面的高度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->Leveheght));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 13);  // 差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空)
	if(posx != 0XFF)
		if(*(buf + posx) == ',')
			Date->DiffTime = 0;
		else
			sscanf((const char *)(buf + posx), "%d,", &(Date->DiffTime));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 14);  // 差分站ID号
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->DiffID));
	else
		return 2;
	return 0;
}
		

解析GPGSA

/***********************************************************************
 * GPS DOP和有源卫星(GSA)最新卫星信息
 * 格式
 *      $GPGSA,<1>,<2>,<3>,<4> 、、、、、 <12>,<13>,<14>,<15>,<16>,<17>,<18>
 * 		$GPGSA,A,3, 18, 32, 25, 24, 23, 10,
 *                    ,   ,   ,   ,   ,   , 2.86,1.30,2.55*07
 * 说明
 *      <1>模式:M =手动,A =自动。
 *      <2>定位型式1 =未定位,2 =二维定位,3 =三维定位。
 *      <3>到<14> PRN数字:01至32表天空使用中的卫星编号,最多可接收12颗卫星信息
 *      <15> PDOP位置精度因子(0.5~99.9)
 * 		<16> HDOP水平精度因子(0.5~99.9)
 *   	<17> VDOP垂直精度因子(0.5~99.9)
 *   	<18>校验和。
 ***********************************************************************/
/** 
 * @brief		GPGSA
 * @details	    解算的 GPGSA  
 */
typedef struct _nmeaGPGSA
{
    char    mode;       /**< 模式:M =手动,A =自动 */
    int     type;       /**< 定位型式1 =未定位,2 =二维定位,3 =三维定位 */
    int     PRNnum[12]; /**< PRN数字:01至32表天空使用中的卫星编号 */
    double  PDOP;       /**< PDOP位置精度因子(0.5〜99.9) */
    double  HDOP;       /**< HDOP位置精度因子(0.5〜99.9) */
    double  VDOP;       /**< VDOP位置精度因子(0.5〜99.9) */
}nmeaGPGSA;

/**
 * @brief		解算GSA数据
 * @details	    将导航定位数据解算成 GSA 数据 
 * @param[in]	buff 需要解算的字符串内容
 * @param[out]	Date 解算后的 GSA 数据 
 * @retval		0: 解算成功
 * @retval		1:没有 $GPGSA 数据
 * @retval	    2:无定位数据
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
int GPGSASolution(nmeaGPGSA *Date, const char *buff)
{
	char *buf, time[100]={0};
	int i, j, num=0;

	buf = strstr(buff, "$GPGSA");
	if(buf == NULL)
		return 1;
	buf += 7;
	if(*buf == '*' || *buf == ',')
		return 2;

	/*** <1>模式:M =手动,A =自动。 ***/
	Date->mode = *buf; buf += 2;

	/*** <2>定位型式1 =未定位,2 =二维定位,3 =三维定位 ***/
	for(i=0; i<20; i++, buf++){
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++;
			break;
		}
		Date->type = *buf - '0';
	}

	/*** <3>到<14> PRN数字:01至32表天空使用中的卫星编号,最多可接收12颗卫星信息 ***/
	for(j=0; j<12; j++){
		for(i=0; i<20; i++, buf++){
			if(*buf == ',' || *buf == '\0' || *buf == '\n'){
				Date->PRNnum[j] = num;
				num = 0; buf++;
				break;
			}
			num = num*10 + *buf - '0';
		}
	}

	/*** <15> PDOP位置精度因子(0.5~99.9) ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->PDOP = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}
	
	/*** <16> HDOP位置精度因子(0.5~99.9) ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == ',' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->HDOP = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}
	
	/*** <17> VDOP位置精度因子(0.5~99.9) ***/
	for(i=0; i < 20; i++, buf++){	
		if(*buf == '*' || *buf == '\0' || *buf == '\n'){
			buf++; time[i] = '\0';
			Date->VDOP = CharToDou(time);
			break;
		}
		time[i] = *buf;
	}

	return 0;
}

解析GPGLL

/***********************************************************************
 * 							地理定位信息
 * 格式
 * 		$GPGLL,2310.82644,N,11324.94929,E,024040.00,A,D*68
 * 说明
 * 		字符串0:$ GPGLL,语句ID,表明该语句为地理位置(GLL)地理定位信息
 * 		分段1:纬度ddmm.mmmm,度分格式(前导数值不足则补0)
 * 		分段2:纬度N(北纬)或S(南纬)
 * 		分段3:经度dddmm.mmmm,度分格式(前导数值不足则补0)区间4:经度E(东经)或W(西经)
 * 		分段5:UTC时间,hhmmss.sss格式
 * 		分段6:状态,A =定位,V =未定位
 * 		分段7:校正值
 * ***********************************************************************/
/**
 * @brief       GPGLL
 * @details	    解算的 GPGLL  
 */
typedef struct _nmeaGPGLL
{
    double  lat;        /**< 纬度ddmm.mmmm(度分)格式(前面的0也将被传输) */
    char    ns;         /**< 纬度半球N(北半球)或S(南半球) */
    double  lon;        /**< 经度dddmm.mmmm(度分)格式(前面的0也将被传输) */
    char    ew;         /**< 经度半球E(东经)或W(西经) */
    int     utc;        /**< UTC时间,hhmmss(时分秒)格式 */
    char    mode;       /**< 状态,A =定位,V =未定位 */
}nmeaGPGLL;

/**
 * @brief		解算 GLL 数据
 * @details	    将导航定位数据解算成 GLL 数据 
 * @param[in]	buff 需要解算的字符串内容
 * @param[out]	Date 解算后的 GLL 数据 
 * @retval		0: 解算成功
 * @retval		1:没有 $GPGLL 数据
 * @retval	    2:无定位数据
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
int GPGLLSolution(nmeaGPGLL *Date, const char *buff)
{
	char *buf, time[20]={0};
	int temp;
	uint8_t posx;

	buf = strstr(buff, "$GPGLL");
	if(buf == NULL)
		return 1;
		
	posx = NMEA_Comma_Pos(buf, 1);  // 纬度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->lat));
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 2);  // 纬度半球
	if(posx != 0XFF)
		Date->ns = *(buf + posx);
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 3);  // 经度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->lon));
	else
		return 2;
		
	posx = NMEA_Comma_Pos(buf, 4);  // 经度半球
	if(posx != 0XFF)
		Date->ew = *(buf + posx);
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 5);  // UTC时间,hhmmss(时分秒)格式
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->utc));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 6);  // 状态,A =定位,V =未定位
	if(posx != 0XFF)
		Date->mode = *(buf + posx);
	else
		return 2;
		
	return 0;
}

解析GPVTG

/***********************************************************************
 * 				履带良好和地面速度(VTG)地面速度信息
 * 格式
 * 		$GPVTG,<1>,T,<2>,M,<3>,N,<4>,K,<5> * hh
 * 		$GPVTG,,T,,M,0.010,N,0.019,K,D*2F
 * 说明
 * 		<1>以真北为参考基准的地面航向(000~359度,前面的0也将被传输)
 * 		<2>以磁北为参考基准的地面航向(000~359度,前面的0也将被传输)
 * 		<3>地面速率(000.0~999.9节,前面的0也将被传输)
 * 		<4>地面速度(0000.0~1851.8公里/小时,前面的0也将被传输)
 * 		<5>模式指示(仅NMEA0183 3.00版本输出,A =自主定位,D =差分,E =投放,N =数据无效)
 ***********************************************************************/
/**
 * @brief       GPVTG
 * @details	    解算的 GPVTG  
 */
typedef struct _nmeaGPVTG
{
    int     course1;    /**< 以真北为参考基准的地面航向 */
    int     course2;    /**< 以磁北为参考基准的地面航向 */
    double  GrSpeed;    /**< 地面速率 */
    double  GrSpees;    /**< 地面速度 */
    char    mode;       /**< 模式指示 */
}nmeaGPVTG;

/**
 * @brief		解算 VTG 数据
 * @details	    将导航定位数据解算成 VTG 数据 
 * @param[in]	buff 需要解算的字符串内容
 * @param[out]	Date 解算后的 VTG 数据 
 * @retval		0: 解算成功
 * @retval		1:没有 $GPVTG 数据
 * @retval	    2:无定位数据
 * @par 修改日志
 * 		fanl于2021-12-11创建
 */
int GPVTGSolution(nmeaGPVTG *Date, const char *buff)
{
	char *buf, time[20]={0};
	int temp;
	uint8_t posx;

	buf = strstr(buff, "$GPVTG");
	if(buf == NULL)
		return 1;

	posx = NMEA_Comma_Pos(buf, 1);  // 以真北为参考基准的地面航向
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->course1));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 3); // 以磁北为参考基准的地面航向
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%d,", &(Date->course2));
	else
		return 2;
	
	posx = NMEA_Comma_Pos(buf, 5); // 地面速率
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->GrSpeed));
	else
		return 2;
	
	posx = NMEA_Comma_Pos(buf, 7); // 地面速度
	if(posx != 0XFF)
		sscanf((const char *)(buf + posx), "%lf,", &(Date->GrSpees));
	else
		return 2;

	posx = NMEA_Comma_Pos(buf, 9); // 模式指示
	if(posx != 0XFF)
		Date->mode = *(buf + posx);
	else
		return 2;

	return 0;
}

测试函数

int main()
{
	nmeaGPRMC RMCDate;
    nmeaGPGSA GSADate;
    nmeaGPVTG VTGDate;
    nmeaGPGGA GGADate;
    nmeaGPGLL GLLDate;

    char buff[] = "$GPRMC,024051.00,A,2310.82644,N,11324.94929,E,0.010,,101221,,,D*71\n\
$GPVTG,,T,,M,0.010,N,0.019,K,D*2F\n\
$GPGGA,024040.00,2310.82644,N,11324.94929,E,2,06,1.30,-40.3,M,-5.2,M,,0123*5F\n\
$GPGSA,A,3,18,32,25,24,23,10,,,,,,,2.86,1.30,2.55*07\n\
$GPGSV,2,1,08,10,40,331,33,14,,,26,18,49,201,46,23,67,017,32*45\n\
$GPGSV,2,2,08,24,48,038,26,25,23,156,45,32,25,284,45,50,59,148,43*7B\n\
$GPGLL,2310.82644,N,11324.94929,E,024040.00,A,D*68\n";

    printf("%s", buff);

	GPRMCSolution(&RMCDate, buff);
    GPVTGSolution(&VTGDate, buff);
    GPGGASolution(&GGADate, buff);
    GPGSASolution(&GSADate, buff);
    GPGLLSolution(&GLLDate, buff);

    return 0;
}

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NMEA是一种通用的串行数据通信协议,用于GPS接收机和其他导航设备之间的数据交换。NMEA协议以ASCII字符形式传输位置、时间、速度等导航信息。 用C语言解析NMEA数据可以分为以下几个步骤: 1. 从串口读取NMEA数据:首先,需要通过C语言提供的串口通信库函数打开串口,设置串口参数,并设置数据接收回调函数。当串口接收到数据时,回调函数将被调用,然后在回调函数中读取接收到的数据。 2. 解析NMEA数据:将接收到的NMEA数据按照格式进行解析NMEA数据通常以"$"字符开始,以回车换行符结束。我们需要根据NMEA协议的规范,使用字符串处理函数从数据中提取需要的信息,例如位置、时间和速度等。 3. 提取数据:根据NMEA协议的规范,每条NMEA数据都有固定的格式和字段顺序。在解析过程中,我们可以根据数据的具体位置使用字符串处理函数截取出需要的数据字段,例如经度、纬度、UTC时间、速度等。 4. 数据处理:根据需要,对提取出的数据进行进一步处理。例如,将经纬度数据转换为可用的数值类型,计算出速度的单位和数值等。 5. 输出结果:根据需要,将处理后的数据进行打印、存储或发送到其他设备。 需要注意的是,NMEA协议有很多不同的消息类型,每个消息类型有特定的数据格式解析规则。在编写C语言解析代码时,需要根据具体的需求和设备使用的消息类型来进行相应的解析处理。同时,也需要处理一些异常情况,例如数据丢失、数据错误或无效数据等,以保证解析的准确性和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值