FL2440——基于安信可A7模块编程实现GPS定位功能
来源:互联网 发布:游戏源码交易平台 编辑:程序博客网 时间:2024/05/16 09:32
基于安信可A7模块编程实现GPS定位功能
A7 GPRS/GPS模块是安信可科技最新推出的“简单、易用的GPRS透传模块”!提供串口转GPRS/短信息/语音通话等信息传输功能,方便嵌入在众多的监测,遥控,安防,车辆导航,定位的硬件产品。以及当下火热的可穿戴设备上,可以应用在诸如儿童/老人智能定位鞋,电动车/山地车定位报警,宠物定位等领域。
要学习GPS模块并编程实现GPS定位功能,自然不能不了解NMEA-0183协议,NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机、GPS数据处理软件、导航软件都遵守或者至少兼容这个协议。
NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等。
其中$GPRMC语句的格式如下:
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh< CR>< LF>
例如完整的GPRMC字段:$GPRMC,065118.000,A,3029.65673,N,11423.61801,E,0.00,0.00,290517,,,A*6F
字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段1:UTC时间,hhmmss.sss格式【6:51:58】
字段2:状态,A=定位,V=未定位【定位】
字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)【3029.65637】
字段4:纬度N(北纬)或S(南纬)【北纬】
字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)【11423.61801】
字段6:经度E(东经)或W(西经)【东经】
字段7:速度,节,Knots【0.00节】
字段8:方位角,度【0.00】
字段9:UTC日期,DDMMYY格式【290517】
字段10:磁偏角,(000 - 180)度(前导位数不足则补0)【空】
字段11:磁偏角方向,E=东W=西【空】
字段12:模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)【自动】
字段13:校验值【校验值为6F】
这里,星号”*”为校验和识别符,其后面的两位数为校验和,代表了“$”和“*”之间所有字符(不包括这两个字符)的异或值的十六进制值。上面这条例句的校验和是十六进制的50,也就是十进制的80。
开发板测试GPS
将A7模块与开发板相连,使用AT命令打开A7模块的GPS功能
连线
我们使用的A7 GPS/GPRS 模块通过TTL电平串口发送命令和返回数据,有两种方式将模块与开发板相连。
1. 开发板默认的串口3是使用的TTL电平,但是默认没有开启。可以参考这篇教程开启串口3,使用该串口的相关引脚与A7的相关引脚相连。
2. 使用usb转TTL串口转接线,前提是使能开发板的USB驱动,并在linux内核中选中转接芯片的支持。比如我的USB转串口芯片为cp210,因此在内核的make menuconfig->Device Drivers->USB support ->USB Serial Converter support选项中选择USB CP210x family of UART Bridge Controllers 选项,重新编译烧录内核。
使能USB驱动:http://blog.csdn.net/edroid1530/article/details/70186871
推荐使用第二种连接方法,将串口AT指令控制发送端(U_TXD)和串口AT指令控制接收端(U_RXD)分别与USB转TTL转接头上的RXD和TXD相连,然后GND与GND相连。
打开GPS
将A7模块成功连上开发板以后,在开发板上使用microcom命令监听相关串口,如果是USB转串口芯片连接则监听串口/dev/ttyUSB0,如果使用开发板默认的TTL电平串口,则监听/dev/ttyS2,输入命令AT返回OK之后,使用AT+GPS=1命令打开GPS功能。
>: microcom -s 115200 /dev/ttyUSB0 >at/*测试GPRS模块*/OK>AT+GPS=1/*打开gps功能*/OK
此时将A7模块上的U_TXD连线切换到A7模块上的GPS_TXD引脚,其他连线不变。以波特率为9600重新打开监听串口,将会不断的收到GPS定位的数据。
>: microcom -s 9600 /dev/ttyUSB0 $GPGGA,,,,,,0,00,,,M,,M,,0000*66$GPGSA,A,1,,,,,,,,,,,,,,,*1E$GPGSV,1,1,00,*55$GPRMC,,V,,,,,,,,,,N*53$GPVTG,,T,,M,,N,,K,N*2C$GPGGA,,,,,,0,00,,,M,,M,,0000*66$GPRMC,065118.000,A,3029.65673,N,11423.61801,E,0.00,0.00,290517,,,A*6F...
编程获取GPS定位信息
由于A7模块获取到的GPS定位信息是通过串口发送到终端设备,我们在编程实现获取GPS定位信息中自然涉及到串口编程。
串口配置文件set_ttyUSB0.c
在set_ttyUSB0的C文件中,实现了对串口的波特率,数据位,停止位,奇偶校验位的设定。
/********************************************************************************* * Copyright: (C) 2017 Li Wanneng<liwjng@gmail.com> * All rights reserved. * * Filename: set_ttyUSB0.c * Description: This file set_ttyUSB0 * * Version: 1.0.0(05/29/2017) * Author: Li Wanneng <liwjng@gmail.com> * ChangeLog: 1, Release initial version on "05/29/2017 08:02:53 PM" * ********************************************************************************/#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: * Output Args: * Return Value: *************************************************************************************/int set_serial(int fd,int nSpeed,int nBits,char nEvent,int nStop){ struct termios newttyUSB0,oldttyUSB0;/*注释1*/ /*保存原有串口配置*/ if(tcgetattr(fd,&oldttyUSB0)!=0) /*注释2*/ { perror("Setupserial 1"); return -1; } bzero(&newttyUSB0,sizeof(newttyUSB0)); 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) { perror("com set error"); return -1; } return 0;} /* ----- End of set_serial() ----- */
下面来分析分析上面程序中需要注意的几个部分。
- 注释1:termios结构体
该结构体原型为:
struct termios { tcflag_t c_iflag; /*input flags*/ tcflag_t c_oflag; /*output flags*/ tcflag_t c_cflag; /*control flags*/ tcflag_t c_lflag; /*local flags*/ cc_t c_cc[NCCS]; /*control characters*/ };
相关成员变量注释已经给出,其中要注意的是c_cflag成员变量。通过该变量设置串口的波特率,数据位停止位等参数。在设置波特率的时候前面要加上字母“B”。
c_cflag的参数可设置为:
CBAUD:(不属于 POSIX)波特率掩码 (4+1 位)。
CBAUDEX:(不属于 POSIX) 扩展的波特率掩码 (1 位),包含在 CBAUD 中。
CSIZE:字符长度掩码。取值为 CS5, CS6, CS7, 或 CS8。
CSTOPB:设置两个停止位,而不是一个。
CREAD:打开接受者。
PARENB:允许输出产生奇偶信息以及输入的奇偶校验。
PARODD:输入和输出是奇校验。
CLOCAL:忽略 modem 控制线。
- 注释2:tcgetattr函数
tcgetattr函数原型为int tcgetattr(int fd, struct termios *termios_p);用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios 结构体中。如果成功返回零;失败,返回非零。
gps数据分析gps_analyse.c
在gps_analyse.c文件中有两个函数gps_analyse 和 print_gps ,分别实现对gps返回的数据进行分析处理和打印到标准输出。
/********************************************************************************* * Copyright: (C) 2017 Li Wanneng<liwjng@gmail.com> * All rights reserved. * * Filename: gps_analyse.c * Description: This file gps_analyse * * Version: 1.0.0(05/29/2017) * Author: Li Wanneng <liwjng@gmail.com> * ChangeLog: 1, Release initial version on "05/29/2017 08:13:42 PM" * ********************************************************************************/#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"/************************************************************************************** * Description: * Input Args: * Output Args: * Return Value: *************************************************************************************/int gps_analyse (char *buff,GPRMC *gps_data){ char *ptr = NULL; if(gps_data==NULL) { return -1; } if(strlen(buff)<10) { return -1; } /*如果buff字符串中包含字符"$GPRMC"则将$GPRMC的地址赋值给ptr*/ if(NULL==(ptr=strstr(buff,"$GPRMC"))) { return -1; } sscanf(ptr,"$GPRMC,%d.000,%c,%f,N,%f,E,%f,%f,%d,,,%c*",&(gps_data->time),&(gps_data->pos_state),&(gps_data->latitude),&(gps_data->longitude),&(gps_data->speed),&(gps_data->direction),&(gps_data->date),&(gps_data->mode));/*sscanf函数为从字符串输入,上面这句话的意思是将ptr内存单元的值作为输入分别输入到后面的结构体成员*/ return 0;} /* ----- End of gps_analyis() ----- *//************************************************************************************** * Description: * Input Args: * Output Args: * Return Value: *************************************************************************************/int print_gps (GPRMC *gps_data){ printf(" \n"); printf(" \n"); printf("===========================================================\n"); printf("== 全球GPS定位导航模块 ==\n"); printf("== 开发人员:李万能 ==\n"); printf("== 邮箱:liwjng@gmail.com.com ==\n"); printf("== 平台:fl2440 ==\n"); printf("== GPS型号:FIT-GPS_SF2820(代替ET-312) ==\n"); printf("===========================================================\n"); printf(" \n"); printf("===========================================================\n"); printf("== GPS状态位 : %c [A:有效状态 V:无效状态] \n",gps_data->pos_state); printf("== GPS模式位 : %c [A:自主定位 D:差分定位] \n", gps_data->mode); printf("== 日期 : 20%02d-%02d-%02d \n",gps_data->date%100,(gps_data->date%10000)/100,gps_data->date/10000); printf("== 时间 : %02d:%02d:%02d \n",(gps_data->time/10000+8)%24,(gps_data->time%10000)/100,gps_data->time%100); printf("== 纬度 : 北纬:%d度%d分%d秒 \n", ((int)gps_data->latitude) / 100, (int)(gps_data->latitude - ((int)gps_data->latitude / 100 * 100)), (int)(((gps_data->latitude - ((int)gps_data->latitude / 100 * 100)) - ((int)gps_data->latitude - ((int)gps_data->latitude / 100 * 100))) * 60.0)); printf("== 经度 : 东经:%d度%d分%d秒 \n", ((int)gps_data->longitude) / 100, (int)(gps_data->longitude - ((int)gps_data->longitude / 100 * 100)), (int)(((gps_data->longitude - ((int)gps_data->longitude / 100 * 100)) - ((int)gps_data->longitude - ((int)gps_data->longitude / 100 * 100))) * 60.0)); printf("== 航速 : %.3f \n",gps_data->speed); printf("== \n"); printf("============================================================\n"); return 0;} /* ----- End of printf_gps() ----- */
对于GPS数据的分析在文章的开头已经分析过了。这里需要注意的是相关数据的转换,GPS接收机直接返回的数据还不太适合我们的阅读习惯,所以我们需要按照一定的规则转换成方便我们识别的数据。
1. 时间,这个是格林威治时间即世界时间(UTC),把它转换成我们用的北京时间(BTC),在这个时间基础上加8个小时。 【14:51:58】
2. 经纬度,GPRMC返回的纬度数据位ddmm.mmmm格式即度分格式,我们把它转换成常见的度分秒的格式,计算方法:如接收到的纬度是:3029.65637、4546.40891
3029.65637/100=30可以直接读出30度, 3029.65637–30*100=29.40891, 可以直接读出29分
29.65637–29 =0.65637*60=39.3822读出39秒, 所以纬度是:30度29分39秒。
3. 南北纬东西经,N:北纬。S:南纬。E:东经。W:西经。
4. 速率,GPRMC返回的速率值是海里/时,单位是节,把它转换成千米/时,换算为:1海里=1.85公里,把得到的速率乘以1.85。
5. 航向,指的是偏离正北的角度
6. 日期,GPRMC的日期格式为:ddmmyy,如:290517表示2017年05月29日,这个日期是准确的,不需要转换
根据上面这些规则,在gps_print函数中我们将GPS接收机获得的数据转换成我们常见的格式并进行显示。
主函数gps_main.c
gps_main文件主要功能。
/********************************************************************************* * Copyright: (C) 2017 Li Wanneng<liwjng@gmail.com> * All rights reserved. * * Filename: gps_main.c * Description: This file * * Version: 1.0.0(05/29/2017) * Author: Li Wanneng <liwjng@gmail.com> * ChangeLog: 1, Release initial version on "05/29/2017 08:37:35 PM" * ********************************************************************************/#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"#define GPS_LEN 512 int set_serial(int fd,int nSpeed, int nBits, char nEvent, int nStop);int gps_analyse(char *buff,GPRMC *gps_date);int print_gps(GPRMC *gps_date);/******************************************************************************** * Description: * 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 failed.\n"); return -1; } set_serial( 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_analyse(gps_buff,&gprmc); print_gps(&gprmc); } close(fd); return 0;} /* ----- End of main() ----- */
主函数中实现的功能就比较简单就,依次为:
- 打开串口ttyUSB0
- 调用set_serial函数设置串口波特率
- 读取串口获取的值赋值给gps_buff
- 打印gps_buff的内容
调用gps_analyse函数和print_gps函数打印出获取到的GPS数据
下面贴上自己定义的gps.h
* Copyright: (C) 2017 Li Wanneng<liwjng@gmail.com> * All rights reserved. * * Filename: gps.h * Description: This head file * * Version: 1.0.0(05/29/2017) * Author: Li Wanneng <liwjng@gmail.com> * ChangeLog: 1, Release initial version on "05/29/2017 08:42:47 PM" * ********************************************************************************/#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_analyse(char *buff,GPRMC *gps_date);extern int print_gps(GPRMC *gps_date);extern int set_serial(int fd,int nSpeed, int nBits, char nEvent, int nStop);#endif
Makefile
由于涉及多个c文件,我们使用Makefile编译程序,下面是我的Makefile内容
CC =/opt/dl/buildroot-2012.08/ARM920t/usr/bin/arm-linux-gccobjs =set_ttyUSB0.o gps_analyse.o gps_main.osrcs =set_ttyUSB0.c gps_analyse.c gps_main.cgps_bin: $(objs) $(CC) -o gps_bin $(objs) @make cleangps_main.o: $(srcs) gps.h $(CC) -c $(srcs)set_ttyUSB0.o: set_ttyUSB0.c $(CC) -c set_ttyUSB0.canalyse_gps.o: analyse_gps.c gps.h $(CC) -c analyse_gps.cclear: @rm gps_bin.PHONY: cleanclean: @rm *.o
测试运行
将程序编译之后在开发板上运行,下面是运行结果。
- FL2440——基于安信可A7模块编程实现GPS定位功能
- FL2440-A7模块用程序实现GPS自动定位解析功能
- 安信可-A7模块——C语言编程实现GPS功能
- 安信可A7模块GPS-编程获取GPS定位信息
- 安信可A7模块GPS定位功能测试及解析
- 安信可A7模块GPS——编程获取GPS经纬度信息
- 安信可-A7模块——GPS显示坐标信息解读
- 安信可A7模块 GPRS/GPS使用教程
- 基于FL2440的GPS模块开发
- 安信可A7编程获取GPS信息
- 安信可A7模块实现拨号发短信
- Android实现GPS定位功能
- 基于STM32和GPS-NEO-6M模块实现GPS导航定位的
- fl2440模块学习——RT3070无线网卡SoftAP模式实现路由器功能
- 安信可 A7模块——GPRS之AT命令
- 安信可-A7模块——GPRS基本AT命令
- 安信可A7模块GPS数据解析与开发板模块连接
- fl2440模块学习——添加RT3070实现无线上网
- 简单的数据库 查询 增删改查 -----
- new String(bytes,offset,length,编码格式)
- Camera2时序图
- 基于对象的程序设计(OOP)
- leetcode 124. Binary Tree Maximum Path Sum
- FL2440——基于安信可A7模块编程实现GPS定位功能
- Win10上使用virtualbox5.1出现supR3HardenedWinReSpawn what:5报错
- hyperledger fabric 1.0交易流程理解
- submile编辑器常用快捷键
- 数据类型和抽象数据类型
- webpack+react+es6 嵌入已有项目
- mybatis动态sql中的trim标签的使用
- C++ Iterator迭代器介绍
- (ASP.NET)DataTable与Dataset的互相转换