解析GPS数据(长字符串解析示例)

news/2024/7/16 7:58:37 标签: stm32, 单片机, ide, 嵌入式硬件, mcu

文章目录

    • 1、ATGM336H模块介绍
    • 2、驱动编写
    • 3、源码

这里GPS一般返回的都是大量的数据,而且是一行行的那种,大部分数据也不太用的到,所以这个时候用串口DMA空闲中断其实就意义不大,这样我们就可以用一种新的思路来进行数据解析,专门针对这样的数据!!!

1、ATGM336H模块介绍

这里我用的大概长这样,还有很多其他版本的,不过区别不大,都差不多,可对照学习
在这里插入图片描述
参数说明:

参数详情说明
波特率:9600(默认),可用软件设置
可用卫星:GPS和北斗双模
输出协议:NMEA-0183
TXD/RXD电平:串口TTL电平
超小尺寸:15mm*13mm

这里官方还给出了输出经纬度转换的计算方法

在这里插入图片描述

2、驱动编写

在cubemx中配置如下,该模块是使用串口进行数据接受的,因此我们这里准备两个串口,其中接收数据的串口开启中断
在这里插入图片描述
之后我们根据官方数据格式编写数据结构体,同时在结构体中进行标志位等的设计
在这里插入图片描述
下面就是我们数据解析的重头戏了,不像以往空闲中断的方式,一次放入一大堆数据,这样比较吃内存,如果是数据比较规律就还好,但是如果数据里面有很多无效信息的时候,就没有必要浪费这个内存,这种采用接收中端来解析的方式就比较合适了,可以很好的处理数据,而且不会过度的占用内存,但是缺点也比较明显,就是设备会频繁的进入中断,这个是我们需要考量的因素,根据实际情况来选用!!!
在这里插入图片描述
经过上面的过程我们只是获取到了数据,并将数据放到结构体里面,但是还没有把数据把数据放到我们想要的变量里面,因此我们下面就要对这个有效数据进行进一步的处理,这里我们用到了strstr这个函数,函数的用法如下所示,就是查找函数,这里我们用来查找字符串里面的分隔符,函数的描述如下所示,根据这个方法,我们就可以很方便的获取我们需要的字符串子串。
在这里插入图片描述
下面是解析函数的使用说明,他的计算流程我已经在图中说清楚了
在这里插入图片描述
之后我们就可以解析并打印数据了,打印数据这里只是比较简单的printf函数,就不具体介绍了,详情可以查看源代码
在这里插入图片描述

这里特别注意

  • gps在室内一般是没有信号的,不要尝试在室内使用,最好是阳台,这样效果好点!
  • 第一次使用官方宣称是冷启动,耗时比较长,1-10分钟,所以不要急

3、源码

gps.c

/*
 * gps.c
 *
 *  Created on: Mar 25, 2022
 *      Author: LX
 */


#include "gps.h"
#include "string.h"
#include "stdio.h"

_SaveData Save_Data;

void errorLog(int num)
{
  while (1)
  {
    printf("ERROR%d\r\n", num);
  }
}
void clrStruct()
{
  Save_Data.isGetData = 0;
  Save_Data.isParseData = 0;
  Save_Data.isUsefull = 0;
  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);
}
//gps数据解析
void parseGpsBuffer()
{
    char *subString;
    char *subStringNext;
    char i = 0;
    if (Save_Data.isGetData)
    {
        Save_Data.isGetData = 0;
        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 = 1;
                    if (usefullBuffer[0] == 'A')
                        Save_Data.isUsefull = 1;
                    else if (usefullBuffer[0] == 'V')
                        Save_Data.isUsefull = 0;
                }
                else
                {
                    errorLog(2); //解析错误
                }
            }
        }
    }
}
//gps数据打印
void printGpsBuffer()
{
    if (Save_Data.isParseData)
    {
        Save_Data.isParseData = 0;

        printf("Save_Data.UTCTime = ");
        printf(Save_Data.UTCTime);
        printf("\r\n");

        if (Save_Data.isUsefull)
        {
            Save_Data.isUsefull = 0;
            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");
        }
    }
}

gps.h

/*
 * gps.h
 *
 *  Created on: Mar 25, 2022
 *      Author: LX
 */

#ifndef GPS_H_
#define GPS_H_

#include "main.h"

//定义数组长度
#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
{
	uint8_t GPS_Buffer[GPS_Buffer_Length];
	uint8_t isGetData;		//是否获取到GPS数据
	uint8_t isParseData;	//是否解析完成
	uint8_t UTCTime[UTCTime_Length];		//UTC时间
	uint8_t latitude[latitude_Length];		//纬度
	uint8_t N_S[N_S_Length];		//N/S
	uint8_t longitude[longitude_Length];		//经度
	uint8_t E_W[E_W_Length];		//E/W
	uint8_t isUsefull;		//定位信息是否有效
} _SaveData;

void clrStruct();
void parseGpsBuffer();
void printGpsBuffer();

#endif /* GPS_H_ */


http://www.niftyadmin.cn/n/980289.html

相关文章

两种方法实现 打印1-100 之间的奇数和 或 偶数和:

输出 1 -100 的办法&#xff1a; rootzhengzelin:~\# for i in $(seq 1 100);do echo $i;done |wc -l # 太长了 &#xff0c;使用 wc命令统计行数即可 100rootzhengzelin:~\# for i in {1..100};do echo $i;done |wc -l 100rootzhengzelin:~\# a1;while [ $a -le 100 ];do ec…

Bash Shell 中的while 循环、 do...while

文章目录while 循环的语法结构 和 一些例子&#xff1a;1、求 10 以内每个整数的平方值&#xff1a;2、使用 while 循环 的嵌套来实现打印三角形&#xff1a;do..while 语法&#xff1a;此链接通往 Bash Shell 编程学习的目录导航 &#xff0c;从入门到放弃&#xff0c;感兴趣的…

bash shell 跳出循环 : break or continue :

文章目录break 跳出整个循环&#xff01;continue 跳出当前循环注意&#xff1a;此链接通往 Bash Shell 编程学习的目录导航 &#xff0c;从入门到放弃&#xff0c;感兴趣的可以去看看&#xff1a; break 跳出整个循环&#xff01; rootzhengzelin:~# cat test.sh #!/bin/bas…

Bash Shell 之 nutil循环

文章目录此链接通往 Bash Shell 编程学习的目录导航 &#xff0c;从入门到放弃&#xff0c;感兴趣的可以去看看&#xff1a; until 循环 与 while 循环结构类似&#xff1b; 区别&#xff1a; while for 等循环是表达式为真&#xff08;返回值为0&#xff09; &#xff0c;才执…

Bash Shell 中的 select 选择语句 以及 PS3 :

文章目录语法结构&#xff1a;注意点&#xff1a;例子&#xff1a;此链接通往 Bash Shell 编程学习的目录导航 &#xff0c;从入门到放弃&#xff0c;感兴趣的可以去看看&#xff1a; 语法结构&#xff1a; select varname in (表达式) do cmd done注意点&#xff1a; 1、 s…

Bash Shell 中的 函数使用 注意事项 及 return 退出函数

文章目录1、函数介绍2、函数定义的方式&#xff1a;3、注意点&#xff1a;4、调用函数&#xff1a;5、同一个脚本具有多个相同函数名 时&#xff1a;6、调用函数时&#xff0c;通过 位置变量 传递参数&#xff1a;8、将函数赋值给变量&#xff1a;9、调用函数内部的参数&#x…

Bash Shell 中 常见的面试题:(理论基础 及 脚本编写)

文章目录理论基础篇&#xff1a;①、如何向脚本内传递参数&#xff01;②、[ ] 和 [[ ]] 的区别&#xff01; 以及 整数运算符 使用什么&#xff1f;③、() 和 { } 的共同点 及 区别&#xff1a;④、列举几个 环境变量&#xff0c;并且 说出他们的作用&#xff1a;⑤、关于 变量…

文件、文本、目录 处理命令大全 目录导航!

此文章作为一个目录导航&#xff0c;更加方便的通往其他文章&#xff01; 文件目录基础篇&#xff1a; 1、touch —— 创建文件 —— 外部命令 2、rm —— 删除文件 或 目录 —— 外部命令 3、mkdir —— 创建目录&#xff1b;rmdir —— 删除空目录 —— 两个都为外部命令 …