安信可A7模块GPS——编程获取GPS经纬度信息

2023-10-10 03:59

本文主要是介绍安信可A7模块GPS——编程获取GPS经纬度信息,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

帝子降兮北渚,目眇眇兮愁予。袅袅兮秋风,洞庭波兮木叶下。
——屈原《湘夫人》


主机操作系统:Centos 6.7
交叉编译器环境:arm-linux-gcc-4.5.4 (可通过命令/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc -v查询)
开发板平台: fl2440
Linux内核版本: linux-3.0 .54
模块:安信可A7模块


在上篇文章[http://blog.csdn.net/qicheng777/article/details/72677113]中,我们通过命令AT+GPS=1开启了GPS模块了,所以本文是在已经开启GPS模块条件下,并且在开发板上通过命令microcom -s 9600 /dev/ttyUSB0监听能够接收到GPS发出的信息后,进行如下编程操作才有意义。

一、串口设置程序

1、关于串口

   因为我们要对GPS所连接的串口进行操作,所以我们必须对其进行相应的设置比如波特率等等的设置才可以实现。比如我们在SecureCRT连接串口时,需要对这些参数进行设置。所以我们需要编程来实现对这些参数的设置。

这里写图片描述

其中串口设置其实就相当于串口通信的协议,

波特率:是为了两者信号流能同步,
数据位:是指又几位数据封装成一帧
结束位:是指以帧传输数据时,协定好结束位,便于提取有效数据
奇偶校验:检验数据的一种手段

关于串口编程具体操作,请参照博客:
[http://blog.csdn.net/dahailantian1/article/details/5954002]
[http://www.cnblogs.com/jason-lu/articles/3173988.html]

串口编程对应一个重要的结构体:

struct termio
{       unsigned short  c_iflag;       /* 输入模式标志 */unsigned short  c_oflag;       /* 输出模式标志 */unsigned short  c_cflag;       /* 控制模式标志*/unsigned short  c_lflag;        /*区域模式标志或本地模式标志或局部模式*/unsigned char   c_line;         /* line discipline行控制*/unsigned char   c_cc[NCC];      /* control characters */
};

c_cflag操作:

c_cflag有很多参数,类似open()函数 RDONLY等。每个参数是一个宏,每个宏只有一个位为1.例如,某个参数的宏可能00000001,则第一位等于1表示这个参数所代表的功能开启,也就是说,如果是一个字节有,8个位,每个位对应一个功能,与c_cflag作或运算就能开启相应的位。

IGNBRK :忽略输入中的 BREAK 状态。 (忽略命 令行中的中
断)
BRKINT :(命令行出 现中断时,可产生一插断)如果设置了
IGNBRK,将忽略 BREAK。如果没有设置,但是设置了 BRKINT,
那么 BREAK 将使得输入和输出队列被刷新,如果终端是一个前
台进程组的控制终端,这个进程组中所有进程将收到 SIGINT 信
号。如果既未设置 IGNBRK 也未设置 BRKINT,BREAK 将视为与
NUL 字符同义,除非设置了 PARMRK,这种情况下它被视为序列
377
* IGNPAR :忽略桢错误和奇偶校验错。
* PARMRK :如果没有设置 IGNPAR,在有奇偶校验错或桢错误的字
符前插入 377 。如果既没有设置 IGNPAR 也没有设置
PARMRK,将有奇偶校验错或桢错误的字符视为 �。
* INPCK :启用输入奇偶检测。
* ISTRIP :去掉第八位。
* INLCR :将输入中的 NL 翻译为 CR。(将收到 的换行符号转换
为Return)
* IGNCR :忽略输入中的回车。
* ICRNL :将输入中的回车翻译为新行 (除非设置了 IGNCR)(否则
当输入信号有 CR 时不会终止输入)。
* IUCLC :(不属于 POSIX) 将输入中的大写字母映射为小写字
母。
* IXON :启用输出的 XON/XOFF 流控制。
* IXANY :(不属于 POSIX.1;XSI) 允许任何字符来重新开始输
出。(?)
* IXOFF :启用输入的 XON/XOFF 流控制。
* IMAXBEL:(不属于 POSIX) 当输入队列满时响零。Linux 没有实
现这一位,总是将它视为已设置。

2、串口设置函数(uart.c):

#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>/***************************************************************************************  Description: 串口参数配置*  Input Args: fd:open打开的文件描述符 nspeed:波特率 nBits:数据位数 nEvent:奇偶校验 nStop:停止位*  Output Argtingzhis: 串口参数设置失败返回-1* Return Value:*************************************************************************************/
int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop)
{struct termios newttys1,oldttys1;if(tcgetattr(fd,&oldttys1)!=0)         //保存原先串口配置{perror("Setupserial 1");return -1;}bzero(&newttys1,sizeof(newttys1));       //将一段内存区域的内容全清为零
newttys1.c_cflag|=(CLOCAL|CREAD );       //CREAD 开启串行数据接收,CLOCAL并打开本地连接模式   newttys1.c_cflag &=~CSIZE;              //设置数据位数
switch(nBits)     //选择数据位  {case 7:newttys1.c_cflag |=CS7;break;case 8:newttys1.c_cflag |=CS8;break;}
switch( nEvent )    //设置校验位  {case '0':       //奇校验  newttys1.c_cflag |= PARENB;             //开启奇偶校验  newttys1.c_iflag |= (INPCK | ISTRIP);   //INPCK打开输入奇偶校验;ISTRIP去除字符的第八个比特  newttys1.c_cflag |= PARODD;             //启用奇校验(默认为偶校验)  break;case 'E' :       //偶校验  newttys1.c_cflag |= PARENB;             //开启奇偶校验  newttys1.c_iflag |= ( INPCK | ISTRIP);  //打开输入奇偶校验并去除字符第八个比特  newttys1.c_cflag &= ~PARODD;            //启用偶校验;  break;case 'N':     //关闭奇偶校验newttys1.c_cflag &= ~PARENB;break;}switch( nSpeed )        //设置波特率  {case 2400:cfsetispeed(&newttys1, B2400);           //设置输入速度cfsetospeed(&newttys1, B2400);           //设置输出速度break;case 4800:cfsetispeed(&newttys1, B4800);cfsetospeed(&newttys1, B4800);break;case 9600:cfsetispeed(&newttys1, B9600);cfsetospeed(&newttys1, B9600);break;case 115200:cfsetispeed(&newttys1, B115200);cfsetospeed(&newttys1, B115200);break;default:cfsetispeed(&newttys1, B9600);cfsetospeed(&newttys1, B9600);break;}if( nStop == 1)                      //设置停止位;若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。  {newttys1.c_cflag &= ~CSTOPB;      //默认为送一位停止位;  }else if( nStop == 2){newttys1.c_cflag |= CSTOPB;       //CSTOPB表示送两位停止位;  }//设置最少字符和等待时间,对于接收字符和等待时间没有特别的要求时newttys1.c_cc[VTIME] = 0;        //非规范模式读取时的超时时间;  newttys1.c_cc[VMIN]  = 0;        //非规范模式读取时的最小字符数;  tcflush(fd ,TCIFLUSH);           //tcflush清空终端未完成的输入/输出请求及数据;TCIFLUSH表示清空正收到的数据,且不读取出来 // 在完成配置后,需要激活配置使其生效if((tcsetattr( fd, TCSANOW,&newttys1))!=0) //TCSANOW不等数据传输完毕就立即改变属性  {perror("com set error");return -1;}return 0;
} /* ----- End of if()  ----- */
    这个程序主要是用上述的结构体中c_cflag进行操作,设置波特率、数据位、校验位、停止位。在设置波特率时需要在数字前加上'B',如B9600,B15200.使用其需通过“与”“或”操作方式。

二、GPS解析程序

 该函数主要用于解析GPS中的GPRMC(推荐最小定位信息)所在行的经纬度,以及时间等信息。

1、GPS程序(alayse_gps.c):

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>#include "gps.h"
int gps_analysis(char *buff,GPRMC *gps_date)
{char *ptr=NULL;if(gps_date==NULL)return -1;if(strlen(buff)<10)return -1;if(NULL==(ptr=strstr(buff,"$GPRMC")))return -1;sscanf(ptr,"$GPRMC,%d.000,%c,%f,N,%f,E,%f,%f,%d,,,%c*",&(gps_date->time),&(gps_date->pos_state),&(gps_date->latitude),&(gps_date->longitude),&(gps_date->speed),&(gps_date->direction),&(gps_date->date),&(gps_date->mode));return 0;
} /* ----- End of if()  ----- */float caculate(float *x)  //用于经纬度转换
{   int a;   float b,c,d,e,f;   a=*x/100;           //30   b=(int)((*x/100-a)*100);   //29   c=((*x/100-a)*100-b)*60;   d=b/60;       e=c/3600; f=a+d+e;   return f;   
}int print_gps(GPRMC *gps_date)
{float mylatitude,mylongitude;mylatitude = caculate(&gps_date->latitude);mylongitude = caculate(&gps_date->longitude);printf("                                                           \n");printf("                                                           \n");printf("===========================================================\n");printf("==                 全球定位系统                         ==\n");printf("==       作者:     杨泥                                ==\n");printf("==       邮箱:      497049229@qq.com                    ==\n");printf("==       开发平台: fl2440                              ==\n");printf("===========================================================\n");printf("                                                         \n");printf("                                                         \n");printf("===========================================================\n");printf("==                                                       \n");printf("==   GPS 状态   : %c  [A:有效         V:无效       ]      \n",gps_date->pos_state);printf("==   GPS 模式   : %c  [A:自主定位     D:差分定位   ]             \n", gps_date->mode);printf("==   日期 : 20%02d-%02d-%02d                             \n",gps_date->date%100,(gps_date->date%10000)/100,gps_date->date/10000);printf("==   当前时间: %02d:%02d:%02d                               \n",(gps_date->time/10000+8)%24,(gps_date->time%10000)/100,gps_date->time%100);printf("==   经度: %.9f  N                                    \n",mylatitude);printf("==   纬度:%.9f  E                                    \n",mylongitude);printf("==   速度: %.3f m/s                                         \n",gps_date->speed);printf("==                                                       \n");printf("===========================================================\n");return 0;}  /* ----- End of print_gps()  ----- */

该程序中用到两个重要的函数:strstr()以及sscanf()

strstr( )函数

char strstr( char *str, char substr );
【参数说明】str为要检索的字符串,substr为要检索的子串。
【返回值】返回字符串str中第一次出现子串substr的地址;如果没有检索到子串,则返回NULL。

if(NULL==(ptr=strstr(buff,”$GPRMC”)))
return -1;
这里返回的是GPRMC所在位置的地址。

sscanf()函数

int sscanf( string str, string fmt, mixed var1, mixed var2 … );
作用:从一个字符串中读进与指定格式相符的数据.
sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
假设GPRMC为如下信息:
$GPRMC,062363.00,A,2236.33923,N,11402.35855,E,0.304,306.80,020411,,,A*62

sscanf(ptr,”$GPRMC,%d.000,%c,%f,N,%f,E,%f,%f,%d,,,%c*”,&(gps_date->time),&(gps_date->pos_state),&(gps_date->latitude),&(gps_date->longitude),&(gps_date->speed),&(gps_date->direction),&(gps_date->date),&(gps_date->mode));
则该函数将ptr中以GPRMC为起始地址的内容格式化输入到结构体的各成员中去,结构体定义在”gps.h”中。

经纬度转换函数:

该函数将aabb.mmmm格式的经纬度换算成aa.mmmmm格式。(存在一定误差)

float caculate(float *x)  //用于经纬度转换
{   int a;   float b,c,d,e,f;   a=*x/100;           //30   b=(int)((*x/100-a)*100);   //29   c=((*x/100-a)*100-b)*60;   d=b/60;       e=c/3600; f=a+d+e;   return f;   
}

三、主程序(gps_main.c):

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>#include "gps.h"
#include "gps_uart.h"
#define GPS_LEN 512 int gps_analysis(char *buff,GPRMC *gps_date);
int print_gps(GPRMC *gps_date);
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);/*********************************************************************************  Description:   main():程序执行的入口*   Input Args:    *  Output Args:* Return Value:********************************************************************************/
int main (int argc, char **argv)
{int fd = 0;int nread = 0;GPRMC gprmc;char gps_buff[GPS_LEN];char *dev_name = "/dev/ttyUSB0";fd=open(dev_name,O_RDWR|O_NOCTTY|O_NDELAY);if(fd<0){printf("open ttyS1 error!!\n");return -1;}set_opt( fd,9600,8,'N',1); //设置串口信息while(1){sleep(2);nread = read(fd,gps_buff,sizeof(gps_buff));if(nread<0){printf("read GPS date error!!\n");return -2;}printf("gps_buff: %s\n", gps_buff);memset(&gprmc, 0 , sizeof(gprmc));gps_analysis(gps_buff,&gprmc);print_gps(&gprmc);}close(fd);return 0;
} /* ----- End of main() ----- */

打开串口

fd = open(“/dev/ttyS0”,O_RDWR | O_NOCTTY | O_NDELAY);
参数–
O_NOCTTY:通知linux系统,这个程序不会成为这个端口的控制终端.
O_NDELAY:通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止).
对于串口的读写操作和对于一般设备的读写操作相同。

设置串口参数

调用uart.c中的set_op()t函数
set_opt( fd,9600,8,’N’,1);
波特率设为9600;数据选择位设置位8位;N表示关闭奇偶校验位;停止位为1,则清除CSTOPB。


四、头文件(gps.h)

#ifndef __GPS_H__
#define __GPS_H__typedef unsigned int UINT;typedef int BYTE;typedef long int WORD;typedef struct __gprmc__{UINT time;                  //格林威治时间char pos_state;             //定位状态float latitude;             //纬度float longitude;            //经度float speed;                //移动速度float direction;            //方向UINT date;                  //日期float declination;          //磁偏角char dd;                    //磁偏角方向char mode;}GPRMC;extern int gps_analysis(char *buff,GPRMC *gps_date);extern int print_gps(GPRMC *gps_date);extern int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);#endif

这里定义了GPS的结构体,并且把相关函数设置为外部函数(extern),方便函数能在其他程序中调用。


五、编译运行:

直接编译

对于多个C程序以及头文件,我们可以把所有的文件放在同一个文件夹下,通过命令直接编译:

[yangni@centos6 gps]$ gcc *.c -o gps_test
这里写图片描述

通过Makefile编译

当然也可以写一个简单的Makefile,和上述编译方式其实是一样的:

CC=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gccobjs=set_uart.o analyse_gps.o gps_main.o
srcs=set_uart.c analyse_gps.c gps_main.cgps_test: $(objs)$(CC) -o gps_test $(objs)@make cleangps_main.o: $(srcs) gps.h$(CC) -c  $(srcs) set_uart.o:  set_uart.c$(CC) -c  set_uart.canalyse_gps.o: analyse_gps.c gps.h$(CC) -c  analyse_gps.cclean:  rm *.o  

通过制作库来编译

 我们可以通过制作静态库或动态库来进行编译,然后编译主程序来找到动态或者静态链接。具体参照楼主的另外一篇博客:

这里写图片描述
[http://blog.csdn.net/qicheng777/article/details/52959291]

生成可执行文件后,下载到开发板上就可以运行了:
这里写图片描述


总结:

分析该程序,我们可以从主函数开始看。我们要操作的是串口,所以具体可以有如下几步总结:1、打开设备"/dev/ttyUSB0"
2、设置串口波特率、数据位等
3、将该设备打印出的GPS信息读入一个buf中
4、定义一个GPRMC结构体gprmc,并用memset进行初始化。
5、将buf中的内容以及gprmc作为参数传到alayse_gps()函数中,该函数会将buf中的内容以格式化输入到gprmc中。
6、gprmc获得了各成员的值,将gprmc作为参数传到print_gps函数,该函数打印出相应的GPS信息,

本文参考博客:[http://blog.csdn.net/hulu_arm/article/details/50766394]

这篇关于安信可A7模块GPS——编程获取GPS经纬度信息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/177775

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)