用32单片机驱动导航模块


小人物
原创
发布时间: 2025-10-15 16:24:16 | 阅读数 0收藏数 0评论数 0
封面
偶然瞥到一块GPS导航模块,看着正方形的陶瓷天线,感觉挺好玩,就想用单片机驱动一下,玩玩,于是就拿手边的STM32F103C8T6来驱动,还配了一块0.96寸OLED屏,用来显示数据。

准备工作:

材料:

  1. STM32F103C8T6单片机
  2. 0.96 OLED屏
  3. GY-GPS6MV2 导航模块
  4. 些许杜邦线


1

模块驱动方式

在网上看了很多帖子,了解了一下,一般GPS模块都是串口输出数据,默认波特率9600,可以通过软件设置,所以只要用单片机的串口接收数据就可以了。

2

GPS的数据解析原理

1.GPS原理

GPS通过接收多个卫星的信号用三角测量法来确定设备的位置

2.NMEA 协议

美国国家海洋电子协会为海用电子设备制定了标准格式NMEA-0183。它包含了定位时间,纬度,经度,高度,定位所用的卫星数,DOP值,差分状态和校正时段等很多信息。

3.数据解析

GPS信息类型:

  1. GPGSV:可见卫星信息
  2. GPGLL:地理定位信息
  3. GPRMC:推荐最小定位信息
  4. GPVTG:地面速度信息
  5. GPGGA:GPS定位信息
  6. GPGSA:当前卫星信息

我们就用GPRMC最小定位信息就可以了。

模块的数据格式是: $ 信息类型,x,x,x,x,x,x,x,x,x,x,x,

每行开头的字符都是'$',接着是信息类型,后面是数据,以逗号分隔开。

如:$GPRMC,080655.00,A,4546.40891,N,12639.65641,E,1.045,328.42,170809,,,A*60

数据详解:

$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh

<1> UTC 时间,hhmmss(时分秒)格式

<2> 定位状态,A=有效定位,V=无效定位

<3>纬度ddmm.mmmm(度分)格式(前面的0也将被传输)

<4> 纬度半球N(北半球)或S(南半球)

<5>经度dddmm.mmmm(度分)格式(前面的0也将被传输)

<6> 经度半球E(东经)或W(西经)

<7>地面速率(000.0~999.9节,前面的0也将被传输)

<8>地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输)

<9> UTC 日期,ddmmyy(日月年)格式

<10>磁偏角(000.0~180.0度,前面的0也将被传输)

<11> 磁偏角方向,E(东)或W(西)

<12>模式指示(仅NMEA01833.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)


3

连接硬件

我用单片机的硬件串口3(PB10, PB11)来接GPS模块的,然后用OLED软件模拟IIC的接PB8,PB9。

4

软件编写

软件主要是初始化串口,和驱动OLED.

GPS.H

#ifndef __GPS_H
#define __GPS_H

#include "sys.h"
// USART3定义


#define GPS_USART USART3
#define USART3_REC_LEN 200 // 定义最大接收字节数
#define GPS_Buffer_Length 100








typedef struct SaveDataGPS
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData; // 是否获取到GPS数据
char isParseData[5]; // 是否解析完成
char UTCTime[20]; // UTC时间
char latitude[20]; // 纬度
char N_S[5]; // 南纬 or 北纬
char longitude[20]; // 经度
char E_W[5]; // 东经 or 西经
char isUsefull[5]; // 定位信息是否有效
} SaveData;


extern SaveData GPS_Frame;
extern u8 GPS_Data_len;



// GPS初始化
void GPS_Init(void);
// 解析GPS数据
void parseGpsData(void);






#endif

GPS.C

#include "gps.h"
#include "usart.h"
#include <string.h>







u16 USART3_RX_STA=0; //接收状态标记
u8 USART3_RX_BUF[USART3_REC_LEN]; //接收缓冲,最大200个字节.
SaveData GPS_Frame;


u8 GPS_Data_len;





// 私有函数声明
static void GPIO_Configuration(void);
static void USART3_Configuration(void);




void GPS_Init(void)
{
GPIO_Configuration();
USART3_Configuration();
}
//**************************************************************************



// 初始化串口3的引脚 TX:PB10 RX:PB11
static void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
// 配置USART3引脚: PB10(TX), PB11(RX)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//**************************************************************************



// 初始化串口3
static void USART3_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能USART3时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
// USART3配置
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(GPS_USART, &USART_InitStructure);

// 使能USART3接收中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 新增:使能接收中断


USART_Cmd(GPS_USART, ENABLE);




// 配置USART3中断
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//**************************************************************************




//串口3接收中断函数
void USART3_IRQHandler(void) //串口3中断服务程序
{
u8 Res;

if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断标志(接收到的数据必须是0x0d 0x0a结尾)
{
Res = USART_ReceiveData(USART3); //读取接收到的数据

if(Res == '$') // 判断是否GPS数据的标志字符
{
GPS_Data_len = 0;
}
USART3_RX_BUF[GPS_Data_len++] = Res;

// 判断这条GPS数据是否自己需要的$GPRMC(最小定位信息)数据类型
if(USART3_RX_BUF[0]=='$' && USART3_RX_BUF[4]=='M' && USART3_RX_BUF[5]=='C' )
{
if(Res == '\n')
{
memset(GPS_Frame.GPS_Buffer, 0, GPS_Buffer_Length); // 清空GPS_Frame.GPS_Buffer
memcpy(GPS_Frame.GPS_Buffer, USART3_RX_BUF, GPS_Data_len); // 复制数据到GPS_Frame.GPS_Buffer
GPS_Frame.isGetData = 1; // 是否获取到GPS数据
GPS_Data_len = 0; // 长度清零准备下次接收数据
memset(USART3_RX_BUF, 0, USART3_REC_LEN); // USART3_RX_BUF清空准备下次接收数据
USART3_RX_STA=1; // 接收到有效数据标志,再主循环中调用
}
}
if(GPS_Data_len >= USART3_REC_LEN) //防止接收数据越界
GPS_Data_len = USART3_REC_LEN;
}
}
//**************************************************************************



// 解析GPS数据
void parseGpsData(void)
{
char *subString;
char *subStringNext;
char i, j;

if(GPS_Frame.isGetData)
{
for(i=0; i<6; i++)
{
if(i==0)
{
subString = strstr(GPS_Frame.GPS_Buffer, ",");
}
else
{
subString++;
subStringNext = strstr(subString, ",");
j = subStringNext - subString;
switch (i)
{
case 1: // 获取UTC时间
memcpy(GPS_Frame.UTCTime, subString, j);
// GPS_Frame.isUsefull[j] = '\0';
break;
case 2: // 定位信息是否有效
memcpy(GPS_Frame.isUsefull, subString, j);
GPS_Frame.isUsefull[j] = '\0';
break;
case 3: // 纬度
memcpy(GPS_Frame.latitude, subString, j);
GPS_Frame.latitude[j] = '\0';
break;
case 4: // 纬度半球
memcpy(GPS_Frame.N_S, subString, j);
GPS_Frame.N_S[j] = '\0';
break;
case 5: // 经度
memcpy(GPS_Frame.longitude, subString, j);
GPS_Frame.longitude[j] = '\0';
break;
case 6: // 经度半球
memcpy(GPS_Frame.E_W, subString, j);
GPS_Frame.E_W[j] = '\0';
break;
default:
printf("解析出错!");
break;
}
}
}
GPS_Frame.isGetData = 0;
}
}

MAIN.C

#include "sys.h"
#include "oled.h"
#include "delay.h"
#include "usart.h"
#include "gps.h"


extern u16 USART3_RX_STA; //接收状态标记
extern char USART3_RX_BUF[USART3_REC_LEN]; //接收缓冲,最大200个字节.






int main(void)
{
u8 len, str[20] = "Hello";

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组
uart_init(9600); // 初始化串口1,波特率115200
delay_init(); // 延时函数初始化
OLED_Init(); // OLED 初始化
OLED_clear(); // 清屏
DS3231_Init(); // 时钟模块初始化
GPS_Init(); // GPS 初始化

str_8x16(32, 0, "GPS Info");




while (1)
{
parseGpsData();
if(USART3_RX_STA)
{

str[0] = GPS_Frame.UTCTime[0];
str[1] = GPS_Frame.UTCTime[1];
str[2] = ':';
str[3] = GPS_Frame.UTCTime[2];
str[4] = GPS_Frame.UTCTime[3];
str[5] = ':';
str[6] = GPS_Frame.UTCTime[4];
str[7] = GPS_Frame.UTCTime[5];
str[8] = '\0';
str_8x16(0, 2, "TIME: ");
str_8x16(48, 2, str);

str_8x16(0, 4, "Wdu: ");
str_8x16(48, 4, GPS_Frame.latitude);
str_8x16(0, 6, "Gdu: ");
str_8x16(48, 6, GPS_Frame.longitude);

USART3_RX_STA = 0;
}
}
}


















5

户外测试

拿设备接移动电源到室外测试,GPS冷启动需要等待好一会,我等了大约7 8分钟的样子。

阅读记录0
点赞0
收藏0
禁止 本文未经作者允许授权,禁止转载
猜你喜欢
评论/提问(已发布 0 条)
评论 评论
收藏 收藏
分享 分享
pdf下载 下载
pdf下载 举报