C语言解析GPS :GPGGA\GPRMC数据

这段代码展示了如何在C语言中解析GPS数据,特别是GPGGA和GPRMC报文。程序定义了数据结构来存储时间、经纬度、状态等信息,并提供了分析这两个类型报文的函数。通过UART接收GPS数据,然后根据接收到的数据进行解析并打印相关信息。
摘要由CSDN通过智能技术生成

C语言解析GPS :GPGGA\GPRMC数据

#ifndef _GN_GPSINFO_H__
#define _GN_GPSINFO_H__

typedef   int				i4;
typedef   unsigned int		u4;
typedef   short             i2;
typedef   unsigned short    u2;
typedef   signed char		i1;
typedef   unsigned char     u1;
typedef   float             f4;
typedef   double			f8;


#define  ASCLL_DATA_$           '$'
#define  ASCLL_DATA_GPGGA       "$GPGGA"
#define  ASCLL_DATA_GPRMC       "$GPRMC"


#define  MAX_RCV_SIZE			1024*5
#define  GPGGA_HEAD_LEN			0x06
#define  CMP_SUCCESS			0x00
#define  CMP_ERROR				0x01

#define     _switchState(a)         pblkUartRcv->u1State = a

enum
{
	RCV_STATE_IDIE = 0,
	RCV_STATE_START,
	RCV_GPGGA_HEAD,
	RCV_GPRMC_HEAD
};

typedef struct
{
	u1	u1AscllName[10];
	u1	u1sizeof;
	u1	u1Head;
}GPS_ASCLLINFO;
typedef struct UartRcvTag
{
	u1 u1RcvBuff[MAX_RCV_SIZE];
	u1 u1State = 0;
	u1 u1DataLen;
	u1 u1Len;
}BlkUartRcv;

//UTC时间信息
typedef struct
{
	u2 year;	//年份
	u1 month;	//月份
	u1 date;	//日期
	u1 hour; 	//小时
	u1 min; 	//分钟
	u1 sec; 	//秒钟
	u1 ssec;	//毫秒
}gps_utc_time;

typedef struct
{
	gps_utc_time	utc_time;			// UTC时间
	f8	latitude_value;					// 纬度
	u1	latitude;						// 纬度半球
	f8	longtitude_value;				// 经度
	u1	longitude;						// 经度半球
	u1	gps_state;						// GPS状态 0=未定位,1=非差分定位,2=差分定位,6=正在估算
	u1	sate_num;						// 解算位置卫星数量
	f4	hdop;							// HDOP水平精度因子
	f4	altitude;						// 海拔高度
}GPGGA_INFO;



typedef struct
 {
	 gps_utc_time utc_time;		// UTC时间
	 u1 gps_state;				// 定位状态
	 f8 latitude_value;			// 纬度
	 u1 latitude;				// 纬度半球
	 f8 longtitude_value;		// 经度
	 u1 longtitude;				// 经度半球
	 f4 speed;					// 地面速率
	 f4 azimuth_angle;			// 地面航向

}GPRMC_INFO;

int _Str2num(u1 *buf, u1*dx);

void _GPRMC_Analysis(GPRMC_INFO *gps_rmc_info, u1 *buf);
void _GPGGA_Analysis(GPGGA_INFO *gps_gga_info, u1 *buf);

#endif

// uart_test.cpp : 定义控制台应用程序的入口点。
//
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "gps_info.h" 				   
#include "stdarg.h"	 
#include "math.h"


GPS_ASCLLINFO Ascll_Info[2] = {
	ASCLL_DATA_GPGGA, 0x06, RCV_GPGGA_HEAD,
	ASCLL_DATA_GPRMC, 0x06, RCV_GPRMC_HEAD

};
BlkUartRcv blkUartRcv;
GPGGA_INFO gga_info;
GPRMC_INFO gmc_info;

//从buf里面得到第num个逗号所在的位置
//返回值:0~0xFE,代表逗号所在位置的偏移.
//       0xFF,代表不存在第num个逗号							  
u1 _Find_Pos(u1 *buf, u1 u1Num)
{
	u1 *p = buf;
	while (u1Num)
	{
		if (*buf == '*' || *buf<' ' || *buf>'z')return 0xFF;//遇到'*'或者非法字符,则不存在第num个逗号
		if (*buf == ',')u1Num--;
		buf++;
	}
	return buf - p;
}

//m^n函数
//返回值:m^n次方.
u4 _Pow(u1 m, u1 n)
{
	u4 result = 1;
	while (n--)result *= m;
	return result;
}
//str转换为数字,以','或者'*'结束
//buf:数字存储区
//dx:小数点位数,返回给调用函数
//返回值:转换后的数值
int _Str2num(u1 *buf, u1*dx)
{
	u1 *p = buf;
	u4 ires = 0, fres = 0;
	u1 ilen = 0, flen = 0, i;
	u1 mask = 0;
	double res;
	while (1) //得到整数和小数的长度
	{
		if (*p == '-'){ mask |= 0x02; p++; }//是负数
		if (*p == ',' || (*p == '*'))break;//遇到结束了
		if (*p == '.'){ mask |= 0x01; p++; }//遇到小数点了
		else if (*p>'9' || (*p<'0'))	//有非法字符
		{
			ilen = 0;
			flen = 0;
			break;
		}
		if (mask & 0x01)flen++;
		else ilen++;
		p++;
	}
	if (mask & 0x02)buf++;		//去掉负号
	for (i = 0; i<ilen; i++)	//得到整数部分数据
	{
		ires += _Pow(10, ilen - 1 - i)*(buf[i] - '0');
	}
	if (flen>5)flen = 5;	//最多取5位小数
	*dx = flen;	 			//小数点位数
	for (i = 0; i<flen; i++)	//得到小数部分数据
	{
		fres += _Pow(10, flen - 1 - i)*(buf[ilen + 1 + i] - '0');
	}
	res = ires*_Pow(10, flen) + fres;
	if (mask & 0x02)res = -res;
	return res;
}

//分析GPRMC信息
//buf:接收到的GPS数据缓冲区首地址
void _GPRMC_Analysis(GPRMC_INFO *gps_rmc_info, u1 *buf)
{
	u1 *p1, dx;
	u1 posx;
	u4 temp;
	float rs;

	p1 = (u1*)strstr((const char *)buf, "$GPRMC");				// "$GPRMC"
	if (p1 == NULL){
		return;
	}

	posx = _Find_Pos(p1, 1);									// 得到UTC时间
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx) / _Pow(10, dx);			// 得到UTC时间,去掉ms	 	
		gps_rmc_info->utc_time.hour = temp / 10000;
		gps_rmc_info->utc_time.min = (temp / 100) % 100;
		gps_rmc_info->utc_time.sec = temp % 100;
		gps_rmc_info->utc_time.ssec = _Str2num(p1 + posx, &dx) % _Pow(10, dx);
		printf("GPS UTC 小时:%d 分钟:%d 秒:%d 毫秒:%d \n\r",
			gps_rmc_info->utc_time.hour,
			gps_rmc_info->utc_time.min,
			gps_rmc_info->utc_time.sec,
			gps_rmc_info->utc_time.ssec);
	}

	posx = _Find_Pos(p1, 2);									// 得到定位状态
	if (posx != 0xFF){
		gps_rmc_info->gps_state = *(p1 + posx);
		printf("GPS卫星状态:%c \n\r", gps_rmc_info->gps_state);
	}

	posx = _Find_Pos(p1, 3);									// 得到纬度值
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_rmc_info->latitude_value = (f8)temp / (f8)_Pow(10, dx);
		printf("GPS纬度值:%.5f \n\r", gps_rmc_info->latitude_value);
	}

	posx = _Find_Pos(p1, 4);									// 南纬还是北纬
	if (posx != 0xFF){
		gps_rmc_info->latitude = *(p1 + posx);
		printf("GPS纬度:%c \n\r", gps_rmc_info->latitude);
	}

	posx = _Find_Pos(p1, 5);									// 得到经度值
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_rmc_info->longtitude_value = (f8)temp / (f8)_Pow(10, dx);
		printf("GPS经度值:%.5f \n\r", gps_rmc_info->longtitude_value);
	}

	posx = _Find_Pos(p1, 6);									// 东经还是西经
	if (posx != 0xFF){
		gps_rmc_info->longtitude = *(p1 + posx);
		printf("GPS经度:%c \n\r", gps_rmc_info->longtitude);
	}

	posx = _Find_Pos(p1, 7);									// 速度
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_rmc_info->speed = (f4)temp / (f4)_Pow(10, dx);
		printf("GPS速度值:%.3f \n\r", gps_rmc_info->speed);
	}

	posx = _Find_Pos(p1, 8);									// 地面航向
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_rmc_info->azimuth_angle = (f4)temp / (f4)_Pow(10, dx);
		printf("GPS速度值:%.3f \n\r", gps_rmc_info->azimuth_angle);
	}

	posx = _Find_Pos(p1, 9);									//得到UTC日期
	if (posx != 0xFF)
	{
		temp = _Str2num(p1 + posx, &dx);		 				//得到UTC日期
		gps_rmc_info->utc_time.date = temp / 10000;
		gps_rmc_info->utc_time.month = (temp / 100) % 100;
		gps_rmc_info->utc_time.year = 2000 + temp % 100;
		printf("GPS UTC 年:%d 月:%d 日:%d \n\r",
			gps_rmc_info->utc_time.year,
			gps_rmc_info->utc_time.month,
			gps_rmc_info->utc_time.date);
	}
}


//分析GPGGA信息
//buf:接收到的GPS数据缓冲区首地址
void _GPGGA_Analysis(GPGGA_INFO *gps_gga_info, u1 *buf)
{
	u1 *p1, dx;
	u1 posx;
	u4 temp;
	float rs;

	p1 = (u1*)strstr((const char *)buf, "$GPGGA");				// "$GPRMC"
	if ( p1 == NULL ){
		return;
	}

	posx = _Find_Pos(p1, 1);									// 得到UTC时间
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx) / _Pow(10, dx);		// 得到UTC时间,去掉ms	 	
		gps_gga_info->utc_time.hour = temp / 10000;
		gps_gga_info->utc_time.min = (temp / 100) % 100;
		gps_gga_info->utc_time.sec = temp % 100;
		gps_gga_info->utc_time.ssec = _Str2num(p1 + posx, &dx) % _Pow(10, dx);
		printf("GPS UTC 小时:%d 分钟:%d 秒:%d 毫秒:%d \n\r",
			gps_gga_info->utc_time.hour,
			gps_gga_info->utc_time.min,
			gps_gga_info->utc_time.sec,
			gps_gga_info->utc_time.ssec);
	}

	posx = _Find_Pos(p1, 2);									// 得到纬度值
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_gga_info->latitude_value = (f8)temp / (f8)_Pow(10, dx);
		printf("GPS纬度值:%.5f \n\r", gps_gga_info->latitude_value);
	}

	posx = _Find_Pos(p1, 3);									// 南纬还是北纬
	if (posx != 0xFF){
		gps_gga_info->latitude = *(p1 + posx);
		printf("GPS纬度:%c \n\r", gps_gga_info->latitude);
	}

	posx = _Find_Pos(p1, 4);									// 得到经度值
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_gga_info->longtitude_value = (f8)temp / (f8)_Pow(10, dx);
		printf("GPS经度值:%.5f \n\r", gps_gga_info->longtitude_value);
	}

	posx = _Find_Pos(p1, 5);									// 东经还是西经
	if (posx != 0xFF){
		gps_gga_info->longitude = *(p1 + posx);
		printf("GPS经度:%c \n\r", gps_gga_info->longitude);
	}

	posx = _Find_Pos(p1, 6);									// GPS状态
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_gga_info->gps_state = temp;
		printf("GPS状态值:%d \n\r", gps_gga_info->gps_state);
	}

	posx = _Find_Pos(p1, 7);									// 卫星数量
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_gga_info->sate_num = temp;
		printf("GPS卫星数量:%d \n\r", gps_gga_info->sate_num);
	}

	posx = _Find_Pos(p1, 8);									// HDOP水平精度因子
	if (posx != 0xFF){
		gps_gga_info->hdop = (f4)temp / (f4)_Pow(10, dx);
		printf("HDOP水平精度因子:%f \n\r", gps_gga_info->hdop);
	}

	posx = _Find_Pos(p1, 9);									// 海拔高度
	if (posx != 0xFF){
		temp = _Str2num(p1 + posx, &dx);
		gps_gga_info->altitude = (f4)temp / (f4)_Pow(10, dx);
		printf("海拔高度:%f \n\r", gps_gga_info->altitude);
	}
}


void _ResetUartRcvBuff()
{
	memset(&blkUartRcv, 0, sizeof(BlkUartRcv));
}

void GN_UartRcvGPSInfo(u1 u1Data)
{
	int check, sum, hour, min, sec;
	BlkUartRcv	*pblkUartRcv = &blkUartRcv;
	u1			*pu1Buff = pblkUartRcv->u1RcvBuff;
	u1			u1size = 0;
	char			u1utc[20];
	if ((u1Data == ASCLL_DATA_$) &&
		(pblkUartRcv->u1State == RCV_STATE_IDIE)){
		pblkUartRcv->u1State = RCV_STATE_START;
	}

	if (pblkUartRcv->u1DataLen >= MAX_RCV_SIZE){
		_ResetUartRcvBuff();
	}

	switch (pblkUartRcv->u1State){
	case RCV_STATE_START:
		pu1Buff[pblkUartRcv->u1DataLen++] = u1Data;
		if (u1Data == '\n'){
			for (u1size = 0; u1size < sizeof(Ascll_Info) / sizeof(GPS_ASCLLINFO); u1size++){
				if (CMP_SUCCESS == memcmp(&pu1Buff[0], Ascll_Info[u1size].u1AscllName, Ascll_Info[u1size].u1sizeof)){
					_switchState(Ascll_Info[u1size].u1Head);
				}
			}
		}
		break;
	case RCV_GPGGA_HEAD:

		printf("-----GPGGA------ \r\n");
		printf("GPGGA:%s \r\n",pu1Buff);
		_GPGGA_Analysis(&gga_info, pu1Buff);	// GPGGA解析函数
		_ResetUartRcvBuff();
		break;
	case RCV_GPRMC_HEAD:

		printf("-----GPRMC------ \r\n");
		printf("GPRMC:%s \r\n", pu1Buff);
		_GPRMC_Analysis(&gmc_info, pu1Buff);	// GPRMC解析函数
		_ResetUartRcvBuff();
		break;
		break;
	default:
		break;
	}
END:
	return;
}

int main()
{
	// $GPGGA,105547.00,3959.99990484,N,11559.73608378,E,1,10,0.9,555.1075,M,-9.2296,M,,*7A\r\n
	// $GPRMC,105546.00,A,3959.99990614,N,11559.73608463,E,0.004,300.7,140622,5.7,W,A*22\r\n
	u1 nema_gga[] = "$GPRMC,105546.000,A,3959.99990614,N,11559.73608463,E,0.004,300.7,140622,5.7,W,A*22\r\n $GPGGA,105547.00,3959.99990484,N,11559.73608378,E,1,10,0.9,555.1075,M,-9.2296,M,,*7A\r\n";

	memset(&gmc_info, 0x00, sizeof(gmc_info));
	int i = sizeof(nema_gga);

	for (i = 0; i <= sizeof(nema_gga); i++){
		GN_UartRcvGPSInfo(nema_gga[i]);
	}

	getchar();
	return 0x00;
}
运行结果:



运行结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值