【STM32F303开发】+如何解析GPS数据
本帖最后由 caizhiwei 于 2015-7-27 09:16 编辑实现步骤如下:
1.初始化usart3:
#define UART3_TX_BUF_SIZE 1*128
#define UART3_RX_BUF_SIZE 512
unsigned char Uart1TxBuf={0}; /* com1_rf发送缓冲区 */
unsigned char Uart1RxBuf={0}; /* com1_rf接收缓冲区 */
unsigned char Uart3TxBuf={0}; /* com3_发送缓冲区 */
unsigned char Uart3RxBuf={0}; /* com3_接收缓冲区 */
bool Uart1RxBuf_full =false;
bool Uart3RxBuf_full =false;
void USART3_Init(u32 Baudrate)
{
USART_InitTypeDefUSART_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);
}
2.写带fifo缓冲区的串口中断:
voidUSART3_IRQHandler(void)
{
static u16 RxCount;
if(USART_GetFlagStatus(USART3,USART_IT_RXNE)==SET)
{
USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清除中断标志
Uart3RxBuf = 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. 解析语义:
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();}
); //P指向了该位置,在字符串中查找字符$第一次出现的位置
for(i=0;i<GPS_BUFF_SIZE;i++)
{
GpsBuf = Uart3RxBuf;//以$开头的字符串
}
printf("%s\r\n",GpsBuf);/* 将收到的GPS模块数据按原样 打印到COM1口,便于跟踪调试 */
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //使能接收中断
}
}
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();}
编辑贴子的时候代码总是错位,试了好几次,编辑之后好好的,点了发帖之后就乱了。。。 /*
*********************************************************************************************************
* 函 数 名: DispGPSStatus
* 功能说明: 打印GPS数据包解码结果
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void DispGPSStatus(void)
{
char buf;
/* 纬度 */
if (myGPS.NS == 'S')
{
sprintf(buf, "南纬 %02d.%06d°", myGPS.WeiDu_Du, gps_FenToDu(myGPS.WeiDu_Fen));
sprintf(&buf, "=%02d°%02d'%02d\"", myGPS.WeiDu_Du,
myGPS.WeiDu_Fen / 10000, gps_FenToMiao(myGPS.WeiDu_Fen));
}
else
{
sprintf(buf, "北纬 %02d.%06d°",myGPS.WeiDu_Du, gps_FenToDu(myGPS.WeiDu_Fen));
sprintf(&buf, "=%02d°%02d'%02d\"", myGPS.WeiDu_Du,
myGPS.WeiDu_Fen / 10000, gps_FenToMiao(myGPS.WeiDu_Fen));
}
printf(buf);
/* 经度 */
if (myGPS.EW == 'E')
{
sprintf(buf, "东经 %03d.%06d°", myGPS.JingDu_Du, gps_FenToDu(myGPS.JingDu_Fen));
sprintf(&buf, "=%03d°%02d'%02d\"", myGPS.JingDu_Du,
myGPS.WeiDu_Fen / 10000, gps_FenToMiao(myGPS.JingDu_Fen));
}
else
{
sprintf(buf, "西经 =%03d.%06d°", myGPS.JingDu_Du, gps_FenToDu(myGPS.JingDu_Fen));
sprintf(&buf, "=%03d°%02d'%02d\"", myGPS.JingDu_Du,
myGPS.JingDu_Fen / 10000, gps_FenToMiao(myGPS.JingDu_Fen));
}
printf(buf);
/* 速度 */
sprintf(buf, "速度 = %5d.%d KM/h", myGPS.SpeedKM / 10, myGPS.SpeedKM % 10);
printf(buf);
/* 海拔 */
sprintf(buf, "海拔 = %5d.%d M", myGPS.Altitude / 10, myGPS.Altitude % 10);
printf(buf);
printf("\n\r正在使用的卫星数量%d.", myGPS.ViewNumber);
if(myGPS.PositionOk == 1)
printf("\n\rGPS定位成功!");
printf("\r"); /* 回车,不换行 */
} <Code Language="csharp">
<![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return $field$;}
set
{
$field$ = value;
this.RaisePropertyChanged("$property$");
}
}
$end$]]>
</Code>
先谢谢楼主~
上面是我试的代码,感觉挺好用…… :lol:lol谢啦,不过有需要的可以下载源码看看,都在里面的 :lol谢谢楼主的分享 多谢分享。。。学习了 好东西 多谢楼主了, 上位机结合百度地图,就是个导航系统了。。:)