单片机处理GPS模块数据的方法详解

1.单片机处理部分

预:GPS结构体

typedef struct
{
    int year;
    int month;
    int day;
    int hour;
    int minute;
    int second;
	int ms; 
} DATE_TIME;

typedef struct
{
	    int latitudeint;      //纬度
		int latitudefloat;
		int longitudeint;     //经度
	    int longitudefloat;
        double latitude_Degree;  //纬度,度
        double longitude_Degree; //经度,度
	    double latitude_DegreeStart;
	    double longitude_DegreeStart; //经度,度
	    double delta_latitude;  //纬度变换量
	    double delta_longitude;  //经度变化量
        float speed;          //地面速率
        float direction;      //地面航向
        int satellite;
	    bool informationflag;  //是否有新数据需要处理
	    int setorgdata;  //是否将当前点设置为起点
        u8 NS;
        u8 EW;
        DATE_TIME Time;
} GPS_INFO;

1.GPS信息获取(串口中断执行)

/**
* @description: GPS信号采集
* @Author: Aoiiix && Young
* @param: {type} void
* @tips : 使用串口命令使GPS只发送 GPRMC 最小定位信息
* @return:	1:接收成功   0:未完成接收
* 使用RawGPS全局变量存储数据
*/

u8 GPSGetInf(void)
{
  static u8 count = 0, ReciveFlag = 0,CountBackwardsFlag=0,CountBackwards=3;
  static char buff[80];
  char str;
  if (uart_index[GPSUART]->CSR & UART_CSR_RXAVL) // 读取到一个数据
  	str = (uint8)uart_index[GPSUART]->RDR;	  // 存储一个数据
  if (str == '$')								  //接收到"$",开始接收数据
  {
  	ReciveFlag = 1;
  	memset(buff, 0, sizeof buff);
  }
if (str == '*')      //接收到结束符,开始倒数录入校验和
  {
  	CountBackwardsFlag=1;
  }
  if (CountBackwardsFlag)
  	CountBackwards--;
  if (ReciveFlag == 1) //接受标志位置1开始记录数据
  {
  	buff[count] = str;
  	count++;
  }
  if (CountBackwards==0)
  {
  	ReciveFlag = 0;
  	count = 0;
  	RawGPS = buff;
  	CountBackwards=3;
  	CountBackwardsFlag=0;
  	ReciveFlag=0;
  	GPSInfNode.informationflag = 1;
  }
  return 1;
}

2.由经纬度计算两点距离

理论说明

已知两点经纬度计算距离的具体例子球是一个近乎标准的椭球体,它的赤道半径为6378.140千米,极半径为 6356.755千米,平均半径6371.004千米。如果我们假设地球是一个完美的球体,那么它的半径就是地球的平均半径,记为R。如果以0度经线为基 准,那么根据地球表面任意两点的经纬度就可以计算出这两点间的地表距离(这里忽略地球表面地形对计算带来的误差,仅仅是理论上的估算值)。设第一点A的经 纬度为(LonA, LatA),第二点B的经纬度为(LonB, LatB),按照0度经线的基准,东经取经度的正值(Longitude),西经取经度负值(-Longitude),北纬取90-纬度值(90- Latitude),南纬取90+纬度值(90+Latitude),则经过上述处理过后的两点被计为(MLonA, MLatA)和(MLonB, MLatB)。那么根据三角推导,可以得到计算两点距离的如下公式:C=sin(MLatA)*sin(MLatB)*cos(MLonA-MLonB)+cos(MLatA)*cos(MLatB)Distance=R*Arccos(\C)*Pi/180这里,R和Distance单位是相同,如果是采用6371.004千米作为半径,那么Distance就是千米为单位,如果要使用其他单位,比如mile,还需要做单位换算,1千米=0.621371192mile,如果仅对经度作正负的处理,而不对纬度作90-Latitude(假设都是北半球,南半球只有澳洲具有应用意义)的处理,那么公式将是:C=sin(LatA)*sin(LatB)+cos(LatA)cos(LatB)cos(MLonA-MLonB)Distance=RArccos(\C)Pi/180以上通过简单的三角变换就可以推出。如果三角函数的输入和输出都采用弧度值,那么公式还可以写作:C=sin(LatAPi/180)sin(LatBPi/180)+cos(LatAPi/180)cos(LatBPi/180)cos((MLonA-MLonB)Pi/180)Distance=RArccos(\C)Pi/180也就是:C=sin(LatA/57.2958)sin(LatB/57.2958)+cos(LatA/57.2958)cos(LatB/57.2958)cos((MLonA-MLonB)/57.2958)Distance=RArccos(\C)=6371.004Arccos(\C) kilometer=0.6213711926371.004Arccos(\C)mile=3958.758349716768Arccos(\C) mile

代码实现

```C

/**

  • @description: 计算两点距离

  • @Author: Young

  • @param: 纬度1,经度1,纬度2,经度2

  • @return: 两点距离
    */
    double GetDistant (double latitude1, double longitude1, double latitude2, double longitude2)
    {
    const double EARTH_RADIUS = 6378137;//地球半径(单位:m)
    double rad_latitude1;
    double rad_latitude2;
    double rad_longitude1;
    double rad_longitude2;
    double distance;
    double a;
    double b;

    rad_latitude1 = Angle2Rad(latitude1);//根据角度计算弧度
    rad_latitude2 = Angle2Rad(latitude2);
    rad_longitude1 = Angle2Rad(longitude1);
    rad_longitude2 = Angle2Rad(longitude2);

    a = rad_latitude1 – rad_latitude2;
    b = rad_longitude1 – rad_longitude2;

    distance = 2 * asin(sqrt(pow(sin(a/2),2) + cos(rad_latitude1)cos(rad_latitude2)pow(sin(b/2),2)));
    distance = distance * EARTH_RADIUS;
    if (latitude1 < latitude2)
    return -1
    distance;
    if (longitude1<longitude2)
    return -1
    distance;
    return distance;
    }

  •   亲测十分好用...这个函数是后面使用GPS导航的关键
    

    3.GPS信息解包

    一些预处理函数
    /**
     * @description: GPS数据处理函数
     * @Author: Aoiiix && Young
     * @param: {type} u8* buf     位置数组
     *                char* line  信息指针
     * @return:	NULL
     *  buf[n] : 第n个','位置
     */
    
    void FindComma(u8 *buf, char *line)
    {
    	const char *p = line;
    	u8 times = 0;
    	buf++;
    	while (*(p + times) != '\0')
    	{
    		if (*(p + times) == ',')
    		{
    			*buf = times;
    			buf++;
    			times++;
    		}
    		else
    			times++;
    	}
    }
    /**
     * @description: 字符串转浮点型数据,整散分离
     * @Author: Aoiiix && Young
     * @param: {type} char* buf     信息指针
     *                u8* index   逗号下标数组
     *                u8  第几个逗号后的数据
     *                bool intflag 整型或浮点型
     *                int* num     数据接收数组 0为整数 1为小数
     * @return:	     void
     *
     */
    void GetNumberSeparate(char *buf, u8 *index, u8 n ,int* num)
    {
    	u8 data[20];
    	u8 count = 0;
    	u8 i;
    	u8 point;
    	for (i = 0; i <*(index + n + 1) - *(index + n); i++)
    	{
    		if (i == 0)
    			while (*(buf + *(index + n) + i + 1) == '0') //去掉高位补位0
    				i++;
    		*(data + count) = *(buf + *(index + n) + i + 1);
    		if (*(data + count) == '.')
    			point = count;
    		count++;
    	}
    	for (i = 0; i < count-1; i++)
    	{
    		if (i < point)
    			*num = *num * 10 + (*(data + i) - '0');
    		if (i>point)
    			*(num+1) = *(num+1) * 10 + (*(data + i) - '0');
    	}
    
    }
    /**
     * @description: 字符串转浮点型
     * @Author: Aoiiix && Young
     * @param: {type} char* buf     信息指针
     *                u8* index   逗号下标数组
     *                u8  第几个逗号后的数据
     * @return:	     num
     *
     */
    float GetNumber(char *buf, u8 *index, u8 n)
    {
    	u8 data[10];
    	u8 count = 0;
    	volatile u8 i;
    	int point = 0;
    	bool flag = 0;
    	float num = 0;
    	for (i = 0; i < *(index + n + 1) - *(index + n); i++)
    	{
    		if (i == 0)
    		{while (*(buf + *(index + n) + i + 1) == '0'&&*(buf + *(index + n) + i + 2)!='.') //去掉高位补位0
    				i++;
    			if (*(buf + *(index + n) + i + 1) == '-')
    			{
    				i++;
    				flag = 1;
    			}
    		}
    		*(data + count) = *(buf + *(index + n) + i + 1);
    		if (*(data + count) == '.')
    			point = count;
    		count++;
    	}
    	if (point == 0)  //没有小数点.
    	{
    		 point = 255;
    	}
    	for (i = 0; i < count-1; i++)
    	{
    		if (i < point)
    			num = num * 10 + (*(data + i) - '0');
    		if (i > point)
    			num += (*(data + i) - '0') * myMath_power(0.1, i - point);
    	}
    	if (flag)
    	return -num;
    	else
    		return num;
    }
    
    数据解包函数
    /**
    * @description: GPS数据解包
    * @Author: Aoiiix && Young
    * @param: {type} GPS_INFO* GPS_INFO     GPS信息结构体
    * @return:	  1:信息有效解包成功  0:数据校验无效
    *
    */
    bool GetMainGPS(GPS_INFO *GPS_INFO,bool flag)
    {
      if (flag==0)
      	return 0;
      u8 index[30]={0};
      double degree;
      int time=0,num[2]={0};
      u8  Checksum;                           //校验和
      u8  Result;                             //数据的校验和
      FindComma(index, RawGPS);
      char str = *(RawGPS + index[2] + 1);
      if (*(RawGPS + index[2] + 1) == 'A')    //一次检验数据是否有效
      	 ;
      else
      {
        GPSInfNode.Time.ms=(int)(GetNumber(RawGPS, index,1)*10)%10;
      	return 0;
      }
      str = *(RawGPS+index[12]+5);
      if (str>='A')
      	Checksum=(str-'7')*16;
      else
      	Checksum=(str-'0')*16;
      str = *(RawGPS+index[12]+6);
      if (str>='A')
      	Checksum+=(str-'7');
      else
      	Checksum+=(str-'0');
      Result = *(RawGPS+1);
      while (*(RawGPS+2+time)!='*')
      {
      	Result^=*(RawGPS+2+time);
      	time++;
      }	
      if (Result==Checksum)  
      {
    
      GetNumberSeparate(RawGPS, index,3,num);
      GPSInfNode.latitudeint    = num[0];
      GPSInfNode.latitudefloat  = num[1];
      
      memset(num, 0, sizeof num); 
      
      GetNumberSeparate(RawGPS, index,5,num);
      	
      GPSInfNode.longitudeint   = num[0];
      GPSInfNode.longitudefloat = num[1];
      
      degree = 	GPSInfNode.latitudeint/100 + (GPSInfNode.latitudeint%100)/60.0 + 
                                       (double)GPSInfNode.latitudefloat/100000/60;
      
      GPSInfNode.delta_latitude = degree - GPSInfNode.latitude_Degree; 
      	
      if (degree >30)
      GPSInfNode.latitude_Degree = degree;
      
      degree = GPSInfNode.longitudeint/100 + (GPSInfNode.longitudeint%100)/60.0 + 
                                       (double)GPSInfNode.longitudefloat/100000/60;	
    
      GPSInfNode.delta_longitude = GPSInfNode.longitude_Degree - degree;
      
      if (degree > 120)
      GPSInfNode.longitude_Degree = degree;
    
      GPSInfNode.NS          = *(RawGPS+index[4]+1);
      GPSInfNode.EW          = *(RawGPS+index[6]+1);
      
      memset(num, 0, sizeof num);
      
      GetNumberSeparate(RawGPS, index,8,num);
      
      GPSInfNode.direction   = num[0] + num[1]*0.01;
      
      time=(int)GetNumber(RawGPS, index,1);
      
      GPSInfNode.Time.hour   = time/10000;
      GPSInfNode.Time.hour   = GPSInfNode.Time.hour+8-(GPSInfNode.Time.hour+8>=24)*24;
      GPSInfNode.Time.minute = (time/100)%100;
      GPSInfNode.Time.second = time%100;
      GPSInfNode.speed       = GetNumber(RawGPS, index, 7);
      
      GPSInfNode.Time.ms=(int)(GetNumber(RawGPS, index,1)*10)%10;  //把ms放在最后,拿ms是否变化作为接收并完成一次转化的标志
      
      GPSInfNode.informationflag = 0;  //清除GPS信息标志位
    
    
      
      return 1;
      }
      else
      	return 0;
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 单片机处理GPS模块数据的方法详解

    发表评论