打印
[STM32F3]

STM32F303-如何解析GPS数据

[复制链接]
2683|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Bermanrep|  楼主 | 2016-1-31 16:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
实现步骤如下:
1.初始化usart3:
#define UART3_TX_BUF_SIZE        1*128
#define UART3_RX_BUF_SIZE        512
unsigned char Uart1TxBuf[UART1_TX_BUF_SIZE]={0};                /* com1_rf发送缓冲区 */
unsigned char Uart1RxBuf[UART1_RX_BUF_SIZE]={0};                /* com1_rf接收缓冲区 */

unsigned char Uart3TxBuf[UART3_TX_BUF_SIZE]={0};                /* com3_发送缓冲区 */
unsigned char Uart3RxBuf[UART3_RX_BUF_SIZE]={0};                /* com3_接收缓冲区 */

bool Uart1RxBuf_full =false;
bool Uart3RxBuf_full =false;
void USART3_Init(u32 Baudrate)
{

  USART_InitTypeDef  USART_InitStructure;
  GPIO_InitTypeDef   GPIO_InitStructure;
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
  
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);
  
  //这里USART3映射到PC10和PC11是部分映射,没有映射时时端口是PB10和PB11,
  //完全映射时(GPIO_FullRemap_USART3)是PD8和PD9 (但是64引脚没有引出PD8和PD9)
  GPIO_PinRemapConfig(GPIO_PartialRemap_USART3,ENABLE);// I/O口重映射开启.
     
  /*Remap Pc10 USART3.TX推挽输出*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  
  /*remap Pc11 USART3.RX浮空输入 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  USART_InitStructure.USART_BaudRate = Baudrate;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART3, &USART_InitStructure);
  
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//接收中断使能
  USART_Cmd(USART3, ENABLE);

}


沙发
Bermanrep|  楼主 | 2016-1-31 16:04 | 只看该作者
2.写带fifo缓冲区的串口中断:
void  USART3_IRQHandler(void)
{
    static u16 RxCount;
     
  if(USART_GetFlagStatus(USART3,USART_IT_RXNE)==SET)
  {   
    USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清除中断标志

        
     Uart3RxBuf[RxCount] = USART_ReceiveData(USART3);         

       RxCount++; // must not change it !
           
      if (RxCount >= UART3_RX_BUF_SIZE) //  
       {     
         RxCount=0;
         Uart3RxBuf_full = true;
       }           
  }
}
3.从缓冲区中提取有效数据:
/*
*********************************************************************************************************
*        函 数 名: gps_pro
*        功能说明:  从串口缓冲区中解析出GPS数据包。插入到主程序中执行即可。分析结果存放在全局变量 myGPS
*        形    参:  无
*        返 回 值: 无
*********************************************************************************************************
*/

void gps_pro(void)
{
    uint16_t i=0;
        
    char *p,*pt;  

                if (Uart3RxBuf_full)
                   {  

                    USART_ITConfig(USART3, USART_IT_RXNE, DISABLE); //禁止接收中断
                    
                    Uart3RxBuf_full = false;
                  
                //LCD_print_0816Num(3, 5,  1 ,0);//debug

                    p = (char *)Uart3RxBuf;
                    pt = strchr(p, '
4. 解析语义:
[code]void GPS_Data_update()
{
   
    char * start_p = GpsBuf;      

    char *pos_p;
   /*
   int strncmp(const char *string1, const char *string2, size_t count);
   比较字符串string1和string2大小,只比较前面count个字符. 比较过程中,
   任何一个字符串的长度小于count, 则count将被较短的字符串的长度取代.
   此时如果两串前面的字符都相等, 则较短的串要小.
   返回值< 0, 表示string1的子串小于string2的子串;
   返回值为0, 表示string1的子串等于string2的子串;
   返回值> 0, 表示string1的子串大于string2的子串.
   */
  if(strncmp(GpsBuf, "$GPGGA",6)==0)
  {
   //ShowStringPos (0, 4,"$GPGGA"); //bebug
   
        /*字段1 :UTC 时间,hhmmss.sss,时分秒格式 */
        pos_p = strchr(start_p, ','); //查找字符串s中首次出现字符c的位置,剥离c前面的信息
        if (pos_p == 0)
        {
            return;//2个逗号连在一起的情况
        }
    pos_p++;  // p+1后指向UTC时间
    myGPS.Hour = StrToIntFix(pos_p, 2);
        pos_p += 2;
        myGPS.Min = StrToIntFix(pos_p, 2);
        pos_p += 2;
        myGPS.Sec = StrToIntFix(pos_p, 2);
         //微秒忽略
        
     /* 字段2 :纬度ddmm.mmmm,度分格式(前导位数不足则补0)*/
     pos_p = strchr(pos_p, ','); //接着刚才指针位置找下一个逗号
        if (pos_p == 0)
        {
           return;
        }
        pos_p++;
        
        myGPS.WeiDu_Du = StrToIntFix(pos_p, 2);
        pos_p += 2;
        myGPS.WeiDu_Fen = StrToIntFix(pos_p, 2) * 10000;
        pos_p += 3;
        myGPS.WeiDu_Fen += StrToIntFix(pos_p, 4);
            
        /* 字段3 :N(北纬)或S(南纬) */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        if (*pos_p == 'S')
        {
                myGPS.NS = 'S';
        }
        else if (*pos_p == 'N')
        {
                myGPS.NS = 'N';
        }
        else
        {
                return;
        }
        
    /* 字段4 :经度dddmm.mmmm,度分格式(前导位数不足则补0) */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        myGPS.JingDu_Du = StrToIntFix(pos_p, 3);
        pos_p += 3;
        myGPS.JingDu_Fen = StrToIntFix(pos_p, 2) * 10000;
        pos_p += 3;
        myGPS.JingDu_Fen += StrToIntFix(pos_p, 4);
        
        /* 字段5 :E(东经)或W(西经) */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        if (*pos_p == 'E')
        {
                myGPS.EW = 'E';
        }
        else if (*pos_p == 'W')
        {
                myGPS.EW = 'W';
        }
        
        /* 字段6 :GPS状态,0=未定位,1=非差分定位,2=差分定位,3=无效PPS,6=正在估算 */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        if ((*pos_p == '1') || (*pos_p == '2'))
        {
                myGPS.PositionOk = 1;
        }
        else
        {
                myGPS.PositionOk = 0;
        }

        
          /* 字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0) */
                pos_p = strchr(pos_p, ',');
                if (pos_p == 0)
                {
                        return;
                }
                pos_p++;
                myGPS.ViewNumber = StrToInt(pos_p);
               
                //p += 2;
        
                /* 字段8:HDOP水平精度因子(0.5 - 99.9) */
                pos_p = strchr(pos_p, ',');
                if (pos_p == 0)
                {
                        return;
                }
                pos_p++;
                myGPS.HDOP = StrToInt(pos_p);
        
                /* 字段9:海拔高度(-9999.9 - 99999.9) */
                pos_p= strchr(pos_p, ',');
                if (pos_p == 0)
                {
                        return;
                }
                pos_p++;
                myGPS.Altitude = StrToInt(pos_p);
        //后面的,39.5,M,-15.5,M,6.8,0000*68 丢弃
        
   
  }
  
  //if(strncmp(GpsBuf, "$GPRMC",6)==0)
  //{
   //ShowStringPos (0, 4,"$GPRMC"); //bebug
  //}
  
}


使用特权

评论回复
板凳
Bermanrep|  楼主 | 2016-1-31 16:05 | 只看该作者
5.运行:
在RTOS中用一个或两个任务执行   gps_pro(); GPS_Data_update();
在main函数中用while(1){gps_pro(); GPS_Data_update();}

); //P指向了该位置,在字符串中查找字符$第一次出现的位置
                    for(i=0;i<GPS_BUFF_SIZE;i++)
                    {
                      GpsBuf = Uart3RxBuf[pt-p+i];  //以$开头的字符串                                       
                    }         
                 
                printf("%s\r\n",GpsBuf);/* 将收到的GPS模块数据按原样 打印到COM1口,便于跟踪调试 */
                  
                    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //使能接收中断               
            
                                 
        }
      
}


使用特权

评论回复
地板
Bermanrep|  楼主 | 2016-1-31 16:05 | 只看该作者
4. 解析语义:
void GPS_Data_update()
{
   
    char * start_p = GpsBuf;      

    char *pos_p;
   /*
   int strncmp(const char *string1, const char *string2, size_t count);
   比较字符串string1和string2大小,只比较前面count个字符. 比较过程中,
   任何一个字符串的长度小于count, 则count将被较短的字符串的长度取代.
   此时如果两串前面的字符都相等, 则较短的串要小.
   返回值< 0, 表示string1的子串小于string2的子串;
   返回值为0, 表示string1的子串等于string2的子串;
   返回值> 0, 表示string1的子串大于string2的子串.
   */
  if(strncmp(GpsBuf, "$GPGGA",6)==0)
  {
   //ShowStringPos (0, 4,"$GPGGA"); //bebug
   
        /*字段1 :UTC 时间,hhmmss.sss,时分秒格式 */
        pos_p = strchr(start_p, ','); //查找字符串s中首次出现字符c的位置,剥离c前面的信息
        if (pos_p == 0)
        {
            return;//2个逗号连在一起的情况
        }
    pos_p++;  // p+1后指向UTC时间
    myGPS.Hour = StrToIntFix(pos_p, 2);
        pos_p += 2;
        myGPS.Min = StrToIntFix(pos_p, 2);
        pos_p += 2;
        myGPS.Sec = StrToIntFix(pos_p, 2);
         //微秒忽略
        
     /* 字段2 :纬度ddmm.mmmm,度分格式(前导位数不足则补0)*/
     pos_p = strchr(pos_p, ','); //接着刚才指针位置找下一个逗号
        if (pos_p == 0)
        {
           return;
        }
        pos_p++;
        
        myGPS.WeiDu_Du = StrToIntFix(pos_p, 2);
        pos_p += 2;
        myGPS.WeiDu_Fen = StrToIntFix(pos_p, 2) * 10000;
        pos_p += 3;
        myGPS.WeiDu_Fen += StrToIntFix(pos_p, 4);
            
        /* 字段3 :N(北纬)或S(南纬) */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        if (*pos_p == 'S')
        {
                myGPS.NS = 'S';
        }
        else if (*pos_p == 'N')
        {
                myGPS.NS = 'N';
        }
        else
        {
                return;
        }
        
    /* 字段4 :经度dddmm.mmmm,度分格式(前导位数不足则补0) */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        myGPS.JingDu_Du = StrToIntFix(pos_p, 3);
        pos_p += 3;
        myGPS.JingDu_Fen = StrToIntFix(pos_p, 2) * 10000;
        pos_p += 3;
        myGPS.JingDu_Fen += StrToIntFix(pos_p, 4);
        
        /* 字段5 :E(东经)或W(西经) */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        if (*pos_p == 'E')
        {
                myGPS.EW = 'E';
        }
        else if (*pos_p == 'W')
        {
                myGPS.EW = 'W';
        }
        
        /* 字段6 :GPS状态,0=未定位,1=非差分定位,2=差分定位,3=无效PPS,6=正在估算 */
        pos_p = strchr(pos_p, ',');
        if (pos_p == 0)
        {
                return;
        }
        pos_p++;
        if ((*pos_p == '1') || (*pos_p == '2'))
        {
                myGPS.PositionOk = 1;
        }
        else
        {
                myGPS.PositionOk = 0;
        }

        
          /* 字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0) */
                pos_p = strchr(pos_p, ',');
                if (pos_p == 0)
                {
                        return;
                }
                pos_p++;
                myGPS.ViewNumber = StrToInt(pos_p);
               
                //p += 2;
        
                /* 字段8:HDOP水平精度因子(0.5 - 99.9) */
                pos_p = strchr(pos_p, ',');
                if (pos_p == 0)
                {
                        return;
                }
                pos_p++;
                myGPS.HDOP = StrToInt(pos_p);
        
                /* 字段9:海拔高度(-9999.9 - 99999.9) */
                pos_p= strchr(pos_p, ',');
                if (pos_p == 0)
                {
                        return;
                }
                pos_p++;
                myGPS.Altitude = StrToInt(pos_p);
        //后面的,39.5,M,-15.5,M,6.8,0000*68 丢弃
        
   
  }
  
  //if(strncmp(GpsBuf, "$GPRMC",6)==0)
  //{
   //ShowStringPos (0, 4,"$GPRMC"); //bebug
  //}
  
}
5.运行:
在RTOS中用一个或两个任务执行   gps_pro(); GPS_Data_update();
在main函数中用while(1){gps_pro(); GPS_Data_update();}

使用特权

评论回复
5
wangagt| | 2016-9-23 11:31 | 只看该作者
您好,我手里有stm32 和 sim808 ,想实现上电自动取 GPS信息,发送到指定的ip上去。楼主这个程序能共享一下吗?多谢多谢wangagt 163邮箱

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

132

帖子

2

粉丝