2.61 ATGM336H—GPS 北斗双模模块(来自 TaurusHard 的贡献)
2.61.1 模块来源
采购链接:https://item.taobao.com/item.htm?spm=a1z09.2.0.0.41c92e8d3GWc6q&id=595353912203&_u=k1n9eb4ne3c3 资料下载:https://pan.baidu.com/s/1ltiJxImpN5HtBg6U86jSjg 提取码: fywk
**实物展示图**2.61.2 规格参数
工作电压:3.3V/5V工作电流:连续运行 <25mA通信方式:UART默认波特率:9600定位精度:2.5 米(CEP50)冷启动捕获灵敏度:-148dBm跟踪灵敏度:-162dBm首次定位时间:32 秒工作温度:-40℃~85℃引脚数量:5(VCC、GND、TX、RX、PPS)模块尺寸:15.7mm x 13.1mm
2.61.3 模块原理
2.61.3.1 模块简介
ATGM336H-5N 系列模块是 9.7X10.1 尺寸的高性能 BDS/GNSS 全星座定位导航模块系列的总称。该系列模块产品都是基于中科微第四代低功耗 GNSSSOC 单芯片——AT6558,支持多种卫星导航系统,包括中国的 BDS(北斗卫星导航系统),美国的 GPS,俄罗斯的 GLONASS,欧盟的 GALILEO,日本的 QZSS 以及卫星增强系统 SBAS(WAAS,EGNOS,GAGAN,MSAS)。AT6558 是一款真正意义的六合一多模卫星导航定位芯片,包含 32 个跟踪通道,可以同时接收六个卫星导航系统的 GNSS 信号,并且实现联合定位、导航与授时。ATGM336H-5N 本系列模块具有高灵敏度、低功耗、低成本等优势,适用于车载导航、手持定位、可穿戴设备,可以直接替换 Ublox MAX 系列模块。其模块框图如下。
2.61.3.2 输出协议
ATGM336H-5N 系列模块通过 UART 作为主要输出通道,按照 NMEA0183 的协议格式输出,具体信息请参照《CASIC 多模卫星导航接收机协议规范》。 其主要包括以下帧格式:
2.61.3.3 GPS 信息
2.61.3.4 地理定位信息
2.61.3.5 当前卫星信息
2.61.3.6 可见卫星信息
2.61.3.7 最简定位信息
2.61.3.8 地面速度信息
2.61.3.9 天线状态输出
2.61.3.10 经纬度换算
协议中的经纬度格式为 ddmm.mmmm/dddmm.mmmm,若换算成常用的经纬度格式,可以通过百度搜索经纬度转换工具转换即可。其计算公式如下:
2.61.4 移植工程
2.61.4.1 引脚选择
模块 | 立创·梁山派 | 接线图 |
---|
2.61.4.2 移植步骤
本例程参考资料中的代码,在 uart.h 和 uart.c 中增加串口数据解析代码,以 3.2.5 小节的最简定位信息为例,将接收到的有效 GPS 报文解析出来并打印在终端显示。
** uart.h**
该部分代码增加 UART1 的相关定义及接收数据结构体定义,具体代码如下:
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: TaurusHard
* 修改日期: 2023年09月05日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#ifndef _UART_H
#define _UART_H
#include "gd32f4xx.h"
#include "systick.h"
// UART0
#define BSP_USART_TX_RCU RCU_GPIOA // 串口TX的端口时钟
#define BSP_USART_RX_RCU RCU_GPIOA // 串口RX的端口时钟
#define BSP_USART_RCU RCU_USART0 // 串口0的时钟
#define BSP_USART_TX_PORT GPIOA // 串口TX的端口
#define BSP_USART_RX_PORT GPIOA // 串口RX的端口
#define BSP_USART_AF GPIO_AF_7 // 串口0的复用功能
#define BSP_USART_TX_PIN GPIO_PIN_9 // 串口TX的引脚
#define BSP_USART_RX_PIN GPIO_PIN_10 // 串口RX的引脚
#define BSP_USART USART0 // 串口0
#define BSP_USART_IRQ USART0_IRQn // 串口0中断
#define BSP_USART_IRQHandler USART0_IRQHandler // 串口0中断服务函数
// UART1
#define UART1_TX_RCU RCU_GPIOA // 串口1TX的端口时钟
#define UART1_RX_RCU RCU_GPIOA // 串口1RX的端口时钟
#define UART1_RCU RCU_USART1 // 串口1的时钟
#define UART1_TX_PORT GPIOA // 串口1TX的端口
#define UART1_RX_PORT GPIOA // 串口1RX的端口
#define UART1_TX_PIN GPIO_PIN_2 // 串口1TX的引脚
#define UART1_RX_PIN GPIO_PIN_3 // 串口1RX的引脚
#define UART1_AF GPIO_AF_7 // 串口1的复用功能
#define UART1 USART1 // 串口1
#define UART1_IRQ USART1_IRQn // 串口1中断
#define UART1_IRQHandler USART1_IRQHandler // 串口1中断服务函数
#define false 0
#define true 1
// 定义数组长度
#define USART_REC_LEN 200 // 定义最大接收字节数
#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
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 usart_gpio_config(uint32_t band_rate); // 配置串口
void uart1_init(uint32_t band_rate);
void uart_send_data(uint32_t usart_periph, uint8_t ucch); // 发送一个字符
void usart_send_string(uint32_t usart_periph, unsigned char *str, unsigned short len);
void clr_uart_recv_struct(void);
void parse_gps_buffer(void);
#endif /* UART_H */
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
uart.c
该部分代码增加 UART1 的相关初始化、接收中断对 GPS 有效数据的处理、对 GPS 数据进行解析和打印等函数,具体代码如下:
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: TaurusHard
* 修改日期: 2023年09月05日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#include "uart.h"
#include "stdio.h"
#include "string.h"
#include <stdarg.h>
uint16_t point1 = 0;
uint8_t USART_RX_BUF[USART_REC_LEN]; // 接收缓冲,最大USART_REC_LEN个字节.
_SaveData Save_Data;
/************************************************
函数名称 : usart_gpio_config
功 能 : 串口配置GPIO
参 数 : band_rate:波特率
返 回 值 : 无
作 者 : LC
*************************************************/
void usart_gpio_config(uint32_t band_rate)
{
/* 开启时钟 */
rcu_periph_clock_enable(BSP_USART_TX_RCU); // 开启串口时钟
rcu_periph_clock_enable(BSP_USART_RX_RCU); // 开启端口时钟
rcu_periph_clock_enable(BSP_USART_RCU); // 开启端口时钟
/* 配置GPIO复用功能 */
gpio_af_set(BSP_USART_TX_PORT, BSP_USART_AF, BSP_USART_TX_PIN);
gpio_af_set(BSP_USART_RX_PORT, BSP_USART_AF, BSP_USART_RX_PIN);
/* 配置GPIO的模式 */
/* 配置TX为复用模式 上拉模式 */
gpio_mode_set(BSP_USART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_USART_TX_PIN);
/* 配置RX为复用模式 上拉模式 */
gpio_mode_set(BSP_USART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_USART_RX_PIN);
/* 配置TX为推挽输出 50MHZ */
gpio_output_options_set(BSP_USART_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_TX_PIN);
/* 配置RX为推挽输出 50MHZ */
gpio_output_options_set(BSP_USART_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_RX_PIN);
/* 配置串口的参数 */
usart_deinit(BSP_USART); // 复位串口
usart_baudrate_set(BSP_USART, band_rate); // 设置波特率
usart_parity_config(BSP_USART, USART_PM_NONE); // 没有校验位
usart_word_length_set(BSP_USART, USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(BSP_USART, USART_STB_1BIT); // 1位停止位
/* 使能串口 */
usart_enable(BSP_USART); // 使能串口
usart_transmit_config(BSP_USART, USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receive_config(BSP_USART, USART_RECEIVE_ENABLE); // 使能串口接收
/* 中断配置 */
nvic_irq_enable(BSP_USART_IRQ, 2, 2); // 配置中断优先级
usart_interrupt_enable(BSP_USART, USART_INT_RBNE); // 读数据缓冲区非空中断
}
/************************************************
函数名称 : uart1_init
功 能 : UART1初始化
参 数 : band_rate:波特率
返 回 值 : 无
作 者 : TaurusHard
*************************************************/
void uart1_init(uint32_t band_rate)
{
/* 开启时钟 */
rcu_periph_clock_enable(UART1_RCU); // 开启串口时钟
rcu_periph_clock_enable(UART1_TX_RCU); // 开启端口时钟
rcu_periph_clock_enable(UART1_RX_RCU); // 开启端口时钟
/* 配置GPIO复用功能 */
gpio_af_set(UART1_TX_PORT, UART1_AF, UART1_TX_PIN);
gpio_af_set(UART1_RX_PORT, UART1_AF, UART1_RX_PIN);
/* 配置GPIO的模式 */
/* 配置TX为复用模式 上拉模式 */
gpio_mode_set(UART1_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UART1_TX_PIN);
/* 配置RX为复用模式 上拉模式 */
gpio_mode_set(UART1_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UART1_RX_PIN);
/* 配置TX为推挽输出 50MHZ */
gpio_output_options_set(UART1_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UART1_TX_PIN);
/* 配置RX为推挽输出 50MHZ */
gpio_output_options_set(UART1_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UART1_RX_PIN);
/* 配置串口的参数 */
usart_deinit(UART1); // 复位串口
usart_baudrate_set(UART1, band_rate); // 设置波特率
usart_parity_config(UART1, USART_PM_NONE); // 没有校验位
usart_word_length_set(UART1, USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(UART1, USART_STB_1BIT); // 1位停止位
/* 使能串口 */
usart_enable(UART1); // 使能串口
usart_transmit_config(UART1, USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receive_config(UART1, USART_RECEIVE_ENABLE); // 使能串口接收
/* 中断配置 */
nvic_irq_enable(UART1_IRQ, 2, 2); // 配置中断优先级
usart_interrupt_enable(UART1, USART_INT_RBNE); // 读数据缓冲区非空中断
}
/************************************************
函数名称 : uart_send_data
功 能 : 串口重发送一个字节
参 数 : usart_periph: USARTx(x=0,1,2,5)/UARTx(x=3,4,6,7)
参 数 : ucch:要发送的字节
返 回 值 :
作 者 : LC
*************************************************/
void uart_send_data(uint32_t usart_periph, uint8_t ucch)
{
usart_data_transmit(usart_periph, (uint8_t)ucch); // 发送数据
while(RESET == usart_flag_get(usart_periph, USART_FLAG_TBE))
; // 等待发送数据缓冲区标志置位
}
/************************************************
函数名称 : fputc
功 能 : 串口重定向函数
参 数 :
返 回 值 :
作 者 : LC
*************************************************/
int fputc(int ch, FILE *f)
{
uart_send_data(BSP_USART, ch);
// 等待发送数据缓冲区标志置位
return ch;
}
/************************************************
函数名称 : usart_send_string
功 能 : 串口发送字符串
参 数 : usart_periph: USARTx(x=0,1,2,5)/UARTx(x=3,4,6,7)
参 数 : str:要发送的字符串
参 数 : len:字符串长度
返 回 值 :
作 者 : TH
*************************************************/
void usart_send_string(uint32_t usart_periph, unsigned char *str, unsigned short len)
{
unsigned short count = 0;
for(; count < len; count++)
{
uart_send_data(usart_periph, *str++);
}
}
void clr_uart_recv_struct(void)
{
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);
}
static void errorLog(int num)
{
printf("ERROR%d\r\n", num);
}
void parse_gps_buffer(void)
{
char *subString;
char *subStringNext;
char i = 0;
if(Save_Data.isGetData)
{
Save_Data.isGetData = false;
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;
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; // 获取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); // 解析错误
}
}
}
}
else
{
}
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");
}
}
}
/************************************************
函数名称 : BSP_USART_IRQHandler
功 能 : 串口接收中断服务函数
参 数 : 无
返 回 值 : 无
作 者 : LC
*************************************************/
void BSP_USART_IRQHandler(void)
{
// uint8_t data = 0;
// if(usart_interrupt_flag_get(BSP_USART, USART_INT_FLAG_RBNE) == SET) // 接收缓冲区不为空
// {
// data = usart_data_receive(BSP_USART); // 把接收到的数据放到缓冲区中
// }
// else
// {
// }
}
/************************************************
函数名称 : UART1_IRQHandler
功 能 : 串口1接收中断服务函数
参 数 : 无
返 回 值 : 无
作 者 : TaurusHard
*************************************************/
void UART1_IRQHandler(void)
{
uint8_t res;
if(usart_interrupt_flag_get(UART1, USART_INT_FLAG_RBNE) == SET) // 接收缓冲区不为空
{
res = usart_data_receive(UART1); // 把接收到的数据放到缓冲区中
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;
}
}
else
{
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
2.61.5 移植验证
在 main.c 中增加 UART1 的初始化,并在 while(1)中增加 GPS 数据解析函数,测试 GPS 识别结果。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: TaurusHard
* 修改日期: 2023年09月05日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#include "gd32f4xx.h"
#include "stdio.h"
#include "systick.h"
#include "uart.h"
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
systick_config(); // 滴答定时器初始化 1us
clr_uart_recv_struct(); // 清空接收缓冲区
usart_gpio_config(115200U); // 串口初始化
uart1_init(9600U); // GPS串口初始化
while(1)
{
parse_gps_buffer(); // 解析GPS数据
delay_ms(100);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
将 DAP-Link 连接至电脑 USB 接口,打开串口调试助手,编译代码下载到梁山派开发板后,运行代码,观察串口调试助手打印信息,当解析到有效定位数据后穿串口会打印如下图信息,当打印该种信息时证明模块已搜星成功并成功定位。
注:该 GPS 模块需放置在室外空旷地带定位,初次上电时需要 30s~2 分钟时间定位(具体看所处位置卫星数量和搜星效率)。
移植成功代码见下文件。