FL2440-A7模块用程序实现GPS自动定位解析功能
来源:互联网 发布:天刀网络延迟高 编辑:程序博客网 时间:2024/05/16 06:14
**主机操作系统:Centos 6.7
交叉编译器版本:buildroot-2012.08
开发板平台: FL2440
Linux内核版本: linux-3.0
开发模块:A7模块GPS自动定位解析**
一、添加内核选项支持cp2102
因为我使用的是cp2102芯片USB转串口,要现在内核里面添加支持才能在开发板上开发使用。
make menuconfig Device Drivers-> [*]USB support -> [*]USB Serial Converter support [*]USB CP210x family of UART Bridge Controllers
make编译后把新内核下载到开发板上。
查看是否已经添加完成,插上cp2102打印如下信息:
可以看到名称为ttyUSB0,后面我们写程序也要从这里打开。
在之前我们在串口调试助手上用AT+GPS=1打开了A7模块的GPS功能,然后进行将A7模块上的U_TXD换接到GPS_TXD上,因为现在要接收GPS发来的数据信息。其他接线不变。(这里需要注意的是,因为模块有些问题,我需要在串口助手上打开GPS后才能在开发板上监听,如果模块挂掉了,那我需要再次在串口调试助手上打开。)
现在我们先来手动在开发板上测试能否接收数据
microcom -s 9600 dev/ttyUSB0
打印如下信息:
可以看到已经能接收位置数据了
接下来我们要开始编程实现GPS自动定位数据解析
二、设置串口
其中串口设置其实就相当于串口通信的协议,我们通过程序设置下面的内容
波特率:是为了两者信号流能同步, 数据位:是指又几位数据封装成一帧 结束位:是指以帧传输数据时,协定好结束位,便于提取有效数据 奇偶校验:检验数据的一种手段
这是我的串口配置程序:
/********************************************************************************* * Copyright: (C) 2017 fanmaolin<fanmaolinn@gmail.com> * All rights reserved. * * Filename: uart.c * Description: This file * * Version: 1.0.0(05/11/2017) * Author: fanmaolin <fanmaolinn@gmail.com> * ChangeLog: 1, Release initial version on "05/11/2017 12:35:00 AM" * ********************************************************************************/#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() ----- */
termios结构体:
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 */};
通过termio结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制
CBAUD:(不属于POSIX)波特率掩码 (4+1 位)。 CBAUDEX:(不属于POSIX)扩展的波特率掩码(1 位)包含在CBAUD中。 CSIZE:字符长度掩码。取值为CS5,CS6,CS7,或CS8。 CSTOPB:设置两个停止位而不是一个。 CREAD:打开接受者。 PARENB:允许输出产生奇偶信息以及输入的奇偶校验。 PARODD:输入和输出是奇校验。 CLOCAL:忽略 modem 控制线。
tcgetattr函数
tcgetattr函数原型为int tcgetattr(int fd, struct termios *termios_p);
用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios 结构体中。如果成功返回零;失败,返回非零。
三、GPS数据解析
在之前的文章中我分析过如何解析GPS的经纬度,现在用程序来解析
/********************************************************************************* * Copyright: (C) 2017 fanmaolin<fanmaolinn@gmail.com> * All rights reserved. * * Filename: ananlyse_gps.c * Description: This file * * Version: 1.0.0(05/11/2017) * Author: fanmaolin <fanmaolinn@gmail.com> * ChangeLog: 1, Release initial version on "05/11/2017 12:36:34 AM" * ********************************************************************************/#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("== 开发平台: 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() ----- */
这个函数就是用来将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; }
strstr函数之前的文章中特意讲解过了,获取IP的时候用到。
sscanf是第一次用到,在这里简单说明一下:
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”中
函数语法
int sscanf( const char *buffer, const char *format, [ argument ] ... ); 作用:读取格式化的字符串中的数据。 buffer存储的数据format窗体控件字符串。argument可选自变量locale要使用的区域设置
sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。
我们在这里将接收到的GPS的数据按照规定的格式输出。
四、主程序(main.c)
/********************************************************************************* * Copyright: (C) 2017 fanmaolin<fanmaolinn@gmail.com> * All rights reserved. * * Filename: gps_main.c * Description: This file * * Version: 1.0.0(05/11/2017) * Author: fanmaolin <fanmaolinn@gmail.com> * ChangeLog: 1, Release initial version on "05/11/2017 12:38:16 AM" * ********************************************************************************/#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 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_name,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。
主函数主要是调用之前写好的结构体来实现我们想实现的功能,可以看出主函数往往比较简洁。
打开串口ttyUSB0
调用set_serial函数设置串口波特率
读取串口获取的值赋值给gps_buff
打印gps_buff的内容
调用gps_analysis函数和print_gps函数打印出获取到的GPS数据
五、头文件(gps.h)
/******************************************************************************** * Copyright: (C) 2017 fanmaolin<fanmaolinn@gmail.com> * All rights reserved. * * Filename: gps.h * Description: This head file * * Version: 1.0.0(05/11/2017) * Author: fanmaolin <fanmaolinn@gmail.com> * ChangeLog: 1, Release initial version on "05/11/2017 12:39:28 AM" * ********************************************************************************/#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),方便函数能在其他程序中调用
六、编译运行
[fanmaolin@Centeros GPS]$ /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc *.c -o gps_test
如果之后需要经常修改也可以写一个Makefile来方便执行
CC=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gccobjs=set_uart.o analyse_gps.o gps_main.osrcs=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
生成gps_test可执行文件放到开发板下给权限777运行即可,在这时一定要保证A7模块工作正常
总结:
1、在这个过程中重点学习编程思想,怎么将一件具体的事(获取GPS自动解析)用程序执行,提升了工作效率。
2、学习使用一些函数如open、read、strstr、sscanf等等
3、学习串口配置uart.c
http://www.cnblogs.com/jason-lu/articles/3173988.html(串口配置)
- FL2440-A7模块用程序实现GPS自动定位解析功能
- FL2440——基于安信可A7模块编程实现GPS定位功能
- 安信可A7模块GPS定位功能测试及解析
- 安信可A7模块GPS-编程获取GPS定位信息
- 安信可-A7模块——C语言编程实现GPS功能
- Android实现GPS定位功能
- 安信可A7模块GPS数据解析与开发板模块连接
- 安信可A7模块 GPRS/GPS使用教程
- 通过FL2440开发板和SF2820模块获取和解析GPS信息
- 基于FL2440的GPS模块开发
- 安信可-A7模块——GPS显示坐标信息解读
- GPS定位功能
- GPS定位功能。GPS定位例子
- GPS定位因素解析
- 安信可A7模块实现拨号发短信
- 小程序GPS定位
- 微信小程序实现自动定位
- iOS应用后台运行GPS定位功能的实现
- 【小结】QEMU中的LIST
- Android自定义滑动Toast
- 点击链接打开新窗口,并展示一张图片
- MPAndroidChart的属性和方法
- Fast RCNN
- FL2440-A7模块用程序实现GPS自动定位解析功能
- HTTPS原理与应用
- Centos 6.9 配置 Tomcat 9 https
- FFmpeg中AVPacket和AVFrame关系
- eclipse运行程序报 DDMS files not found: D:\Java\SDK\tools\hprof-conv.exe
- Android 录音和播放录音
- 认证 (authentication) 和授权 (authorization) 的区别
- Android 技术重温系列 (15)- Canvas & Drawables
- linux内核编译