STM32使用HAL库获取GPS模块HT1818Z3G5L信息(方法1)

news2025/1/11 23:36:54

1、写在最前

先了解一下GPRMC的格式
格 式:
GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,A*50
说 明:
字段 0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段 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:校验值

2、配置

使用STM32F103C8T6的串口1,连接模块的串口。
此模块4个引脚标注为“V G T R”
在这里插入图片描述

功能:
V = 3.3V
G = GND
T = TX
R = RX

STM32CUBE配置如下:
在这里插入图片描述
在这里插入图片描述
记得开启串口中断。

3、程序编写

1、先使用单字节接收方式,因为每个帧的结构都是$开头,0x0d,0x0a结尾。如果使用空闲接收的话,这个模块一次发送的数据比较大,需要大几百字节的缓存。
首先在main函数中,先定义需要的全局变量

uint8_t g_ucRxByte;
uint8_t g_ucRxCnt;
uint8_t g_ucaRx[GPS_BUFF_SIZE];
rtcType_T g_tRtcCN;
float g_fSpeed;

在这里插入图片描述
2、进入主循环之前,开启串口接收

  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1,&g_ucRxByte,1);
  /* USER CODE END 2 */

3、编写GPS.h头文件

#ifndef __GPS_H
#define __GPS_H
#include "main.h"

#define GPS_BUFF_SIZE	100

typedef struct
{
	uint16_t usYear;
	uint8_t ucMonth;
	uint8_t ucDay;
	uint8_t ucHour;
	uint8_t ucMinute;
	uint8_t ucSecond;
}rtcType_T;

extern uint8_t g_ucaGNRMC[GPS_BUFF_SIZE];
extern uint8_t g_ucGNRMCRxSta;

uint8_t GPS_GetTime(char *cpRmc,rtcType_T *tpRTC);/*从RMC(推荐最小定位信息)中获取GPS的时间信息,东8区时间*/
rtcType_T GPS_TimeToArea(rtcType_T tTime, uint8_t ucArea);/*转换GPS时间到指定区的时间*/
float GPS_GetSpeed(char *cpRmc);

#endif

4、编写GPS.c文件

#include "gps.h"
#include "string.h"
#include "stdlib.h"

uint8_t g_ucaGNRMC[GPS_BUFF_SIZE];
uint8_t g_ucGNRMCRxSta;


uint8_t GPS_GetTime(char *cpRmc,rtcType_T *tpRTC)
{
	char *cpStart;
	uint8_t i;

	cpStart = strchr(cpRmc,',');
	
	tpRTC->ucHour = (cpStart[1]-0x30)*10 + (cpStart[2]-0x30) ;/**/

	tpRTC->ucMinute = (cpStart[3]-0x30)*10 + (cpStart[4]-0x30);
	tpRTC->ucSecond = (cpStart[5]-0x30)*10 + (cpStart[6]-0x30);
	
	cpStart = cpRmc;
	for(i = 0;i < 9;i++)
	{
		cpStart = strchr(cpStart,',');
		cpStart++;
	}
	tpRTC->ucDay = (cpStart[0]-0x30)*10 + (cpStart[1]-0x30);
	tpRTC->ucMonth = (cpStart[2]-0x30)*10 + (cpStart[3]-0x30);
	tpRTC->usYear = (cpStart[4]-0x30)*10 + (cpStart[5]-0x30) + 2000;
	
	return 1;

}


rtcType_T GPS_TimeToArea(rtcType_T tTime, uint8_t ucArea)
{
	rtcType_T tConvertTime;
	tConvertTime = tTime;
	tConvertTime.ucHour += ucArea;
	if(1==tConvertTime.ucMonth||3==tConvertTime.ucMonth||5==tConvertTime.ucMonth||7==tConvertTime.ucMonth||8==tConvertTime.ucMonth||10==tConvertTime.ucMonth||12==tConvertTime.ucMonth)//1,3,5,7,8,9,12月每月为31天
	{
		if(24 <= tConvertTime.ucHour)
		{
			tConvertTime.ucHour -= 24;
			tConvertTime.ucDay += 1;//如果超过24小时,减去24小时,后再加上一天
			if(tConvertTime.ucDay > 31)
			{
				tConvertTime.ucDay -= 31;
				tConvertTime.ucMonth += 1;
			}//如果超过31一天,减去31天,后加上一个月
		}
	}
	else if(4==tConvertTime.ucMonth||6==tConvertTime.ucMonth||9==tConvertTime.ucMonth||11==tConvertTime.ucMonth)//4,6,9,11月每月为30天
	{
		if(24 <= tConvertTime.ucHour)
		{
			tConvertTime.ucHour -= 24;
			tConvertTime.ucDay += 1;//如果超过24小时,减去24小时,后再加上一天
			if(30 < tConvertTime.ucDay)
			{
				tConvertTime.ucDay -= 30;
				tConvertTime.ucMonth += 1;
			}//如果超过30一天,减去30天,后加上一个月
		}
	}
	else//剩下为2月,闰年为29天,平年为28天
	{
		if(24 <= tConvertTime.ucHour)
		{
			tConvertTime.ucHour -= 24;
			tConvertTime.ucDay += 1;
			if((0 == tConvertTime.usYear%400)||(0 == tConvertTime.usYear%4 && 0 != tConvertTime.usYear%100))//判断是否为闰年,年号能被400整除或年号能被4整除,而不能被100整除为闰年
			{
				if(29 < tConvertTime.ucDay)
				{
					tConvertTime.ucDay -= 29;
					tConvertTime.ucMonth += 1;
				}
			}//为闰年
			else
			{
				if(28 < tConvertTime.ucDay)
				{
					tConvertTime.ucDay -= 28;
					tConvertTime.ucMonth += 1;
				}
			}//为平年
		}
 
	}
	if(12 < tConvertTime.ucMonth)
	{
		tConvertTime.ucMonth-=12;
		tConvertTime.usYear+=1;
	}
	return tConvertTime;
}

/*GNRMC的第7个字段为速度,节,Knots(一节也是1.852千米/小时)*/
float GPS_GetSpeed(char *cpRmc)
{
	float fSpeed;
	char *cpStart,*cpEnd,*ptr;
	uint8_t i,ucLenth;
	char caTmp[10];
	
	memset(caTmp,0,10);
	
	cpStart = cpRmc;
	for(i = 0;i < 7;i++)
	{
		cpStart = strchr(cpStart,',');
		cpStart++;
	}
	cpEnd = strchr(cpStart,',');
	ucLenth = cpEnd - cpStart;
	memcpy(caTmp,cpStart,ucLenth);
	caTmp[ucLenth] = '\0';
	fSpeed = strtof(caTmp,&ptr);
	fSpeed = fSpeed * 1.852;
	return fSpeed;
}

文件中使用了字符串转浮点数函数,如果不需要速度,可以取消,同时无需包含#include “stdlib.h”

5、返回主函数,进行中断回调函数的编写。

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(g_ucRxByte == '$')
	{
		g_ucRxCnt = 0;
	}
	else if(g_ucRxByte == 0x0a)/*一帧结束*/
	{
		if(g_ucaRx[0]=='$' && g_ucaRx[4]=='M' && g_ucaRx[5]=='C')/*只提取GNRMC*/
		{
			memcpy(g_ucaGNRMC,g_ucaRx,g_ucRxCnt);
			g_ucGNRMCRxSta = g_ucRxCnt | 0x80;
		}
	}
	
	g_ucaRx[g_ucRxCnt++] = g_ucRxByte;
	
	if(g_ucRxCnt >= GPS_BUFF_SIZE)	
	{
		g_ucRxCnt = 0;
	}
	
	HAL_UART_Receive_IT(&huart1,&g_ucRxByte,1);
}
/* USER CODE END 4 */

6、使用模块
在主循环中,解析获取的GNRMC数据。

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if(g_ucGNRMCRxSta & 0x80)
	  {
		  g_ucGNRMCRxSta = 0;
		  GPS_GetTime((char *)g_ucaGNRMC,&tRTCGps);
		  g_tRtcCN = GPS_TimeToArea(tRTCGps,8);
		  g_fSpeed = GPS_GetSpeed((char *)g_ucaGNRMC);
	  }
  }
  /* USER CODE END 3 */

在这里插入图片描述

7、结果
在这里插入图片描述

4、写在最后

这个模块一般般吧,我把模块放到靠近窗户,定位时有时无,定位成功后,静止状态的速度也会跳动。如果需要获取有效的速度信号,可能需要其他辅助,例如运动检测等判断是否在静止状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1573447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【服务器部署篇】Linux下安装Docker容器

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

计算机网络——37认证

认证 目标&#xff1a;Bob需要Alice证明他的身份 Protocol ap1.0&#xff1a;Alice说"A am Alice" 可能出现的问题&#xff1a; 在网络上Bob看不到Alice&#xff0c;因此Trudy可以简单的声称他是Alice 认证&#xff1a;重新尝试 Protocol ap2.0&#xff1a;Alice…

继电器线圈两端为什么要反向并联二极管

原理描述&#xff1a; 电感的特点&#xff1a;穿过电感的电流不会突然变化&#xff0c;也就是说变化的电流在电感上面会产生感应电动势。 感应电动势的作用&#xff1a;阻碍电流的变化。 三极管断开之前&#xff0c;电流是穿过线圈&#xff0c;原来的电流是从上往下流动&#…

自定义实现shell/bash

文章目录 函数和进程之间的相似性shell打印提示符&#xff0c;以及获取用户输入分割用户的输入判断是否是内建命令执行相关的命令 全部代码 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#…

数据结构和算法:分治

分治算法 分治&#xff08;divide and conquer&#xff09;&#xff0c;全称分而治之&#xff0c;是一种非常重要且常见的算法策略。分治通常基于递归实现&#xff0c;包括“分”和“治”两个步骤。 1.分&#xff08;划分阶段&#xff09;&#xff1a;递归地将原问题分解为两个…

C语言自定义类型变量——枚举(enum)

一.枚举的定义和声明 字面意思&#xff0c;枚举就是一一列举&#xff0c;把可能的取值一一列举&#xff0c;在我们现实生活中有许多可以列举的事物&#xff0c;例如&#xff1a;一周七天&#xff0c;一年四季&#xff0c;性别&#xff0c;月份&#xff0c;三原色等等。当我们需…

vim美化配置(懒人版)

文章目录 配置vim&#xff08;懒人版&#xff09;1.搜索资源2.安装3.自定义缩进4.卸载方法 配置vim&#xff08;懒人版&#xff09; 1.搜索资源 打开gitee&#xff0c;注意到上面的搜索框 搜索 vimforcpp 进入&#xff0c;找到安装方法中的链接 2.安装 复制粘贴到linux中的命…

【JavaWeb】Day36.MySQL概述——数据库设计-DDL(三)

查询 关于表结构的查询操作&#xff0c;工作中一般都是直接基于图形化界面操作。 1.查询当前数据库所有表 2.查看指定表结构 3.查询指定表的建表语句 注意&#xff1a;23版的点击导航中的转到DDL 修改 关于表结构的修改操作&#xff0c;一般也是直接基于图形化界面操作。 添…

Linux基础篇:Linux第三方软件仓库——可以让Linux变得有趣的软件仓库

Linux第三方软件仓库——可以让Linux变得有趣的软件仓库 一、epel源介绍 EPEL&#xff08;Extra Packages for Enterprise Linux&#xff09;源是一个由Fedora项目组维护的第三方软件仓库&#xff0c;为企业级Linux发行版&#xff08;如Red Hat Enterprise Linux&#xff08;…

2024年阿里云新购、升级及续费活动大全

随着云计算技术的不断发展和普及&#xff0c;越来越多的企业和个人开始选择将业务和数据迁移到云端。作为国内领先的云计算服务提供商&#xff0c;阿里云一直致力于为用户提供更加稳定、高效和安全的云服务。2024年&#xff0c;阿里云继续推出了丰富的新购、升级及续费活动&…

读所罗门的密码笔记12_群雄逐鹿(上)

1. 国际电信规则 1.1. 美国坚持互联网自由和极少的内容限制&#xff0c;这一立场肯定会遭到许多国家的反对 1.2. 除去两个各方针锋相对、无法妥协的议题&#xff0c;比如内容限制规定&#xff0c;实际上所有国家都已在打击垃圾邮件和常见网络安全威胁方…

【苍穹外卖】sql自动补全列名

第一步要设置IDEA与MySQL的链接 右侧的Database 加号 Data Source ----MySQL 填一下用户名密码就行&#xff0c;然后测试连接。可能会有时区问题&#xff0c;他让你点什么你就点 完了之后&#xff0c;他的表好像只有bank下面的那一个&#xff0c;要把所有的表都调出来&…

SpringBoot属性配置的多种方式

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot属性配置的多种方式 📚个人知识库: Leo知识库,欢迎大家访问 目录 …

一些Java面试题

1、 Java语言有哪些特点 1、简单易学、有丰富的类库 2、面向对象&#xff08;Java最重要的特性&#xff0c;让程序耦合度更低&#xff0c;内聚性更高&#xff09; 3、与平台无关性&#xff08;JVM是Java跨平台使用的根本&#xff09; 4、可靠安全 5、支持多线程 2、面向对象和…

软件无线电原理

常规软件无线电接收器&#xff1a; 首先&#xff0c;来自天线的射频信号被放大&#xff0c;通常射频部分利用一个调谐器将感兴趣的频段区域的信号进行放大。这个放大的射频信号被送入一个混频器。来自本振的信号也被送入混频器&#xff0c;其频率由无线电的调谐控制决定。混频器…

【.Net】DotNetty

文章目录 概述NIO和BIO、AIODotNetty适用场景DotNetty的整体架构和模块DotNetty的使用示例来源 概述 本系列文章主要讲述由微软Azure团队研发的.net的版本的netty&#xff0c;Dotnetty。所有的开发都将基于.net core 3.1版本进行开发。 Dotnetty是什么&#xff0c;原本Netty是…

UART设计

一、UART通信简介 通用异步收发器&#xff0c; 特点&#xff1a;串行、异步、全双工通信 优点&#xff1a;通信线路简单&#xff0c;传输距离远 缺点&#xff1a;传输速度慢 数据传输速率&#xff1a;波特率&#xff08;单位&#xff1a;baud&#xff0c;波特&#xff09; …

重装系统之后,电脑连网卡都没反应怎么办?

前言 有些电脑比较奇葩&#xff0c;安装完成之后会出现网卡连驱动都没有&#xff0c;这时候要安装电脑驱动可是真的烦躁。怎么下手呢&#xff1f; 如果确定电脑的网卡型号还好&#xff0c;直接找个电脑下载个对应的网卡驱动&#xff0c;用U盘复制过去就能安装。 但如果不知道…

golang 选择排序

学习笔记&#xff5e; // Author sunwenbo // 2024/4/6 21:49 package mainimport "fmt"/* 选择排序基本介绍选择式排序也属于内部排序法&#xff0c;是从预排序的数据中按指定的规则选出某一元素&#xff0c;经过和其他元素重整&#xff0c;再依原则交换位置后达到…

Java集合——Map、Set和List总结

文章目录 一、Collection二、Map、Set、List的不同三、List1、ArrayList2、LinkedList 四、Map1、HashMap2、LinkedHashMap3、TreeMap 五、Set 一、Collection Collection 的常用方法 public boolean add(E e)&#xff1a;把给定的对象添加到当前集合中 。public void clear(…