GPS数据NEMA0183报文解析源码     DATE: 2019-03-20 08:42

GPS.H
#ifndef __GPS_H__
#define __GPS_H__

#include "common.h"

typedef struct
{
u8 UTCDateTime[6]; //YMDHMS
u8 Status; //A/V
u8 Latitude[9]; //ddmm.mmmm
u8 NS; //N/S
u8 Longitude[10]; //dddmm.mmmm
u8 EW; //E/W
u8 Speed[5]; //速率000.0~999.9节
u8 Course[5]; //航向000.0~359.9度
}stru_GPSRMC;

typedef struct
{
//    u8 UTCTime[10];    //hhmmss.mmm
//    u8 Latitude[9];    //ddmm.mmmm
//    u8 NS;        //N/S
//    u8 Longitude[10];    //dddmm.mmmm
//    u8 EW;        //E/W
    u8 PositionFix;    //0,1,2,6
    u8 SatUsed[2];    //00~12
//    u8 HDOP[4];        //0.5~99.9
    u8 Altitude[7];    //-9999.9~99999.9
}stru_GPSGGA;

typedef struct
{
    u8 Mode;        //A/M
    u8 Mode2;    //0,1,2,3
    u8 SatUsedList[12];   
    u8 PDOP[4];
    u8 HDOP[4];
    u8 VDOP[4];
}stru_GPSGSA;

typedef struct
{
u8 SatID;
//    u8 Elevation[2];//0-90 degree
//    u8 Azimuth[3]; //0-359 degree
u8 SNR; //0-99 dbHz
}stru_SatInfo;

typedef struct
{
    u8 SatInView;
    stru_SatInfo SatInfo[12];
}stru_GPSGSV;

#define NMEA_NULL    0x00            //GPS语句类型
#define NMEA_GPGGA    0x01
#define NMEA_GPGSA    0x02
#define NMEA_GPGSV    0x04
#define NMEA_GPRMC    0x08

void GPS(void);
void ShowLongitude(u8,u8);
void ShowLatitude(u8,u8);
void ShowGPSTime(u8,u8);
void GPSSateDataInit(void);
bit ReciveOK(void);
void ShowSatSNR(u8,u8);

#endif
GPS.C

//-------------------------------------------------------
//GPS 解析模块 By wowbanui
//版本历史:
//       2010/08 v0.1 初始版本
//       2011/03 v0.2 注释掉不需要的字段,部分数据直接处理成数值,
//               减少内存占用.输出部分直接调用LCD命令,移植需更改
//---------------------------------------------------------

#include "GPS.H"
#include "S1D15E06.h"

static u8 NMEA_CMD=NMEA_NULL;         //NMEA 语句
static u8 NMEA_CMD_Buff[]="$GPxxx,"; //NMEA 语句类型缓存
static u8 NMEA_CMD_Index=0;         //读取 CMD字符的个数
static bit NMEA_CMD_Parsered=0;        //CMD类型解析完毕
static u8 NMEA_DAT_Block=0;         //NMEA 数据字段号 从0开始
static u8 NMEA_DAT_BlockIndex=0;     //NMEA 数据每个字段内字符索引 从0开始
static bit NMEA_CMD_Start=0;         //NMEA 语句开始. 检测到 $ 时置1
static bit ReciveFlag=0;             //数据接收完成. 最后一条 GPRMC 语句发送完毕置1,

static u8 ucTempA=0;                 //存储解析两位数字用的的十位临时变量
static u8 SateInfoIndex=0;            //
//static u8 ucTemp[5];

stru_GPSRMC xdata GPS_RMC_Data;
stru_GPSGGA xdata GPS_GGA_Data;
stru_GPSGSA xdata GPS_GSA_Data;
stru_GPSGSV xdata GPS_GSV_Data;


void GPSSateDataInit(void)
{   
    u8 i;
    for(i=0;i<12;i++)
    {
        GPS_GSV_Data.SatInfo[i].SatID=0x00;
        GPS_GSA_Data.HDOP[0]=0x01;
        GPS_GSA_Data.HDOP[1]=0x01;
        GPS_GSA_Data.HDOP[2]=0x01;
        GPS_GSA_Data.HDOP[3]=0x01;
    }
}

void ShowGPSTime(u8 ucLX,u8 ucLY)
{
    GPS_RMC_Data.UTCDateTime[3]+=8;
    if (GPS_RMC_Data.UTCDateTime[3]>23)
    {
        GPS_RMC_Data.UTCDateTime[3]-=24; //Hour
        GPS_RMC_Data.UTCDateTime[2]++; //Day
        if (((GPS_RMC_Data.UTCDateTime[1]==1)||\
             (GPS_RMC_Data.UTCDateTime[1]==3)||\
             (GPS_RMC_Data.UTCDateTime[1]==5)||\
             (GPS_RMC_Data.UTCDateTime[1]==7)||\
             (GPS_RMC_Data.UTCDateTime[1]==8)||\
             (GPS_RMC_Data.UTCDateTime[1]==10)||\
             (GPS_RMC_Data.UTCDateTime[1]==12))&&\
             (GPS_RMC_Data.UTCDateTime[2]>31))
        {
            GPS_RMC_Data.UTCDateTime[2]=1;//Day
            GPS_RMC_Data.UTCDateTime[1]++;//Month
        }
        if (((GPS_RMC_Data.UTCDateTime[1]==4)||\
             (GPS_RMC_Data.UTCDateTime[1]==6)||\
             (GPS_RMC_Data.UTCDateTime[1]==9)||\
             (GPS_RMC_Data.UTCDateTime[1]==11))&&\
             (GPS_RMC_Data.UTCDateTime[2]>30))
        {
            GPS_RMC_Data.UTCDateTime[2]=1;
            GPS_RMC_Data.UTCDateTime[1]++;
        }
        if ((GPS_RMC_Data.UTCDateTime[1]==2)&&(GPS_RMC_Data.UTCDateTime[2]>28))
        {
            GPS_RMC_Data.UTCDateTime[2]=1;
            GPS_RMC_Data.UTCDateTime[1]++;
        }

        if(GPS_RMC_Data.UTCDateTime[1]>12)
        {
            GPS_RMC_Data.UTCDateTime[1]=1;
            GPS_RMC_Data.UTCDateTime[0]++;
        }
    }
    LCD_SetLocation(ucLX,ucLY);
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[0]/10+'0');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[0]%10+'0');
    LCD_PutChar('/');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[1]/10+'0');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[1]%10+'0');
    LCD_PutChar('/');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[2]/10+'0');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[2]%10+'0');
    LCD_PutChar(' ');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[3]/10+'0');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[3]%10+'0');
    LCD_PutChar(':');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[4]/10+'0');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[4]%10+'0');
    LCD_PutChar(':');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[5]/10+'0');
    LCD_PutChar(GPS_RMC_Data.UTCDateTime[5]%10+'0');
}


void ShowLatitude(u8 ucX,u8 ucY) // N dd'mm'ss.ssss
{
    unsigned long s;

    LCD_SetLocation(ucX,ucY);
    LCD_PutChar(GPS_RMC_Data.NS);             //北纬南纬标志
    LCD_PutChar(' ');
    LCD_PutChar(GPS_RMC_Data.Latitude[0]);     //度, 直接提取
    LCD_PutChar(GPS_RMC_Data.Latitude[1]);
    LCD_PutChar(0x02);                         //度(°)符号
    LCD_PutChar(GPS_RMC_Data.Latitude[2]);     //分, 直接提取
    LCD_PutChar(GPS_RMC_Data.Latitude[3]);

    //直接提取后四位分并扩大10000倍为整数存于Long型, 避免小数运算
    s=(GPS_RMC_Data.Latitude[5]-'0')*1000+\
        (GPS_RMC_Data.Latitude[6]-'0')*100+\
        (GPS_RMC_Data.Latitude[7]-'0')*10+\
        (GPS_RMC_Data.Latitude[8]-'0');

    s*=60;             //转换成单位 秒(")

    LCD_PutChar('\'');
    LCD_PutChar(s/100000+'0');
    s=s%100000;
    LCD_PutChar(s/10000+'0');
    s=s%10000;
    LCD_PutChar('.');
    LCD_PutChar(s/1000+'0');
    s=s%1000;
    LCD_PutChar(s/100+'0');
    s=s%100;
    LCD_PutChar(s/10+'0');
    s=s%10;
    LCD_PutChar(s+'0');
    LCD_PutChar('"');
}


void ShowLongitude(u8 ucX,u8 ucY)
{
    unsigned long s;

    LCD_SetLocation(ucX,ucY);
    LCD_PutChar(GPS_RMC_Data.EW);
    LCD_PutChar(GPS_RMC_Data.Longitude[0]);
    LCD_PutChar(GPS_RMC_Data.Longitude[1]);
    LCD_PutChar(GPS_RMC_Data.Longitude[2]);
    LCD_PutChar(0x02);
    LCD_PutChar(GPS_RMC_Data.Longitude[3]);
    LCD_PutChar(GPS_RMC_Data.Longitude[4]);
    s=(GPS_RMC_Data.Longitude[6]-'0')*1000+\
        (GPS_RMC_Data.Longitude[7]-'0')*100+\
        (GPS_RMC_Data.Longitude[8]-'0')*10+\
        (GPS_RMC_Data.Longitude[9]-'0');
    s*=60;
    LCD_PutChar('\'');
    LCD_PutChar(s/100000+'0');
    s=s%100000;
    LCD_PutChar(s/10000+'0');
    LCD_PutChar('.');
    s=s%10000;
    LCD_PutChar(s/1000+'0');
    s=s%1000;
    LCD_PutChar(s/100+'0');
    s=s%100;
    LCD_PutChar(s/10+'0');
    s=s%10;
    LCD_PutChar(s+'0');
    LCD_PutChar('"');
}


void ShowSatSNR(u8 ucX,u8 ucY)
{
    u8 i,j,Mode;
    for (i=0;i<12;i++)
    {
        Mode=1;
        for (j=0;j<12;j++)
        {
            if (GPS_GSV_Data.SatInfo[i].SatID==GPS_GSA_Data.SatUsedList[j]) Mode=3;
        }
        LCD_SNRBar(i*8,6,GPS_GSV_Data.SatInfo[i].SNR/4,Mode);
    }
}

bit ReciveOK(void)
{
    if (ReciveFlag)
    {
        ReciveFlag=0;
        return 1;
    }
    else
    {
        return 0;
    }
}

static void ParserGPGGA(void)
{
    switch(SBUF)
    {
        case '*': //语句结束
            NMEA_CMD_Start=0;
            break;
        case ',': //该字段结束
            NMEA_DAT_Block++;
            NMEA_DAT_BlockIndex=0;
            break;
        default:    //字段字符
            switch(NMEA_DAT_Block) //判断当前处于哪个字段
            {
               
                case 5:             //<6> GPS状态 0=未定位, 1=非差分定位, 2=差分定位, 6=正在估算
                    GPS_GGA_Data.PositionFix=SBUF;
                    break;
                case 6:             //<7> 正在使用的卫星数量 00~12
                    GPS_GGA_Data.SatUsed[NMEA_DAT_BlockIndex]=SBUF;
                    break;
               
                    case 8:         //<9> 海拔高度 -9999.9~99999.9
                    GPS_GGA_Data.Altitude[NMEA_DAT_BlockIndex]=SBUF;
                    break;
            }
            NMEA_DAT_BlockIndex++;     //字段字符索引++, 指向下一个字符
    }
}

static void ParserGPRMC(void)
{
    switch(SBUF)
    {
        case '*':
            NMEA_CMD_Start=0;
            ReciveFlag=1;     //接收完毕, 可以处理
            break;
        case ',':
            NMEA_DAT_Block++;
            NMEA_DAT_BlockIndex=0;
            break;
        default:
            switch(NMEA_DAT_Block)
            {
                case 0:         //<1> UTC时间 hhmmss.mmm
                    switch(NMEA_DAT_BlockIndex)
                    {
                        case 0:
                        case 2:
                        case 4:
                            ucTempA=SBUF-'0';
                            break;
                        case 1:
                            GPS_RMC_Data.UTCDateTime[3]=ucTempA*10+SBUF-'0';
                            break;
                        case 3:
                            GPS_RMC_Data.UTCDateTime[4]=ucTempA*10+SBUF-'0';
                            break;
                        case 5:
                            GPS_RMC_Data.UTCDateTime[5]=ucTempA*10+SBUF-'0';
                            break;
                    }
                    break;
                case 1:         //<2> 定位状态 A=有效定位, V=无效定位
                    GPS_RMC_Data.Status=SBUF;
                    break;
                case 2:         //<3> 纬度 ddmm.mmmm
                    GPS_RMC_Data.Latitude[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                case 3:         //<4> 纬度半球 N/S
                    GPS_RMC_Data.NS=SBUF;
                    break;
                case 4:         //<5> 经度 dddmm.mmmm
                    GPS_RMC_Data.Longitude[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                case 5:         //<6> 经度半球 E/W
                    GPS_RMC_Data.EW=SBUF;
                    break;
                case 6:         //<7> 地面速率 000.0~999.9 节
                    GPS_RMC_Data.Speed[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                case 7:         //<8> 地面航向 000.0~359.9 度, 以真北为参考基准
                    GPS_RMC_Data.Course[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                case 8:         //<9> UTC日期 ddmmyy
                    switch(NMEA_DAT_BlockIndex)
                    {
                        case 0:
                        case 2:
                        case 4:
                            ucTempA=SBUF-'0';
                            break;
                        case 1:
                            GPS_RMC_Data.UTCDateTime[2]=ucTempA*10+SBUF-'0';
                            break;
                        case 3:
                            GPS_RMC_Data.UTCDateTime[1]=ucTempA*10+SBUF-'0';
                            break;
                        case 5:
                            GPS_RMC_Data.UTCDateTime[0]=ucTempA*10+SBUF-'0';
                            break;
                    }
                    break;
            }
            NMEA_DAT_BlockIndex++;
    }
}

static void ParserGPGSA(void)
{
    switch(SBUF)
    {
        case '*':
            NMEA_CMD_Start=0;
            break;
        case ',':
            NMEA_DAT_Block++;
            NMEA_DAT_BlockIndex=0;
            //清空已使用卫星号, 避免上次数据干扰
            if((NMEA_DAT_Block>=2)||(NMEA_DAT_Block<=13))
                GPS_GSA_Data.SatUsedList[NMEA_DAT_Block-2]=0x00;
            break;
        default:
            switch(NMEA_DAT_Block)
            {
                case 0:         //<1>模式 M=手动, A=自动
                    GPS_GSA_Data.Mode=SBUF;
                    break;
                case 1:         //<2>定位型式 1=未定位, 2=二维定位, 3=三维定位
                    GPS_GSA_Data.Mode2=SBUF;
                    break;
                case 2:         //<3> PRN 01~32 使用中的卫星编号
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                    switch(NMEA_DAT_BlockIndex)
                    {
                        case 0:
                            ucTempA=SBUF-'0';
                            break;
                        case 1:
                            GPS_GSA_Data.SatUsedList[NMEA_DAT_Block-2]=ucTempA*10+SBUF-'0';
                            break;
                    }
                    break;
                case 14:        //<4> PDOP 位置精度因子 0.5~99.9
                    GPS_GSA_Data.PDOP[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                case 15:        //<5> HDOP 水平精度因子 0.5~99.9
                    GPS_GSA_Data.HDOP[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                case 16:        //<6> VDOP 垂直精度因子 0.5~99.9
                    GPS_GSA_Data.VDOP[NMEA_DAT_BlockIndex]=SBUF;
                    break;
                }
            NMEA_DAT_BlockIndex++;
    }
}

static void ParserGPGSV(void)
{
    switch(SBUF)
    {
        case '*':
            NMEA_CMD_Start=0;
            break;
        case ',':
            NMEA_DAT_Block++;
            NMEA_DAT_BlockIndex=0;
            break;
        default:
            switch(NMEA_DAT_Block)
            {
               
                case 1:         //<2> 本句GSV的编号
                    if (SBUF=='1') SateInfoIndex=0;
                    //解析到第一句 GSV 语句 则判断卫星信息从心开始
                    break;
                case 2:         //<3> 可见卫星的总数 00~12
                    switch(NMEA_DAT_BlockIndex)
                    {
                        case 0:
                            ucTempA=SBUF-'0';
                            break;
                        case 1:
                            GPS_GSV_Data.SatInView=ucTempA*10+SBUF-'0';
                            break;
                    }
                    break;
                case 3:         //<4> 卫星编号 01~32
                case 7:
                case 11:
                case 15:
                    switch(NMEA_DAT_BlockIndex)
                    {
                        case 0:
                            ucTempA=SBUF-'0';
                            break;
                        case 1:
                            GPS_GSV_Data.SatInfo[SateInfoIndex].SatID=ucTempA*10+SBUF-'0';

                            GPS_GSV_Data.SatInfo[SateInfoIndex].SNR=0x00;
                            //清空信噪比数据, 避免上次数据干扰
                            //因为当卫星信噪比无时GPS输出的NMEA数据中信噪比字段没有,
                            //而导致直接跳到下一字段, 此时上次若有数据则直接会残留下来

                            SateInfoIndex++;
                            //卫星信息索引+1, 以下都-1处理
                            //同上, 避免放于"信噪比"字段为空时处理不到

                            break;
                    }
                    break;
               
                case 6:         //<7>讯号噪声比 C/No 00~99
                case 10:
                case 14:
                case 18:
                    switch(NMEA_DAT_BlockIndex)
                    {
                        case 0:
                            ucTempA=SBUF-'0';
                            break;
                        case 1:
                            GPS_GSV_Data.SatInfo[SateInfoIndex-1].SNR=ucTempA*10+SBUF-'0';
                            break;
                    }
                    break;
             }
        NMEA_DAT_BlockIndex++;
    }
}

void GPS(void)
{
    LED_G=0;
    if(NMEA_CMD_Start)
    {             //解析到以$开始的 NMEA 语句, 进入NMEA 解析流程:
        if(NMEA_CMD_Parsered)
        {         //CMD语句类型解析完毕, 根据类型条用解析函数
            switch(NMEA_CMD)
            {
                case NMEA_GPGGA:
                    ParserGPGGA();
                    break;
                case NMEA_GPGSA:
                    ParserGPGSA();
                    break;
                case NMEA_GPGSV:
                    ParserGPGSV();
                    break;
                case NMEA_GPRMC:
                    ParserGPRMC();
                    break;
                default:    //无法识别的格式, 复位
                    NMEA_CMD=NMEA_NULL;
                    NMEA_CMD_Parsered=0;
                    NMEA_CMD_Index=1;
                    NMEA_CMD_Start=0;
            }
        }
        else
        {         //需要解析CMD语句类型
            switch(SBUF)
            {
                case ',':     //第一个字段结束
                    if(NMEA_CMD_Buff[4]=='G'&&NMEA_CMD_Buff[5]=='A') NMEA_CMD=NMEA_GPGGA;
                    if(NMEA_CMD_Buff[4]=='S'&&NMEA_CMD_Buff[5]=='A') NMEA_CMD=NMEA_GPGSA;
                    if(NMEA_CMD_Buff[5]=='V') NMEA_CMD=NMEA_GPGSV;
                    if(NMEA_CMD_Buff[5]=='C') NMEA_CMD=NMEA_GPRMC;
                    //此处如果都不成立, 即语句不被识别, 则NMEA_CMD为NULL或其他,
                    //则转为根据类型解析时会跳转到无法识别的格式, 而后复位
                    NMEA_CMD_Parsered=1;
                    NMEA_CMD_Index=1;
                    NMEA_DAT_Block=0;
                    NMEA_DAT_BlockIndex=0;
                    break;
                case '*':
                    NMEA_CMD_Start=0;
                    break;
                default:        //处于第一个字段中, 继续接收
                    NMEA_CMD_Buff[NMEA_CMD_Index]=SBUF;
                    NMEA_CMD_Index++;
                    if (NMEA_CMD_Index>6) NMEA_CMD_Start=0;
                    // CMD 超过6个字符, (数组越界, 导致死机)
                    // 则判断不是正常的CMD语句, 则略过此句.
            }
        }
    }
    else
    {             //未解析到$, 循环接收并判断 直到 $
        if (SBUF=='$')
        {         //接收到$, 下一个字符即为类型判断字符, 先进行相关变量初始化
            NMEA_CMD_Buff[0]=SBUF;
            NMEA_CMD_Start=1;     //下次调用则进入NMEA 解析流程:
            NMEA_CMD_Index=1;     //从头存放GPS类型字符到变量
            NMEA_CMD_Parsered=0;
            NMEA_CMD=NMEA_NULL;
            NMEA_DAT_Block=0;
            NMEA_DAT_BlockIndex=0;
        }
    }
    LED_G=1;
}

  上一篇:什么是GPS Week(GPS周)