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

2023-05-16

前言:

        最近入手了个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);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • Android 将阿拉伯数字转换为英文数字

    我从 GPS 收到以下错误 Fatal Exception java lang NumberFormatException Invalid double 现在 这是我通过 Fabric 从用户处收到的错误 它看起来像阿拉伯语 所以我猜只有当
  • 通过js获取WebView中的位置

    我正在尝试创建 WebView 它将通过 js 获取 GPS 本地化 但是当我单击应该显示本地化的按钮时 在android 4 1 1 模拟器 中 错误代码2 无法启动地理定位服务 在 android 4 1 2 phone 中什么也没有发
  • 信号好的情况下GPS更新间隔越快?

    我试图限制我的程序每 10 秒更新一次位置 而不是不断更新 以减少电池消耗 当我在室内调试且信号较弱 即 GPS 图标闪烁 时 此方法工作正常 但如果手机得到正确修复 即 GPS 图标静态 更新间隔会增加到大约一秒 我知道代码mLocati
  • 如何测试GPS状态?

    我现在创建一个应用程序来通过 GPS 检测设备的位置 我对 GPS 状态有疑问 我查看 GpsStatus Listener 但它很复杂 因为我是 Android 新手 这是我尝试对 GPS 状态执行的操作 我是否走在正确的轨道上 fina
  • Java中的多点三边测量算法

    我正在尝试在我的 Android 应用程序中实现三边测量算法来确定用户的室内位置 我正在使用超宽带信标来获取到固定点的距离 我能够采用中建议的方法三边测量法 Android Java https stackoverflow com ques
  • 我如何从 JMapViewer 世界地图中获取鼠标单击位置

    我正在使用地图浏览器 http wiki openstreetmap org wiki JMapViewerjar 在 JPanel 上显示世界地图 在地图上我添加MapMarkerDot s这是 GPS 点 问题是当我单击MapMarke
  • 设置模拟位置时 GPS 提供商未知错误?

    我正在尝试设置我的模拟位置 但是 我收到以下错误 提供商 gps 未知 并且不确定出了什么问题 我已经获得了在manifest xml 中声明的所有权限以及所有参数 模拟定位法 Initiates the method to set the
  • 在没有互联网的情况下使用 Javascript 获取 GPS 位置 [重复]

    这个问题在这里已经有答案了 您好 如果设备具有 GPS 硬件 我们可以在没有互联网连接的情况下使用 JavaScript 获取 GPS 位置吗 请注意谁将其标记为重复 我需要 JavaScript 在没有互联网连接的情况下工作 并使用 GP
  • GPS 坐标(以度为单位)来计算距离

    在iPhone上 我以十进制度数获取用户的位置 例如 纬度39 470920和经度 0 373192 也就是A点 我需要用另一个 GPS 坐标 同样以十进制表示 B 点创建一条线 然后 计算从 A 到 B 的线与另一个点 C 之间的距离 垂
  • Android:计算两个位置之间距离的最佳方法

    我在这个主题上做了一些研究 但有很多观点并没有给出一个清晰的图像 我的问题是这样的 我正在为 Android 开发一个基于 GPS 的应用程序 在其中我想实时了解 Android LocationManager 指定的当前位置与其他位置之间
  • 如何知道jar文件是否已经在运行?

    经过谷歌研究后 我找到了很好的答案 例如 1 using jps or jps l让 jars 在 JVM 下运行 这个答案可以 但是如果用户根本没有安装java并且我使用例如 bat文件和带有java JRE的文件夹运行我的jar 另外
  • LocationManager requestLocationUpdates minTime OR minDistance

    我用的是安卓系统LocationManager及其方法requestLocationUpdates像这样 locationManager requestLocationUpdates LocationManager GPS PROVIDER
  • 关闭应用程序后如何调试

    我正在尝试重现问题 这需要在特定位置关闭并重新打开我的应用程序 这是我的问题 1 如何查看我的日志 使用NSLog命令 当我的 iPhone 未连接到 XCode 时 2 是否可以将iPhone模拟器的特定位置 例如市中心 设置为默认位置
  • 如何创建在 React-Native 中检测自动位置的地图

    我已经在react native中创建了地图 参考https github com lelandrichardson react native maps https github com lelandrichardson react nat
  • 是否可以自定义区域形状?核心位置

    例如 至少我想要一个正方形 矩形 道路的形状作为我的区域 不它不是 根据文档 目前唯一的区域类是 CLCircularRegion 显然是圆形 和 CLBeaconRegion 基于与 iBeacon 的接近度 未来苹果可能会添加对自定义形
  • 如何在Android中获取当前位置[重复]

    这个问题在这里已经有答案了 我在使用 Android 定位系统的网络提供程序获取当前位置坐标时遇到麻烦 已经阅读了大量教程并在我的项目中实现了 4 或 5 个现有类 所有这些类都给了我最后的坐标 但不是当前的坐标 我很确定这个问题是我所缺少
  • 如何在从另一个活动调用一个活动时延迟一些?

    我有一个应用程序 其中我正在接收包含他的位置的短信 收到短信后 它会调用另一个活动来启动并将该位置传递给该活动以将其绘制在地图上 在调用第二个活动之前 它会显示一个类似于通知的吐司在屏幕上 但由于调用第二个活动 吐司没有出现 我的问题是我们
  • 我可以使用手机信号塔的信息在没有 GPS 服务的 j2me 中获取移动设备的位置吗

    我可以通过 j2me 编程获取未安装 GPS 装置的移动设备的位置吗 我可以使用手机信号塔信息获取位置吗 我听说过三角测量 https stackoverflow com a 9820133 839601 method 并且经历了http
  • Android 7.0+ 屏幕关闭时前台服务无法接收位置更新

    我正在尝试创建一个 Android 应用程序 在设备屏幕关闭时连续实时记录设备位置数据 我的代码可以在 Android 6 0 及更早版本中正常运行 但 Android 7 0 似乎会破坏我的应用程序 我已经实现了一个 Android 前台
  • 在android中快速获取当前位置

    我有一个 Android 应用程序需要设备当前位置 纬度和经度 我已经尝试了网上的一些教程 特别是堆栈溢出的一些解决方案 但它们对我来说效果不佳 我的要求非常简单 首先 我需要它速度快 并且在片段开始时需要一次位置 其次 我需要它尽可能精确

随机推荐