手把手教你一步步从零玩转 STM32 GPS:HAL 库驱动 NEO-6M 获取时间经纬度
一模块介绍NEO-6M GPS 模块1. 模块核心特性型号NEO-6M 是嵌入式开发中最常用的民用 GPS 定位模块通信方式UART 串口TTL 电平默认配置9600波特率、8N1输出协议标准NMEA-0183定位协议自动发送多帧定位数据核心数据帧$GPRMC帧包含✅ UTC 时间 / 日期 ✅ 经纬度原始数据 ✅ 定位有效状态 ✅ 速度航向信息硬件接口共 4 个引脚VCC、GND、TX、RX3.3V 供电切记需要到室外该模块室内无法获取信息2. 硬件连接规则STM32 ↔ NEO-6MVCC ↔ 3.3VGND ↔ GNDUSART2_RX(PA3)↔ GPS_TXUSART2_TX(PA2)↔ GPS_RX3. 定位说明模块需要在室外空旷环境才能定位成功室内 / 遮挡环境会提示定位无效。二初始化STM32CUBEMX 配置步骤本工程使用USART2接收 GPS 数据按照以下步骤配置步骤 1基础系统配置选择你的 STM32 芯片型号如 STM32F103C8T6RCC 配置选择外部晶振HSE配置系统时钟为 72MHz选择外部晶振作为系统时钟设置为72Mhz时钟主频 速度更快3.SYS 配置Debug 选择 Serial Wire如果没勾选可能导致下一次无法烧录需要通过拉BOOT。开启SW调试下载模式步骤 2USART2 串口配置左侧Connectivity→ 选择USART2模式选择Asynchronous异步通信参数设置与 GPS 模块一致波特率9600字长8 Bits校验位None停止位1无需修改硬件默认引脚TXPA2RXPA3。选择串口2异步模式设置为9600波特率步骤 3开启串口接收中断左侧System Core→NVIC勾选USART2 global interrupt使能中断优先级默认即可点击 OK。开启串口2中断同理可以开启串口1作为测试接口打印一些结果步骤 4生成工程代码点击GENERATE CODE生成 MDK/STM32CubeIDE 工程打开工程准备添加 GPS 驱动代码。三核心代码gps.h gps.c 完整文件1. GPS 头文件gps.h#ifndef _GPS_H#define _GPS_H#include main.h// 缓存与数据长度宏定义#define GPS_Buffer_Length 80#define UTCTime_Length 11#define latitude_Length 11#define N_S_Length 2#define longitude_Length 12#define E_W_Length 2#define GPSRX_LEN_MAX 255// GPS数据存储结构体typedef struct SaveData{char GPS_Buffer[GPS_Buffer_Length];char isGetData; // 是否获取到完整GPS数据char isParseData; // 是否解析完成char UTCTime[UTCTime_Length]; // UTC时间char latitude[latitude_Length];// 纬度char N_S[N_S_Length]; // 南北纬标识 N/Schar longitude[longitude_Length];// 经度char E_W[E_W_Length]; // 东西经标识 E/Wchar isUsefull; // 定位信息是否有效char UTCDate[15]; // GPS日期DDMMYY} _SaveData;// 函数声明void BSP_GPS_IRQHandler(uint8_t dat);void parseGpsBuffer(void);void printGpsBuffer(void);float gps_str_to_float(char *dm_str, uint8_t is_longitude);void str_time_to_arr(char *utc_str, uint8_t *time);void gps_date_split(char *date_str, uint8_t *day);uint8_t Get_Week(int year, int month, int day);#endif2. GPS 驱动文件gps.c#include gps.h#include stdlib.h#include string.h#include stdio.h// GPS接收全局变量unsigned char GPSRX_BUFF[GPSRX_LEN_MAX];unsigned char GPSRX_LEN 0;_SaveData Save_Data;#define GPRMC_FRAME_MAX_LEN 80/******************************************************************* 函 数 名 称BSP_GPS_IRQHandler* 函 数 说 明GPS串口中断接收函数******************************************************************/void BSP_GPS_IRQHandler(uint8_t dat){// 边界检查防止数组越界if(GPSRX_LEN (GPSRX_LEN_MAX - 1)){GPSRX_LEN 0;memset((void*)GPSRX_BUFF, 0, GPSRX_LEN_MAX);}// 帧头$重置接收缓存if(dat $){GPSRX_LEN 0;memset((void*)GPSRX_BUFF, 0, GPSRX_LEN_MAX);}GPSRX_BUFF[GPSRX_LEN] dat;// 识别$GPRMC帧接收完成if(GPSRX_BUFF[0] $ strncmp((char*)GPSRX_BUFF[1], GPRMC, 4) 0){if(dat \n GPSRX_LEN GPRMC_FRAME_MAX_LEN){memcpy(Save_Data.GPS_Buffer, (char*)GPSRX_BUFF, GPSRX_LEN);Save_Data.GPS_Buffer[GPSRX_LEN] \0;Save_Data.isGetData 1;// 重置缓存GPSRX_LEN 0;memset((void*)GPSRX_BUFF, 0, GPSRX_LEN_MAX);}}}/******************************************************************* 函 数 名 称parseGpsBuffer* 函 数 说 明解析GPRMC数据帧******************************************************************/void parseGpsBuffer(void){char *subString;char *subStringNext;char i 0;if (Save_Data.isGetData){Save_Data.isGetData 0;for (i 0 ; i 9 ; i){if (i 0){if ((subString strstr(Save_Data.GPS_Buffer, ,)) NULL)printf(GPS_1\r\n);}else{subString;if ((subStringNext strstr(subString, ,)) ! NULL){char usefullBuffer[2];switch(i){case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break;case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break;case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break;case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break;case 9:memcpy(Save_Data.UTCDate, subString, subStringNext - subString);break;default:break;}subString subStringNext;Save_Data.isParseData 1;if(usefullBuffer[0] A)Save_Data.isUsefull 1;else if(usefullBuffer[0] V)Save_Data.isUsefull 0;}else{printf(GPS_2\r\n);}}}}}/******************************************************************* 函 数 名 称printGpsBuffer* 函 数 说 明串口打印GPS解析数据******************************************************************/void printGpsBuffer(void){if (Save_Data.isParseData){Save_Data.isParseData 0;printf(UTC时间: %s\r\n,Save_Data.UTCTime);if(Save_Data.isUsefull){Save_Data.isUsefull 0;printf(纬度: %s %s\r\n,Save_Data.latitude,Save_Data.N_S);printf(经度: %s %s\r\n,Save_Data.longitude,Save_Data.E_W);}else{printf(GPS 定位无效!\r\n);}}}/******************************************************************* 函 数 名 称gps_str_to_float* 函 数 说 明度分格式转十进制经纬度******************************************************************/float gps_str_to_float(char *dm_str, uint8_t is_longitude){if(dm_str NULL || strlen(dm_str) 0){return 0.0f;}float degree 0.0f;float minute 0.0f;char degree_str[4] {0};char minute_str[15] {0};uint16_t dm_len strlen(dm_str);if(is_longitude){if(dm_len 3) return 0.0f;memcpy(degree_str, dm_str, 3);strncpy(minute_str, dm_str 3, dm_len - 3);}else{if(dm_len 2) return 0.0f;memcpy(degree_str, dm_str, 2);strncpy(minute_str, dm_str 2, dm_len - 2);}degree atof(degree_str);minute atof(minute_str);return (degree minute / 60.0f);}/******************************************************************* 函 数 名 称str_time_to_arr* 函 数 说 明UTC时间转北京时间(UTC8)******************************************************************/void str_time_to_arr(char *utc_str, uint8_t *time){uint8_t utc_hour, utc_min;if(utc_str NULL || time NULL) return;utc_hour (utc_str[0] - 0) * 10 (utc_str[1] - 0);utc_min (utc_str[2] - 0) * 10 (utc_str[3] - 0);time[0] utc_hour 8;if(time[0] 24) time[0] - 24;time[1] utc_min;}/******************************************************************* 函 数 名 称gps_date_split* 函 数 说 明拆分GPS日期******************************************************************/void gps_date_split(char *date_str, uint8_t *day){if(date_str NULL || day NULL) return;day[0] (date_str[0]-0)*10 (date_str[1]-0);day[1] (date_str[2]-0)*10 (date_str[3]-0);day[2] (date_str[4]-0)*10 (date_str[5]-0);}/******************************************************************* 函 数 名 称Get_Week* 函 数 说 明计算星期几******************************************************************/uint8_t Get_Week(int year, int month, int day){if(month 1 || month 2){month 12;year--;}int week (day 2*month 3*(month1)/5 year year/4 - year/100 year/400) % 7;return (uint8_t)week;}四使用实例main.c 中调用 GPS 驱动1. 第一步添加串口中断回调在工程中找到stm32xx_it.c文件添加以下代码USART2 中断处理#include gps.h// 定义GPS串口接收变量uint8_t rx2;// 串口接收完成回调函数void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if (huart-Instance USART2){// 把接收到的数据传给GPS处理函数BSP_GPS_IRQHandler(rx2);// 重新开启中断接收HAL_UART_Receive_IT(huart2, rx2, 1);}}2. 第二步main.c 完整使用代码#include main.h#include usart.h#include gpio.h#include gps.h#include stdio.h// 全局变量uint8_t beijing_time[2]; // 北京时间[小时,分钟]uint8_t gps_date[3]; // 日期[日,月,年]uint8_t week; // 星期char *week_table[] {周一,周二,周三,周四,周五,周六,周日};// 重定向printfint fputc(int ch ,FILE *f){HAL_UART_Transmit(huart1,(uint8_t *)ch,1,1000);return ch;}int main(void){// 1. 系统初始化HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init(); // 调试串口MX_USART2_UART_Init(); // GPS串口// 2. 开启GPS串口中断接收HAL_UART_Receive_IT(huart2, rx2, 1);while (1){// 3. 解析GPS数据parseGpsBuffer();// 4. 打印GPS原始数据printGpsBuffer();// 5. 数据格式转换if(Save_Data.isParseData Save_Data.isUsefull){// 转换北京时间str_time_to_arr(Save_Data.UTCTime, beijing_time);// 拆分日期gps_date_split(Save_Data.UTCDate, gps_date);// 计算星期week Get_Week(2000 gps_date[2], gps_date[1], gps_date[0]);// 转换十进制经纬度float lat gps_str_to_float(Save_Data.latitude, 0);float lon gps_str_to_float(Save_Data.longitude, 1);// 打印转换后数据printf(\r\n);printf(北京时间: %02d:%02d\r\n, beijing_time[0], beijing_time[1]);printf(日期: 20%02d-%02d-%02d\r\n, gps_date[2], gps_date[1], gps_date[0]);printf(星期: %s\r\n, week_table[week]);printf(十进制纬度: %.5f\r\n, lat);printf(十进制经度: %.5f\r\n, lon);printf(\r\n\r\n);}HAL_Delay(1000);}}测试帧6,03,40,105,27,14,86,293,36,19,36,290,37*7B$GPGSV,2,2,07,23,,,10,30,24,208,26,50,37,132,31*76$GPGLL,3438.65354,N,11257.61544,E,072530.00,A,A*65$GPRMC,072531.00,A,3438.65335,N,11257.61546,E,0.019,,130226,,,A*74$GPVTG,,T,,M,0.019,N,0.036,K,A*2E$GPGGA,072531.00,3438.65335,N,11257.61546,E,1,05,1.40,276.4,M,-17.0,M,,*78$GPGSA,A,3,01,30,19,03,14,,,,,,,,3.05,1.40,2.71*09$GPGSV,2,1,07,01,44,044,36,03,40,105,28,14,86,293,37,19,36,290,38*7A$GPGSV,2,2,07,23,,,12,30,24,208,26,50,37,132,32*77也可参考下面文章手把手教你一步步使用基于HAL库的STM32的GPS模块解析(NEO-6M-GPS)_stm32 hal库的 给gps 编程-CSDN博客

相关新闻

AI Agent 面试题 649:RAG系统中的文档更新检测和索引刷新

AI Agent 面试题 649:RAG系统中的文档更新检测和索引刷新

🔥 AI Agent 面试题 649:RAG系统中的文档更新检测和索引刷新摘要:本文深入解析了「RAG系统中的文档更新检测和索引刷新」这一 AI Agent 领域的核心面试题。文章从 文档分块策略 的基本概念出发,系统性地剖析了 更新检测、索引刷新…

2026/7/14 7:07:41 阅读更多 →
计算机网络基础7788

计算机网络基础7788

2026/7/14 7:07:41 阅读更多 →
TB67H480FNG与PIC18LF4680在电机控制中的黄金组合

TB67H480FNG与PIC18LF4680在电机控制中的黄金组合

1. 为什么选择TB67H480FNG与PIC18LF4680这对黄金组合在电机控制和嵌入式系统开发领域,硬件选型往往直接决定项目的成败。TB67H480FNG(东芝步进电机驱动IC)与PIC18LF4680(Microchip 8位MCU)的组合,是我在多个…

2026/7/14 7:03:40 阅读更多 →

最新新闻

从零开始构建企业级网络安全监控:Clear-NDR-ISO实战指南 [特殊字符]

从零开始构建企业级网络安全监控:Clear-NDR-ISO实战指南 [特殊字符]

从零开始构建企业级网络安全监控:Clear-NDR-ISO实战指南 🚀 【免费下载链接】Clear-NDR-ISO A Suricata based NDR distribution 项目地址: https://gitcode.com/GitHub_Trending/se/Clear-NDR-ISO 你是否曾为网络攻击的隐蔽性而担忧?…

2026/7/14 10:14:57 阅读更多 →
Ubuntu Samba共享服务:从零搭建到安全加固的完整实践

Ubuntu Samba共享服务:从零搭建到安全加固的完整实践

1. 环境准备与Samba基础安装在开始搭建Samba共享服务之前,我们需要确保系统环境准备就绪。我建议使用Ubuntu 20.04 LTS或更高版本,这些长期支持版本经过充分测试,稳定性更有保障。实测下来,新版本对Samba的性能优化和安全补丁支持…

2026/7/14 10:10:55 阅读更多 →
Dify开源AI开发平台:从零构建企业级工作流应用实战指南

Dify开源AI开发平台:从零构建企业级工作流应用实战指南

在AI应用开发领域,很多团队都面临着从原型到生产环境的转化难题。传统开发方式需要处理复杂的模型集成、工作流设计和部署配置,这让很多有创意的想法难以快速落地。Dify作为一款开源的可视化AI应用开发平台,正是为了解决这些问题而生。本文将…

2026/7/14 10:08:55 阅读更多 →
SAP PM 核心数据表全览:从设备主数据到维护订单的架构解析

SAP PM 核心数据表全览:从设备主数据到维护订单的架构解析

1. SAP PM模块数据架构全景图第一次接触SAP PM模块的数据表时,我完全被各种缩写搞晕了。直到后来在项目现场看到一张设备维修工单从创建到关闭的全流程,才真正理解这些数据表就像工厂车间的传送带,每个环节都有专门的"工位"负责特定…

2026/7/14 10:06:54 阅读更多 →
现代C++手写损失函数:数值稳定性与边缘部署实战

现代C++手写损失函数:数值稳定性与边缘部署实战

1. 项目概述:为什么在现代C里手写损失函数,比调用PyTorch一行代码更值得花三周时间“Deep Learning from Scratch in Modern C: Cost Functions”——这个标题乍看像教科书章节,实则是我去年在为一家工业视觉检测系统做底层推理引擎重构时&am…

2026/7/14 10:06:54 阅读更多 →
FLUX.2-klein-base-4B-bf16高级技巧:负向提示与分类器引导优化终极指南

FLUX.2-klein-base-4B-bf16高级技巧:负向提示与分类器引导优化终极指南

FLUX.2-klein-base-4B-bf16高级技巧:负向提示与分类器引导优化终极指南 【免费下载链接】FLUX.2-klein-base-4B-bf16 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/FLUX.2-klein-base-4B-bf16 FLUX.2-klein-base-4B-bf16是一款基于Apple Sil…

2026/7/14 10:02:49 阅读更多 →

日新闻

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

更多请点击: https://kaifayun.com 第一章:AI Agent数据越界行为的合规性挑战与溯源必要性 AI Agent在自主执行任务过程中,可能因提示注入、上下文污染或权限配置缺陷,无意或有意访问、缓存、传输受保护数据(如PII、G…

2026/7/14 0:01:13 阅读更多 →
Perplexity vs ChatGPT vs Claude:实测127组复杂查询任务,谁才是真正可靠的“事实型AI助手”?

Perplexity vs ChatGPT vs Claude:实测127组复杂查询任务,谁才是真正可靠的“事实型AI助手”?

更多请点击: https://codechina.net 第一章:Perplexity 怎么用 Perplexity 是衡量语言模型预测能力的核心指标,数值越低表示模型对文本序列的不确定性越小、预测越精准。它本质上是交叉熵损失的指数形式,计算公式为:…

2026/7/14 0:01:13 阅读更多 →
全球首发!五一视界定制物理AI卫星ECS-1剑指万亿赛道

全球首发!五一视界定制物理AI卫星ECS-1剑指万亿赛道

五一视界发布公告,近日,公司与环天智慧科技股份有限公司(“环天智慧”)正式达成空天领域战略合作。环天智慧是国内领先、聚焦天基对地观测遥感卫星总体研制与在轨运营的商业航天企业,同时也是西南地区规模最大、具备全自主可控遥感卫星星座建…

2026/7/14 0:03:13 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/13 4:38:36 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/13 4:38:38 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/14 7:15:24 阅读更多 →

月新闻