FL2440-A7模块用程序实现GPS自动定位解析功能

本文介绍了在Centos 6.7系统上,使用buildroot-2012.08交叉编译器,针对FL2440开发板和A7模块,实现GPS自动定位数据解析的全过程。内容包括内核选项支持cp2102,设置串口,解析GPS数据,编写主程序,以及利用strstr和sscanf等函数处理GPS信息。通过这个过程,学习了编程思想和提高工作效率的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

**主机操作系统: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 

添加USB支持
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-gcc

objs=set_uart.o analyse_gps.o gps_main.o
srcs=set_uart.c analyse_gps.c gps_main.c

gps_test: $(objs)
    $(CC) -o gps_test $(objs)
    @make clean

gps_main.o: $(srcs) gps.h
    $(CC) -c  $(srcs) 

set_uart.o:  set_uart.c
    $(CC) -c  set_uart.c

analyse_gps.o: analyse_gps.c gps.h
    $(CC) -c  analyse_gps.c

clean:  
    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(串口配置)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值