GD32串口读取GPS模块数据并解析经纬度教程-附完整代码和资料文件

前言:

        最近入手了个GPS模块,手上只有GD32的开发板。网上有很多使用STM32库函数的GPS驱动程序,但是基于GD32库函数读取GPS驱动的教程居然一篇都没有。所以为了学习GD32库的同学,还是写一篇博客记录一下。

资料下载:

1、教程所用到的GPS模块资料的百度云链接:

https://pan.baidu.com/s/1scQYIS97CqzUzH5XQ3CI6A?pwd=5u0w

2、完整代码下载链接:

https://download.csdn.net/download/YANGJIERUN/87381512

使用的开发板:

 

        本教程使用的开发板为DRG GD-2 GD32F103C8T6最小系统板。使用的GPS集成中科微电子的模组,市面上买得到的GPS模块都可以用本程序读取定位数据。

GD32串口引脚定义如下:

 一般USART0用于下载程序和作为Debug打印数据使用,市面上大多数的开发板的串口都是默认占用USART0。所以我使用USART1读取GPS数据。

一、串口的初始化

        串口初始化网上也有很多教程,这里简单带过。USART0和USART1的初始化步骤一致,只是函数参数上USART0改为了USART1而已。这里直接放代码。

串口0初始化代码:

// 串口 0 初始化
void USART0_init(uint32_t bound)
{
	/* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);
    
	/* enable GPIO clock */
	rcu_periph_clock_enable(RCU_GPIOA);
	
	/* connect port to USARTx_Tx */
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
	/* connect port to USARTx_Rx */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
	
	/* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, bound);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);
}

串口1初始化代码:

// 串口 1 初始化
void USART1_init(uint32_t bound)
{
	/* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);
	/* enable GPIO clock */
	rcu_periph_clock_enable(RCU_GPIOA);
	
	/* connect port to USARTx_Tx */
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
	/* connect port to USARTx_Rx */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
	
	/* USART configure */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, bound);
    usart_word_length_set(USART1, USART_WL_8BIT);
    usart_stop_bit_set(USART1, USART_STB_1BIT);
    usart_parity_config(USART1, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    usart_enable(USART1);
}

二、串口的输入

        串口输入本教程使用最简单的轮询输入。网上有教程是通过重写scanf实现串口输入的,但是重写scanf的实际使用很不好。数据一多就出错,而且只能被一个串口使用,本人不推荐大家使用。个人觉得还是C语言库里面的getchar()用的舒服。

串口0的输入代码如下:

//串口0的专用 getchar 函数
char USART0_getchar(void)
{
	/* 等待串口输入数据 */
	while (usart_flag_get(USART0, USART_FLAG_RBNE) == RESET);
	return (char)usart_data_receive(USART0);
}

串口1的输入代码如下:

//串口1的专用 getchar 函数
char USART1_getchar(void)
{
	/* 等待串口输入数据 */
	while (usart_flag_get(USART1, USART_FLAG_RBNE) == RESET);
	return (char)usart_data_receive(USART1);
}

三、串口打印

串口0的串口打印输出代码如下:

//串口0的专用 putchar 函数
void USART0_putchar(char ch)
{
	usart_data_transmit(USART0, (uint8_t)ch);
	while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

//串口0的专用 puts 函数
void USART0_puts(char* fmt)
{
	uint16_t i = 0;
	while(fmt[i] != '\0')
	{
		USART0_putchar(fmt[i]);
		i++;
	}
}

串口1的串口打印输出代码如下:

//串口1的专用 putchar 函数
void USART1_putchar(char ch)
{
	usart_data_transmit(USART1, (uint8_t)ch);
	while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));
}

//串口1的专用 puts 函数
void USART1_puts(char* fmt)
{
	uint16_t i = 0;
	while(fmt[i] != '\0')
	{
		USART1_putchar(fmt[i]);
		i++;
	}
}

四、GPS模块的数据解析

        学会了串口的输入输出,解析GPS的经纬度就是个简单的字符串匹配。中科微的GPS模组手册里面有其他数据解析的说明,这里只解析经纬度,其他数据的解析也是大同小异。经纬度的计算方法如下:

 解析代码:

#include "DRG_GPS_Mode.h"

#define BUFF_SIZE 200

typedef struct SaveData 
{
	char N_S[N_S_Length];		//N/S
	char E_W[E_W_Length];		//E/W
} _SaveData;

_SaveData Save_Data;

// 解析 GPS 数据
void parseGpsBuffer(void)
{
	uint8_t ch,Rxbuffer[BUFF_SIZE];
	uint16_t index,i;
	while(1)
	{
		ch = USART1_getchar();
		if(ch == '$')
		{
			index = 0;
			while(ch != ',')
			{
				ch = USART1_getchar();
				Rxbuffer[index] = ch;
				index++;
			}
			if(!strcmp("GNGLL,",(const char*)Rxbuffer))
			{
				for(i = 0;i < 10;i++)
					Save_Data.N_S[i] = USART1_getchar();
				ch = USART1_getchar();
				ch = USART1_getchar();
				ch = USART1_getchar();
				for(i = 0;i < 10;i++)
					Save_Data.E_W[i] = USART1_getchar();
				break;
			}
		}
	}
	/*
	USART0_puts("Save_Data.N_S = ");
	USART0_puts(Save_Data.N_S);
	USART0_puts("\r\n");

	USART0_puts("Save_Data.E_W = ");
	USART0_puts(Save_Data.E_W);
	USART0_puts("\r\n");
	*/
}

// 获取 GPS 纬度数据 - 字符串形式
char* Get_Gps_N_S_str(void)
{
	return Save_Data.N_S;
}

// 获取 GPS 经度数据 - 字符串形式
char* Get_Gps_E_W_str(void)
{
	return Save_Data.E_W;
}

主函数:

#include "DRG_GPS_Mode.h"

int main(void)
{
	USART0_init(115200U);
	USART1_init(9600U);
	USART0_puts("USART0 begin...\r\n");
	USART1_puts("USART1 begin...\r\n");
   	while(1)
	{
		parseGpsBuffer();				// 解析串口 1 上 GPS 模块的数据
		
		USART0_puts("N_S = ");
		USART0_puts(Get_Gps_N_S_str());	// 打印维度字符串数据
		USART0_puts("\r\n");
		
		USART0_puts("E_W = ");
		USART0_puts(Get_Gps_E_W_str());	// 打印经度字符串数据
		USART0_puts("\r\n");
	}
}

串口助手读取到的数据:

 使用定位工具可以判断读取的数据是否准确。注意GPS模块要拿到室外定位,这样数据才准确。

 完整代码:

工程结构如下:

 my_usart为串口驱动,GPS_Mode包含GPS解析的步骤。

1、main.c

#include "DRG_GPS_Mode.h"

int main(void)
{
	USART0_init(115200U);
	USART1_init(9600U);
	USART0_puts("USART0 begin...\r\n");
	USART1_puts("USART1 begin...\r\n");
   	while(1)
	{
		parseGpsBuffer();				// 解析串口 1 上 GPS 模块的数据
		
		USART0_puts("N_S = ");
		USART0_puts(Get_Gps_N_S_str());	// 打印维度字符串数据
		USART0_puts("\r\n");
		
		USART0_puts("E_W = ");
		USART0_puts(Get_Gps_E_W_str());	// 打印经度字符串数据
		USART0_puts("\r\n");
	}
}

2、DRG_GPS_Mode.h

#ifndef _DRG_GPS_MODE_H_
#define _DRG_GPS_MODE_H_

#include "my_usart.h"

//定义数组长度
#define N_S_Length 11
#define E_W_Length 11

void parseGpsBuffer(void);		// 解析 GPS 数据

char* Get_Gps_N_S_str(void);	// 获取 GPS 纬度数据 - 字符串形式
char* Get_Gps_E_W_str(void);	// 获取 GPS 经度数据 - 字符串形式
#endif

3、DRG_GPS_Mode.c

#include "DRG_GPS_Mode.h"

#define BUFF_SIZE 200

typedef struct SaveData 
{
	char N_S[N_S_Length];		//N/S
	char E_W[E_W_Length];		//E/W
} _SaveData;

_SaveData Save_Data;

// 解析 GPS 数据
void parseGpsBuffer(void)
{
	uint8_t ch,Rxbuffer[BUFF_SIZE];
	uint16_t index,i;
	while(1)
	{
		ch = USART1_getchar();
		if(ch == '$')
		{
			index = 0;
			while(ch != ',')
			{
				ch = USART1_getchar();
				Rxbuffer[index] = ch;
				index++;
			}
			if(!strcmp("GNGLL,",(const char*)Rxbuffer))
			{
				for(i = 0;i < 10;i++)
					Save_Data.N_S[i] = USART1_getchar();
				ch = USART1_getchar();
				ch = USART1_getchar();
				ch = USART1_getchar();
				for(i = 0;i < 10;i++)
					Save_Data.E_W[i] = USART1_getchar();
				break;
			}
		}
	}
	/*
	USART0_puts("Save_Data.N_S = ");
	USART0_puts(Save_Data.N_S);
	USART0_puts("\r\n");

	USART0_puts("Save_Data.E_W = ");
	USART0_puts(Save_Data.E_W);
	USART0_puts("\r\n");
	*/
}

// 获取 GPS 纬度数据 - 字符串形式
char* Get_Gps_N_S_str(void)
{
	return Save_Data.N_S;
}

// 获取 GPS 经度数据 - 字符串形式
char* Get_Gps_E_W_str(void)
{
	return Save_Data.E_W;
}

4、my_usart.h

#ifndef _MY_USART_H_
#define _MY_USART_H_

#include "gd32f10x.h"
#include "string.h"

void USART0_init(uint32_t bound);	//串口0 初始化函数
void USART0_putchar(char ch);		//串口0 putchar() 函数
void USART0_puts(char* fmt); 		//串口0 puts() 函数
char USART0_getchar(void);	 		//串口0 getchar() 函数


void USART1_init(uint32_t bound);	//串口1 初始化函数
void USART1_putchar(char ch);		//串口1 putchar() 函数
void USART1_puts(char* fmt); 		//串口1 puts() 函数
char USART1_getchar(void);   		//串口1 getchar() 函数

#endif

5、my_usart.c

#include "my_usart.h"

// 串口 0 初始化
void USART0_init(uint32_t bound)
{
	/* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);
    
	/* enable GPIO clock */
	rcu_periph_clock_enable(RCU_GPIOA);
	
	/* connect port to USARTx_Tx */
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
	/* connect port to USARTx_Rx */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
	
	/* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, bound);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);
}

//串口0的专用 getchar 函数
char USART0_getchar(void)
{
	/* 等待串口输入数据 */
	while (usart_flag_get(USART0, USART_FLAG_RBNE) == RESET);
	return (char)usart_data_receive(USART0);
}

//串口0的专用 putchar 函数
void USART0_putchar(char ch)
{
	usart_data_transmit(USART0, (uint8_t)ch);
	while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

//串口0的专用 puts 函数
void USART0_puts(char* fmt)
{
	uint16_t i = 0;
	while(fmt[i] != '\0')
	{
		USART0_putchar(fmt[i]);
		i++;
	}
}

// 串口 1 初始化
void USART1_init(uint32_t bound)
{
	/* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);
	/* enable GPIO clock */
	rcu_periph_clock_enable(RCU_GPIOA);
	
	/* connect port to USARTx_Tx */
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
	/* connect port to USARTx_Rx */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
	
	/* USART configure */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, bound);
    usart_word_length_set(USART1, USART_WL_8BIT);
    usart_stop_bit_set(USART1, USART_STB_1BIT);
    usart_parity_config(USART1, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    usart_enable(USART1);
}

//串口1的专用 putchar 函数
void USART1_putchar(char ch)
{
	usart_data_transmit(USART1, (uint8_t)ch);
	while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));
}

//串口1的专用 puts 函数
void USART1_puts(char* fmt)
{
	uint16_t i = 0;
	while(fmt[i] != '\0')
	{
		USART1_putchar(fmt[i]);
		i++;
	}
}

//串口1的专用 getchar 函数
char USART1_getchar(void)
{
	/* 等待串口输入数据 */
	while (usart_flag_get(USART1, USART_FLAG_RBNE) == RESET);
	return (char)usart_data_receive(USART1);
}

  • 11
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: gd32f405是一款具有DMA功能的微控制器,可以通过串口与外部设备进行数据通信。串口通信是一种常用的数据传输方式,它通过数据线来传输数据,并且具有较好的适应性和广泛的应用场景。 gd32f405支持使用DMA(直接内存访问)来处理串口数据传输。DMA是一种硬件模块,可以在不需要CPU干预的情况下,直接从内存读取数据并将其传输到外部设备,或将外部设备的数据传输到内存。这样可以减轻CPU的负担,提高数据传输效率。 使用DMA进行串口数据传输有以下几个步骤: 1. 配置DMA通道:首先需要配置DMA通道用于串口数据传输的接口。在gd32f405中,可以使用多个DMA通道进行不同功能的数据传输。 2. 配置串口:需要配置串口相关参数,包括波特率、数据位数、校验位等。gd32f405的串口模块具有多个发送和接收缓冲区,可以通过调用相应的函数对串口进行配置。 3. 配置DMA传输方向和长度:根据具体需求,需要设置DMA的传输方向,即是从内存到外设还是从外设到内存。同时需要设置数据传输的长度。 4. 启动DMA传输:配置完成后,通过调用相应的函数启动DMA传输。DMA将自动从内存读取数据并进行串口传输,或从串口接收数据并写入内存,无需CPU干预。 通过使用DMA进行串口数据传输,可大大提高数据传输效率,减少CPU的负担。gd32f405的DMA功能使得串口通信更加可靠和高效。 ### 回答2: gd32f405是一款单片机芯片,而串口和DMA是其提供的两种功能。 串口是一种用于数据传输的接口,通过串行通信的方式可以实现将数据从一个设备传输到另一个设备。gd32f405内置了多个串口通道,可以通过配置相关寄存器和使用相应的引脚来实现与其他设备的串口通信。 而DMA(Direct Memory Access)是一种直接内存访问的技术,可以在不经过CPU的情况下,直接将数据从外设读取到内存或从内存写入到外设。在gd32f405中,通过配置DMA通道的相关寄存器,可以实现串口数据的DMA传输。 具体实现串口-DMA的步骤如下: 1. 配置串口:包括波特率、数据位、停止位、校验位等参数。 2. 配置DMA通道:包括传输方向、数据宽度、传输大小等参数。 3. 配置内存地址和外设地址:分别指定DMA传输的起始地址和目标地址。 4. 使能串口的DMA模式和DMA通道。 5. 当需要进行数据传输时,触发DMA传输请求。 6. 当DMA传输完成后,通过相应的中断或标志位进行处理。 通过串口-DMA的方式,可以实现高效的数据传输,减轻CPU负担。此外,gd32f405还支持多个DMA通道,可以同时进行多路数据传输,提高系统的数据处理效率。 总结来说,gd32f405芯片提供了串口和DMA功能,可以通过配置相关寄存器和引脚,实现串口数据的高效传输,并且支持多通道的DMA操作,提高系统的性能和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰森硬创客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值