嵌入式之GPS

嵌入式系统上实现GPS全球定位功能

GPS(Global Positioning System)即全球定位系统,是由美国建立的一个卫星导航定位系统,利用该系统,用户可以在全球范围内实现全天候、连续、实时的三维导航定位和测速;另外,利用该系统,用户还能够进行高精度的时间传递和高精度的精密定位,通过GPS系统可以实现跟踪定位、防盗、里程统计、汽车导航、电子地图等等现实生活不可或缺的功能。本文着眼于在嵌入式linux系统上GPS功能的实现和研究。

1.1 GPS模块与ARM开发板的物理连接

GPS模块属于字符设备,只需要和FL2440开发板的第二个串口连接既可以,然后将GPS测试模块放在室外便可以每隔一段时间向开发板的串口发一个数据包。

~ >: microcom /dev/ttyS1 -s 4800

GPGGA,024907.000,3029.6642,N,11423.6203,E,1,10,1.0,35.7,M,-13.7,M,,0000*41GPGSA,A,3,04,08,32,17,28,30,07,11,20,01,,,1.9,1.0,1.7*3BGPRMC,024907.000,A,3029.6642,N,11423.6203,E,0.07,244.07,210914,,,A*67GPGGA,024908.000,3029.6643,N,11423.6202,E,1,10,1.0,35.3,M,-13.7,M,,0000*4AGPGSA,A,3,04,08,32,17,28,30,07,11,20,01,,,1.9,1.0,1.7*3BGPGSV,3,1,11,04,78,178,38,01,74,066,31,30,56,242,44,11,54,043,31*75GPGSV,3,2,11,28,47,328,27,07,40,194,40,08,31,177,47,17,29,277,27*74GPGSV,3,3,11,20,23,145,36,32,21,098,33,19,15,059,*4CGPRMC,024908.000,A,3029.6643,N,11423.6202,E,0.09,238.16,210914,,,A*6DGPGGA,024909.000,3029.6643,N,11423.6202,E,1,10,1.0,35.0,M,-13.7,M,,0000*48GPGSA,A,3,04,08,32,17,28,30,07,11,20,01,,,1.9,1.0,1.7*3BGPRMC,024909.000,A,3029.6643,N,11423.6202,E,0.07,251.95,210914,,,A*66

。。。

1.1 GPS数据解析

GPS数据如何理解呢?这一大串的数据到底代表了什么意思呢?要想编写GPS数据解析程序,肯定要知道这些数据代表什么,还要知道如何转换这些数据。以下给出一个博客链接详细地说明了GPS数据,这里不在做赘述:

http://www.cnblogs.com/csMapx/archive/2011/11/02/2232663.html

1.1 ARM+linux串口编程介绍

其实编写GPS数据解析程序就是ARM+linux串口编程,串口编程是嵌入式应用程序开发中最基础也是最重要的部分,如何从一个串口设备获取数据并将这些数据做一定的解析呢?OK,串口编程大致可以分为以下几个步骤:

至于串口编程的详细介绍,如何设置波特率,如何设置停止位等等,以下给出两个linux串口编程的博客链接,讲的很详细,不再赘述:

http://www.cnblogs.com/wblyuyang/archive/2011/11/21/2257544.html

http://blog.csdn.net/mtv0312/article/details/6599162

1.4 编写一个简单的GPS数据解析程序

这个程序比较简单,只是一个测试GPS数据的程序,GPS数据当中的GPRMC数据就可以用来做导航信息用了,包含了经度、纬度、日期时间等等!如果你们想做一个比较完善的GPS数据解析程序,可以在我的基础上进行修改,比如加上GPS数据出错处理、GPS数据超时处理等等!

OK,我先说一下我的代码包含以下这几个文件:gps_test.c gps_analysis.c set_com.c gpsd.h主函数在gps_test.c文件中,gps_analysis.c主要是GPS数据解析函数设计,set_com.c主要是设置GPS串口设备函数设计,gpsd.h是头文件!

1.4.1 编写gps_test.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 "gpsd.h"
#define GPS_LEN 512         /* GPS数据长度宏定义 */
int main (int argc, char **argv)
{
    int fd = 0;
    int nread = 0;
    GPRMC gprmc;
    //GPRMC *gprmc;
    char gps_buff[GPS_LEN];
    char *dev_name = "/dev/ttyS1";
    fd = open_com(dev_name);
    set_opt(fd,4800,8,'N',1);
    while(1)
    {
        sleep(2);  //注意这个时间的设置,设置不恰好的话,会导致GPS数据读取不完成,数据解析出错误
        nread = read(fd,gps_buff,sizeof(gps_buff));
        //printf("gps_buff: %s", gps_buff);
        memset(&gprmc, 0 , sizeof(gprmc));
        gprmc_analysis(gps_buff, &gprmc);
        if(nread > 0)
        {
printf("===========  GPS全球定位模块  ==============\n");
printf("==            开发者:韦书胜                  ==\n");
printf("==            版本:  1.0.0                    ==\n");
printf("===========================================\n");
printf("===========================================\n");
printf("= GPS状态位 : %c  [A:有效状态 V:无效状态]=\n" ,gprmc.pos_state);
printf("= GPS模式位 : %c  [A:自主定位 D:差分定位]=\n" , gprmc.mode);
printf("=日期 : 20%02d-%02d-%02d=\n", gprmc.date%100, (gprmc.date%10000)/100,
  gprmc.date/10000);
printf("=时间 : %02d:%02d:%02d=\n",(gprmc.time/10000+8)%24,(gprmc.time%10000)/100,
gprmc.time%100);
printf("=纬度 : 北纬:%.3f=\n",(gprmc.latitude/100));
printf("=经度 : 东经:%.3f=\n",(gprmc.longitude/100));
printf("=速度 : %.3f =\n",gprmc.speed);
printf("===========================================\n");
          }
}
close(fd);
    return 0;
} /* ----- End of main() ----- */

1.4.2 编写gps_analysis.c GPS数据解析函数

/*********************************************************************************
 *      Copyright:  (C) 2014 lingyun
 *                  All rights reserved.
 *
 *       Filename:  gps_analysis.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(2014年09月09日)
 *         Author:  skyyang <790549341@qq.com>
 *      ChangeLog:  1, Release initial version on "2014年09月09日 04时21分53秒"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "gpsd.h"
int gprmc_analysis (char *buff,GPRMC *gprmc)
{
char *ptr = NULL;
    if(gprmc == 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*",\
            &(gprmc->time),&(gprmc->pos_state),&(gprmc->latitude),&(gprmc->longitude),&(gprmc->speed),&(gprmc->direction),&(gprmc->date),&(gprmc->mode));
return 0;
} /*  ----- End of gprmc_analysis()  ----- */
//strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。
//sscanf() 从一个字符串中读进与指定格式相符的数据。
/*
例子:
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char **argv) 
{ 
int ret; 
char *string; 
int digit; 
char buf1[255]; 
char buf2[255]; 

string = "china beijing 123"; 
ret = sscanf(string, "%s %s %d", buf1, buf2, &digit); 
printf("1.string=%s\n", string); 
printf("1.ret=%d, buf1=%s, buf2=%s, digit=%d\n\n", ret, buf1, buf2, digit);
return 0;
} 
执行结果: 
1.ret=3, buf1=china, buf2=beijing, digit=123 
可以看出,sscanf的返回值是读取的参数个数 
*/

1.4.3 编写set_com.c GPS串口设备配置函数

/*********************************************************************************
 *      Copyright:  (C) 2014 
 *                  All rights reserved.
 *
 *       Filename:  set_com.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(2014年09月09日)
 *         Author:  
 *      ChangeLog:  1, Release initial version on "2014年09月09日 04时15分06秒"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <stdlib.h>
#include "gpsd.h"
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if( tcgetattr( fd,&oldtio)  !=  0)
    {
        perror("SetupSerial 1");
        return -1;
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    switch( nBits )
    {
        case 7:
            newtio.c_cflag |= CS7;
            break;
        case 8:
            newtio.c_cflag |= CS8;
            break;
    }
    switch( nEvent )
    {
        case 'O':                     //奇校验        
            newtio.c_cflag |= PARENB;
            newtio.c_cflag |= PARODD;
            newtio.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'E':                     //偶校验        
            newtio.c_iflag |= (INPCK | ISTRIP);
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            break;
        case 'N':
            newtio.c_cflag &= ~PARENB;
            break;
}
switch( nSpeed )
    {
        case 2400:
            cfsetispeed(&newtio, B2400);
            cfsetospeed(&newtio, B2400);
            break;
        case 4800:
            cfsetispeed(&newtio, B4800);
            cfsetospeed(&newtio, B4800);
            break;
        case 9600:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
            break;
        default:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
    }
    if( nStop == 1 )
    {
        newtio.c_cflag &=  ~CSTOPB;
    }
    else if ( nStop == 2 )
    {
        newtio.c_cflag |=  CSTOPB;
    }
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("com set error");
        return -1;
    }   
    return 0;
}
int open_com(char *device_name)
{
    int fd = 0;
    if (0 > (fd = open(device_name, O_RDWR|O_NOCTTY|O_NDELAY))) //要设置非阻塞模式打开设备否则会出错!
    {
        perror("Open Comport Fail:");
        return 0;
    }
    return fd;
}/*  ----- End of open_com()  ----- */

1.4.4 编写gpsd.h头文件

#ifndef __GPSD_H__
#define __GPSD_H__
typedef unsigned int UINT;    //add by wei
typedef int BYTE;             //add by wei 
typedef long int WORD;        //add by wei
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 open_com(char *device_name);
extern int gprmc_analysis(char *buff,GPRMC *gprmc);
extern int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);
#endif

1.5 编译下载GPS数据解析程序到开发板上

1.交叉编译器编译GPS数据解析程序,这里最好自己写一个makefile

[weishusheng@localhost gps_yang]$ ls
gps_analysis.c  gpsd.h  gps_test  gps_test.c  makefile  set_com.c  version.h
[weishusheng@localhost gps_yang]$ /opt/buildroot-2011.11/arm920t/usr/bin/arm-linux-gcc set_com.c gps_test.c gps_analysis.c -o gps_wei_test
[weishusheng@localhost gps_yang]$ ls
gps_analysis.c gpsd.h gps_test.c gps_wei_test set_com.c

生成gps_wei_test

2.在开发板上直接运行gps_test可执行程序,便可以获取解析后的GPS数据了:

/fl2440/gps >: ./gps_wei_test 
gps infomation :8,53,332,24,30,52,231,43*77GPGSV,3,2,12,11,47,043,15,07,33,192,48,17,32,284,34,20,28,140,14*7CGPGSV,3,3,12,08,24,176,47,32,23,091,13,19,11,064,22,06,03,218,24*7FGPRMC,030323.000,A,3029.6405,N,11423.6222,E,0.34,332.13,210914,,,A*69GPGGA,030324.000,3029.6408,N,11423.6220,E,1,09,1.0,106.1,M,-13.7,M,,0000*7DGPGSA,A,3,04,08,28,30,07,17,01,11,19,,,,1.8,1.0,1.5*33GPRMC,030324.000,A,3029.6408,N,11423.6220,E,0.29,346.94,210914,,,A*61GPGGA,030325.000,3029.6410,N,11423.6218,E,1,09,1.0,105.2,M,-13.7,M,,0000*7EGPGSA,A,3,04,08,28,30,07,17,01,11,19,,,,1.8,1.0,1.5*33GPRMC,030325.000,A,3029.6410,N,11423.6218,E,0.28,315.50,210914,,,A*6DGPGGA,030326.000,3029.6412,N,11423.6216,E,1,09,1.0,104.5,M,-13.7,M,,0000*77GPGSA,A,3,04,08,28,30,07,17,01,11,19,,,,1.8,1.0,1.5*33GPRMC,030326.000,A,3029.6412,N,11423.621=========== GPS全球定位模块 ================ 开发者:weishusheng ==== 版本: 1.0.0 ==============================================
============================================
= GPS状态位 : A [A:有效状态 V:无效状态]=
日期 : 2014-09-21
时间 : 11:03:23
纬度 : 北纬:30.296
经度 : 东经:114.236
速度 : 0.340

到此,我们的GPS定位成功!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 常见的蓝牙耳机的音频编码

    蓝牙耳机设备在工作时,前端会先依托 PCM 将音频信号先量化成数字信号,接着按照不同的蓝牙音频编码压缩打包数据,再调制到特定的频率上发射。接收端...

    心跳包
  • C语言字符串指针

    运行结果: http://c.biancheng.net http://c.biancheng.net 字符数组归根结底还是一个数组,上节讲到的关于指针...

    心跳包
  • pthread_attr_init线程属性

    线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。我们用pthread_attr...

    心跳包
  • 一天一个设计模式:单例模式

    作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例。

    用户1134788
  • Head First设计模式——单例模式

    单例模式是所有设计模式中最简单的模式,也是我们平常经常用到的,单例模式通常被我们应用于线程池、缓存操作、队列操作等等。

    SpringSun
  • python:常见函数查询

    函数名: lstrip(),rstrip() 函数说明: 删除字符串开头(末尾)指定指定字符串

    用户4492257
  • 灭霸所有单例模式,克隆、序列化、反射机制破坏7种单例模式

    单例模式实际上也不止 7 种。但是,每一种都并非安全的。今天我给大家讲一讲如何利用克隆、序列化、反射机制破坏单例模式。

    业余草
  • 『开发技巧』Python音频操作工具PyAudio上手教程

    当需要使用Python处理音频数据时,使用python读取与播放声音必不可少,下面介绍一个好用的处理音频PyAudio工具包。

    小宋是呢
  • 开门人和关门人

    题目描述 每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签到、签离记录,请根据记录找出当天开门和关门的人。 输入...

    AI那点小事
  • C# 文件操作系列一

    在.Net环境中,所有关于文件操作的类都在System.IO命名空间下,注:在修改文件时,安全性显得格外重要,但是本随笔不过多讲述安全性,这里假设我们有足够的权...

    郑小超.

扫码关注云+社区

领取腾讯云代金券