天天看點

arm9+linux fl2440 GPS 資料采集和處理

=======================================================================

                                           主機作業系統:centos 6.7

                                           交叉編譯器版本:arm-linux-gcc-4.5.4

                                           開發闆平台:fl2440

                                            linux核心版本:Linux-3.0

                                            Author:  shaocongshuai <[email protected]>

=======================================================================

GPS簡介:

       GPS是英文Global Positioning System(全球定位系統)的簡稱。GPS起始于1958年美國軍方的一個項目,1964年投入使用。20世紀70年代,美國陸海空三軍聯合研制了新一代衛星定位系統GPS 。主要目的是為陸海空三大領域提供實時、全天候和全球性的導航服務,并用于情報搜集、核爆監測和應急通訊等一些軍事目的,經過20餘年的研究實驗,耗資300億美元,到1994年,全球覆寫率高達98%的24顆GPS衛星星座己布設完成。在機械領域GPS則有另外一種含義:産品幾何技術規範(Geometrical Product Specifications, 簡稱GPS)。另外一種含義為G/s(GB per second)。GPS(Generalized Processor Sharing)廣義為處理器分享,網絡服務品質控制中的專用術語。

       于GPS,序列槽都是字元裝置,難道就不需要再在linux核心中使能驅動嗎?是這樣的,在一開始核心中就已經對序列槽驅動進行了使能,而GPS子產品中有GPS子產品的驅動,這個子產品通過自身的序列槽不斷的發送資料開發闆需要做的就是讀取然後處理就夠了。

一:GPS與開發闆的連結

fl2440開發闆有兩個序列槽ttys0和ttys1,其中ttys0用來連接配接電腦終端,則ttys1連接配接GPS子產品的序列槽,linux中的序列槽裝置檔案放于/de/目錄下,序列槽一,序列槽二分别為”/dev/ttyS0”,”/dev/ttyS1”.在linux下操作序列槽與操作檔案相同.

GPS子產品接上電,監聽序列槽了發回的資料包

~ >: microcom /dev/ttyS1 -s 4800

 $GPGSV,3,2,11,27,31,041,,30,30,316,,09,21,230,37,16,19,083,*75

$GPGSV,3,3,11,23,11,199,30,28,07,291,,22,00,151,*48

$GPRMC,092047.000,A,3026.3016,N,11415.4829,E,1.90,13.28,200416,,,A*53

$GPGGA,092048.000,3026.3025,N,11415.4832,E,1,05,2.5,56.1,M,-14.4,M,,0000*49

$GPGSA,A,3,09,23,01,08,11,,,,,,,,4.1,2.5,3.3*31

$GPRMC,092048.000,A,3026.3025,N,11415.4832,E,1.78,11.99,200416,,,A*58

$GPGGA,092049.000,3026.3027,N,11415.4832,E,1,05,2.5,55.9,M,-14.4,M,,0000*41

$GPGSA,A,3,09,23,01,08,11,,,,,,,,4.1,2.5,3.3*31

$GPRMC,092049.000,A,3026.3027,N,11415.4832,E,1.28,13.39,200416,,,A*56

$GPGGA,092050.000,3026.3029,N,11415.4833,E,1,05,2.5,55.7,M,-14.4,M,,0000*48

$GPGSA,A,3,09,23,01,08,11,,,,,,,,4.1,2.5,3.3*31

$GPRMC,092050.000,A,3026.3029,N,11415.4833,E,1.81,14.25,200416,,,A*58

$GPGGA,092051.000,3026.3039,N,11415.4837,E,1,05,2.5,54.7,M,-14.4,M,,0000*4D

$GPGSA,A,3,09,23,01,08,11,,,,,,,,4.1,2.5,3.3*31

$GPRMC,092051.000,A,3026.3039,N,11415.4837,E,2.74,13.72,200416,,,A*50

-s      Set serial line to SPEED

二、arm+Linux 序列槽程式設計
至于序列槽程式設計的詳細介紹,如何設定波特率,如何設定停止位等等,以下給出兩個linux序列槽程式設計的部落格連結,講的很詳細,不再贅述:
http://www.cnblogs.com/wblyuyang/archive/2011/11/21/2257544.html
http://my.oschina.net/u/137617/blog/27762

gps_ttyS1.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>

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;

}

三、GPS資料解析

NMEA是National Marine Electronics Association(美國國家海事電子協會)的縮寫。NMEA-0183協定是目前GPS接收機上使用最廣泛的協定,大多數常見的GPS接收機、GPS資料處理軟體、導航軟體都遵守或者至少相容這個協定。

NMEA-0183協定定義的語句非常多,但是常用的或者說相容性最廣的語句

隻有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等,名稱如下:

(1)   Global Positioning System FixData(GGA)GPS定位資訊

(2)   GPS DOP and Active Satellites(GSA)目前衛星資訊

(3)   GPS Satellites in View(GSV)可見衛星資訊

(4)   Recommended Minimum SpecificGPS/TRANSIT Data(RMC)推薦定位資訊

(5)   Track Made Good and GroundSpeed(VTG)地面速度資訊

(6)   Geographic Position(GLL)定位地理資訊

3、    本程式主要通過GPS裝置獲得經度、緯度和高度,隻需對該語句$GPGGA進行解析,

該語句所具有的文法為:

$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh

<1> UTC時間,hhmmss(時分秒)格式

<2> 緯度ddmm.mmmm(度分)格式(前面的0也将被傳輸)

<3> 緯度半球N(北半球)或S(南半球)

<4> 經度dddmm.mmmm(度分)格式(前面的0也将被傳輸)

<5> 經度半球E(東經)或W(西經)

<6> GPS狀态:0=未定位,1=非差分定位,2=差分定位,6=正在估算

<7> 正在使用解算位置的衛星數量(00~12)(前面的0也将被傳輸)

<8> HDOP水準精度因子(0.5~99.9)

<9> 海拔高度(-9999.9~99999.9)

<10> 地球橢球面相對大地水準面的高度

<11> 差分時間(從最近一次接收到差分信号開始的秒數,如果不是差分定位将為空

<12> 差分站ID号0000~1023(前面的0也将被傳輸,如果不是差分定位将為空)

gps_analysis.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 ( NULL == gps_date )

    {

        return -1;

    }

    if ( strlen(buff) < 10 )

    {

        return -2;

    }

    if ( NULL==(ptr=strstr(buff, "$GPRMC")) )

    {

        return -3;

    }

    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;

}

int print_gps(GPRMC *gps_date)

{

    printf("===========================================================\n");

    printf("==                   the GPS module                      ==\n");

    printf("==              Author:shaocongshuai                           ==\n");

    printf("==              email:[email protected]                  ==\n");

    printf("==              stage:fl2440                             ==\n");

    printf("===========================================================\n");

    printf("==   GPS state bit : %c               \n",gps_date->pos_state);

   printf("==   GPS way bit : %c               \n", gps_date->mode);

   printf("==   date : 20%02d-%02d-%02d                             \n",gps_date->date%100,(gps_date->date%10000)/100,gps_date->date/10000);

   printf("==   time : %02d:%02d:%02d                               \n",(gps_date->time/10000+8)%24,(gps_date->time%10000)/100,gps_date->time%100);

   printf("==   latitude : N:%.3f                                    \n",(gps_date->latitude/100));

   printf("==   longitude : E:%.3f                                    \n",(gps_date->longitude/100));

   printf("==   speed : %.3f                                         \n",gps_date->speed);

   printf("==                                                       \n");

   printf("===========================================================\n");

   return 0;

}

gps_main.c檔案測試

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <string.h>

#include <errno.h>

#include <stdlib.h>

#include <termios.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);

int main (int argc, char **argv)

{

    int     fd = 0;

    int     nread = 0;

    GPRMC   gprmc;

    char    gps_buff[GPS_LEN];

    char    *dev_name = "/dev/ttyS1";

    fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY);

    if ( fd < 0 )

    {

        printf ("open ttyS1 error.\n");

        return -1;

    }

    set_opt(fd, 4800, 8, 'N', 1);

    while ( 1 )

    {

        sleep(2);

        nread = read(fd, gps_buff, sizeof(gps_buff));

        if ( nread < 0 )

        {

            printf ("read GPS data error.\n");

            return -2;

        }

        printf ("gps_buff: %s\n", gps_buff);

        memset(&gprmc, 0, sizeof(gprmc));

        gps_analysis(gps_buff, &gprmc);

        print_gps(&gprmc);

    }

    return 0;

}

gps.h檔案代碼

#ifndef __GPS_H__

#define __GPS_H__

typedef long int  LI;

typedef struct  gprmc

{

    int     time; //格林威治時間

    char    pos_state; //定位狀态

    float   latitude; //緯度

    float   longitude; //經度

    float   speed; //移動速度

    float   direction; //方向

    int     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_port(int    fd, int nSpeed, int nBits, char nEvent, int nStop);

#endif

[[email protected] GPS]$ /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc gps_analysis.c gps_main.c gps_ttyS1.c -o gps

[[email protected] GPS]$ ls

gps  gps_analysis.c  gps.h  gps_main.c  gps_ttyS1.c

将上圖gps燒錄到開發闆後,記得更改可執行權限

~ >: tftp -gr gps 192.168.1.93

gps                  100% |*******************************| 13187   0:00:00 ETA

~ >: chmod 777 gps

~ >: ./gps

gps_buff:

$GPGGA,130533.000,3026.3040,N,11415.4593,E,1,03,3.3,4.1,M,-14.4,M,,0000*7A

$GPGSA,A,2,17,06,30,,,,,,,,,,3.4,3.3,1.0*36

$GPRMC,130533.000,A,3026.3040,N,11415.4593,E,0.33,240.13,200416,,,A*67

$GPGGA,130534.000,3026.3043,N,11415.4597,E,1,03,3.3,4.4,M,-14.4,M,,0000*7F

$GPGSA,A,2,17,06,30,,,,,,,,,,3.4,3.3,1.0*36

$GPRMC,130534.000,A,3026.3043,N,11415.4597,E,0.08,168.18,200416,,,A*6D

$GPGGA,130535.000,3026.3047,N,11415.4602,E,1,03,3.3,4.6,M,-14.4,532.000,A,3026.3039,N,11415.4594,E,0.97,230.40,200416,,,A*60

===========================================================

==                   the GPS module                      ==

==              Author:shaocongshuai                           ==

==              email:[email protected]                  ==

==              stage:fl2440                             ==

===========================================================

==   GPS state bit : A               

==   GPS way bit : A               

==   date : 2016-04-20                             

==   time : 21:05:33                               

==   latitude : N:30.263                                    

==   longitude : E:114.155                                    

==   speed : 0.330                                         

==                                                       

===========================================================