单片机处理GPS模块信息

这篇具有很好参考价值的文章主要介绍了单片机处理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;
    }文章来源地址https://www.toymoban.com/news/detail-814183.html

  亲测十分好用...这个函数是后面使用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;
}

到了这里,关于单片机处理GPS模块信息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式开发:单片机嵌入式Linux学习路径

    SOC(System on a Chip)的本质区别在于架构和功能。低端SOC如基于Cortex-M架构的芯片,如STM32和NXP LPC1xxx系列,不具备MMU(Memory Management Unit),适用于轻量级实时操作系统如uCOS和FreeRTOS。高端SOC如基于Cortex-A架构的芯片,如三星、高通、飞卡、全志和瑞芯微等,具备MMU,支持虚拟内

    2024年02月15日
    浏览(37)
  • 嵌入式(二)单片机基础 | 单片机特点 内部结构 最小系统 电源 晶振 复位

    上一篇文章我们介绍了嵌入式系统 嵌入式系统(Embedded System)是一种特定用途的计算机系统,它通常嵌入在更大的产品或系统中,用于控制、监测或执行特定的任务。这些系统通常由硬件和软件组成,旨在满足特定的需求,如嵌入在家电、汽车、医疗设备、工业自动化、消费

    2024年02月02日
    浏览(88)
  • 单片机(嵌入式)程序分层架构

    目录 前言 嵌入式3层软件架构 嵌入式4层软件架构-1 驱动层 操作系统层 中间件层 应用层 嵌入式4层软件架构-2 硬件层 嵌入式微处理芯片 嵌入式存储器系统 嵌入式I/O接口 中间层 系统软件层 RTOS 文件系统 GUI 应用层 嵌入式5层软件架构1 嵌入式5层软件架构2 嵌入式6层软件架构

    2023年04月19日
    浏览(65)
  • 单片机和Linux嵌入式区别

    单片机是一种集成电路,它能够在一个芯片上完成各种计算、控制和管理任务。单片机没有明确的分层,这是因为它通常被用来设计嵌入式系统,其程序结构和功能要根据具体的应用需求来设计。 在单片机的程序设计中,可以通过一些方法将程序分为不同的层次,比如可以将

    2024年01月17日
    浏览(52)
  • 【单片机/嵌入式】最完整学习路线

            关于这个问题我在网上寻找到 了 相关文章解释得很详细,不了解的同学可以参考一下这篇文章: 到底什么是嵌入式?什么是单片机? - 知乎         一个人学习是孤独的,如果你是一名学生,建议加入学校的电子社团或者实验室,有老师的帮助和同学的互助

    2024年02月03日
    浏览(39)
  • 【唠唠嵌入式】__如何学习单片机?

    目录 前言 个人定位,从事软件还是硬件? 学习内容 (* ̄︶ ̄)创作不易!期待你们的 点赞、收藏和评论喔。 作为一个老司机,多年来跟 单片机 、 Keil 、 C语言 、 AD 、 烙铁 、 风枪 、 示波器 、 电子元器件 纠缠不清。期间经历了不少磨练,熬过了很多夜晚,也掉了大把头

    2024年02月06日
    浏览(49)
  • 嵌入式51单片机04-矩阵按键系列

    一、矩阵按键基础知识 矩阵按键工作原理 : 逐行扫描 :通过高四位轮流输出低电平来对矩阵键盘进行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过判断低四位数据中哪一位为零来判断哪一个按键被按下。 逐列扫描 :通过低四位轮流输出低电平来

    2024年02月07日
    浏览(49)
  • 单片机项目分享 stm32机器视觉的人脸识别系统 - 单片机 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年01月22日
    浏览(59)
  • 【单片机毕设选题】stm32实现车牌识别系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(43)
  • 单片机项目分享 基于stm32的便携用电功率统计系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月19日
    浏览(76)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包