一、模块介绍
全球四大卫星定位系统
GPS 系统(美国)
BDS 系统(中国北斗)
GLONASS 系统(俄罗斯)
伽利略卫星导航系统(欧盟)
ATGM336H-5N 系列模块是 9.7X10.1 尺寸的高性能 BDS/GNSS 全星座定位导航模块系列的总称。该系列模块产品都是基于中科微第四代低功耗 GNSS SOC 单芯片—AT6558,支持多种卫星导航系统,包括中国的 BDS(北斗卫星导航系统),美国的 GPS,俄罗斯GLONASS,欧盟的 GALILEO,日本的 QZSS以及卫星增强系统 SBAS(WAAS,EGNOS,GAGAN,MSAS)。AT6558 是一款真正意义的六合一多模卫星导航定位芯片,包含 32 个跟踪通道,可以同时接收六个卫星导航系统的 GNSS 信号,并且实现联合定位、导航与授时。
二、使用步骤
首次使用用usb转ttl连接电脑串口助手,验证模块能否正常工作,是否定位成功。后续用stm32串口代替电脑,实现接收数据。
1.数据解析
测试最好是带电脑到户外空旷地进行,若是把天线放在阳台外面的话,有一定几率定位失败。空旷地首次定位一般是一分钟以内。
用串口来看下数据,波特率默认是 9600
板载 LED 保持一定的频率闪烁证明定位成功了
GN、GP、BD 分别代表 双模模式、GPS 模式、北斗模式
数据解析
例 $GNRMC,084852.000,A,2236.9453,N,11408.4790,E,0.53,292.44,141216,A*75
2.数据转换
数据格式:
纬度:ddmm.mmmm 经度:dddmm.mmmm
度分格式 换算成百度 谷歌地图的格式
北纬 2236.9453 22+(36.9453/60)= 22.615755
东经 11408.4790 114+(08.4790/60)=114.141317
转换成 度分秒的格式
北纬 2236.9453 = 22 度 36 分 0.9453x60 秒 = 22 度 36 分 56.718 秒
东经 11408.4790 = 114 度 8 分 0.4790x60 秒 = 114 度 8 分 28.74 秒
三、代码示例
思路:gps作为独立工作的模块,stm32端只需编写串口接收函数,接收gps模块发来的数据。由于只关注经纬度,故只需解析经纬度即可。
模块资料里只给了F1的例程,这里放改完的F4的代码吧。
gps.c
#include "sys.h"
#include "gps.h"
char rxdatabufer;
u16 point1 = 0;
_SaveData Save_Data;
//
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用
#endif
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
//串口1对应引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
//USART1端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
//USART1 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
//USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
CLR_Buf();//清空缓存
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if(Res == '$')
{
point1 = 0;
}
USART_RX_BUF[point1++] = Res;
if(USART_RX_BUF[0] == '$' && USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C') //确定是否收到"GPRMC/GNRMC"这一帧数据
{
if(Res == '\n')
{
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memcpy(Save_Data.GPS_Buffer, USART_RX_BUF, point1); //保存数据
Save_Data.isGetData = true;
point1 = 0;
memset(USART_RX_BUF, 0, USART_REC_LEN); //清空
}
}
if(point1 >= USART_REC_LEN)
{
point1 = USART_REC_LEN;
}
}
}
u8 Hand(char *a) // 串口命令识别函数
{
if(strstr(USART_RX_BUF,a)!=NULL)
return 1;
else
return 0;
}
void CLR_Buf(void) // 串口缓存清理
{
memset(USART_RX_BUF, 0, USART_REC_LEN); //清空
point1 = 0;
}
void clrStruct()
{
Save_Data.isGetData = false;
Save_Data.isParseData = false;
Save_Data.isUsefull = false;
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memset(Save_Data.UTCTime, 0, UTCTime_Length);
memset(Save_Data.latitude, 0, latitude_Length);
memset(Save_Data.N_S, 0, N_S_Length);
memset(Save_Data.longitude, 0, longitude_Length);
memset(Save_Data.E_W, 0, E_W_Length);
}
void errorLog(int num)
{
while (1)
{
printf("ERROR%d\r\n",num);
}
}
void parseGpsBuffer()
{
char *subString;
char *subStringNext;
char i = 0;
if (Save_Data.isGetData)
{
Save_Data.isGetData = false;
//printf("**************\r\n");
// printf(Save_Data.GPS_Buffer);
for (i = 0 ; i <= 6 ; i++)
{
if (i == 0)
{
if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
errorLog(1); //解析错误
}
else
{
subString++;
if ((subStringNext = strstr(subString, ",")) != NULL)
{
char usefullBuffer[2];
switch(i)
{
case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //获取UTC时间
case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //获取UTC时间
case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break; //获取纬度信息
case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //获取N/S
case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //获取经度信息
case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //获取E/W
default:break;
}
subString = subStringNext;
Save_Data.isParseData = true;
if(usefullBuffer[0] == 'A')
Save_Data.isUsefull = true;
else if(usefullBuffer[0] == 'V')
Save_Data.isUsefull = false;
}
else
{
errorLog(2); //解析错误
}
}
}
}
}
void printGpsBuffer()
{
if (Save_Data.isParseData)
{
Save_Data.isParseData = false;
printf("Save_Data.UTCTime = ");
printf(Save_Data.UTCTime);
printf("\r\n");
if(Save_Data.isUsefull)
{
Save_Data.isUsefull = false;
printf("Save_Data.latitude = ");
printf(Save_Data.latitude);
printf("\r\n");
printf("Save_Data.N_S = ");
printf(Save_Data.N_S);
printf("\r\n");
printf("Save_Data.longitude = ");
printf(Save_Data.longitude);
printf("\r\n");
printf("Save_Data.E_W = ");
printf(Save_Data.E_W);
printf("\r\n");
}
else
{
printf("GPS DATA is not usefull!\r\n");
}
}
}
#endif
gps.h
#ifndef __gps_H
#define __gps_H
#include "stdio.h"
#include "stm32f4xx_conf.h"
#include "sys.h"
#include "string.h"
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
#define false 0
#define true 1
//定义数组长度
#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
//extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
//extern u16 USART_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
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/S
char longitude[longitude_Length]; //经度
char E_W[E_W_Length]; //E/W
char isUsefull; //定位信息是否有效
} _SaveData;
void errorLog(int num);
void parseGpsBuffer(void);
void printGpsBuffer(void);
void uart_init(u32 bound);
extern char rxdatabufer;
extern u16 point1;
extern _SaveData Save_Data;
void CLR_Buf(void);
u8 Hand(char *a);
void clrStruct(void);
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "gps.h"
#include "led.h"
#include "key.h"
//-----------------------------------------------------------------------//
// 模块 stm32
//GPS TX-->PA10 pa9 USART1
//------------------------------------------------------------------------//
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(9600); //GPS使用的串口初始化
LED_Init();
KEY_Init();
clrStruct();
while(1)
{
if(KEY0==0) //按下按键获取一次 直接操作库函数方式读取IO
{ delay_ms(10);//消抖
if(KEY0==0)
{
LED1=0;
parseGpsBuffer();//获取位置信息
printGpsBuffer();//发送位置信息
delay_ms(2000);
LED1=1; //可以借此检验是否发送成功
}
}
}
}
如何操作想用的变量
思路:由于接收数据被存放到结构体中,访问结构体变量中的内容即可。
结构体成员的访问需要借助结构体成员运算符——点(.)
c语言中:typedef给结构体起别名
这种方法在实际操作中用的非常多,在嵌入式开发中几乎全都是用typedef给结构体起别名方法。比如你常见的STM32单片机中的程序,就是这样写的。
typedef struct 结构体名
{
成员列表;
}变量名列表;
例 给结构体模板struct student重新命名为student
// 给结构体模板struct student重新命名为student
typedef struct student
{
char *name; // 学生名字
int num; // 学生学号
int age; // 学生年龄
}student;
使用student创建三个结构体变量student1,student2
student student1 , student2;
我们代码中定义了一个结构体模板struct SaveData 重新命名为_SaveData。
因此只需用_SaveData创建结构体变量SaveData。Save_Data.xxx即可操作变量。
如:显示在屏幕上 、给其它变量赋该值
调用oled的showstring函数显示Save_Data.latitude
w=Save_Data.latitude; //纬度文章来源:https://www.toymoban.com/news/detail-822521.html
总结
另外附上官方给的F1的工程文件模块参考例程F1+使用手册
本文介绍了GPS模块的使用。
大家有问题可以留言,看到了我会及时回复!文章来源地址https://www.toymoban.com/news/detail-822521.html
到了这里,关于STM32读取GPS数据-ATGM336H的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!