STM32Cube的串口实战(一)GPS+BD模块
作者:互联网
串口系列
STM32Cube的串口设置(一)即学即用
STM32Cube的串口设置(二)一个串口接收另一个串口发送
通过串口设置之前的部分大家应该基本会使用多个串口配合了,今天就来找个东西练练手,第一个拿GPS+BD开刀(用的是ATK_S1216F8_BD模块,STM32F767的芯片)。
实验目的
【将串口3连接的GPS+BD模块发送的信号转送到串口1通过USB打印出来,搜集其中相关信息获取需要的信息,单独打印】
一、基本思路
1、需要了解GPS+BD模块的波特率以及工作特性,确保UART3可以收到模块发送的数据
2、接收到数据后,转存至数据处理区,将数据条条单独分析
3、数据分析完毕之后将需要的经纬度位置、世界标准时间、GPS卫星数、BD卫星数等信息放到相应存储空间
4、向UART1发送UART3的原数据
5、向UART1发送处理后的数据
【GPS+BD模块是一个与卫星的通信装置,但是它只能向卫星请求当地的定位,所以与STM32的连接部分只存在GPS+BD的单方面发送信息,为单工传输,不涉及UART3的发送】
二、操作步骤
要求:通过串口向PC发送一段字符
1、根据自己的stm32的芯片型号来选择,我这里是STM32F767IGTx
2、选好芯片之后照旧设置RCC为外部时钟
3、使能串口1、3(usart1、usart3),如图:
模式设为异步(Asynchronous)其他默认,波特率可以自己改,USART1为115200Bits/s,USART3为38400Bits/s。
之后再使能串口1、3中断
4、设置中断优先级,如图:
设置中断优先级
5、看原理图,找到串口对应引脚,如图:
我这里是
PA10——>USART1_RX
PA9——>USART1_TX
PB11——>USART3_RX
PB10——>USART3_TX
6、根据对应引脚设置串口引脚,如图:
找到PA9、PA10引脚左键点击分别选择USART1_TX和USART1_RX
(不用担心选错选反,针脚的功能是ST公司已经定义好了的)
7、设置时钟树,如图:
这里会搞的按自己习惯搞,不会搞的默认就好,但是不能有里面是红色的框(红色框就是错了意思)
8、项目设置,如图:
红框里的按照自己的Keil版本来
个人喜欢把.c/.h文件分开
9、点击右上角的‘GENERATE CODE’直接生成代码,如图:
10、生成代码后用Keil打开项目并在Application/User中找到usart.c并在/USER CODE BEGIN 0/后添加如下代码,如图:
#include <stdio.h>
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
int fputc(int ch, FILE *f)
{
while((USART3->ISR&0X40)==0);
USART3->TDR=(uint8_t)ch;
return ch;
}
uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//串口发送缓存区
__align(8) uint8_t USART3_TX_BUF[USART3_MAX_SEND_LEN]; //发送缓冲,最大USART3_MAX_SEND_LEN字节
//串口接收缓存区
uint8_t USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
uint16_t USART_RX_STA=0; //接收状态标记
uint16_t USART3_RX_STA=0;
uint8_t aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
以上代码主要保证将UART1的输出直接用printf代替。
11-A、生成代码后用Keil打开项目并在Application/User中找到main.c:
在/USER CODE BEGIN PV/后添加如下代码
extern uint8_t USART3_RX_BUF[800];//重申明外部转存空间
在/* USER CODE BEGIN WHILE */后添加如下代码
HAL_UART_Receive_IT(&huart3,USART3_RX_BUF,1);
HAL_UART_Transmit(&huart1,USART3_RX_BUF,sizeof(USART3_RX_BUF),100);
\\开启中断
在/* USER CODE BEGIN 4 */后添加回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART3)
{
HAL_UART_Transmit(&huart1,USART3_RX_BUF,1,100);//串口1发送接收buff里的东西
HAL_UART_Receive_IT(&huart3,USART3_RX_BUF,1); //重新开启串口3接收中断
}
}
编译、下载
该操作是将UART3的原数据不进行处理直接转发到UART1,操作简单,不涉及数据处理。
11-B、在项目中新建两个文件,分别为gps.h和gps.c:
gps.h
#ifndef __GPS_H
#define __GPS_H
//GPS NMEA-0183协议重要参数结构体定义
//卫星信息
__packed typedef struct
{
unsigned char num; //卫星编号
unsigned char eledeg; //卫星仰角
unsigned short azideg; //卫星方位角
unsigned char sn; //信噪比
}nmea_slmsg;
//北斗 NMEA-0183协议重要参数结构体定义
//卫星信息
__packed typedef struct
{
unsigned char beidou_num; //卫星编号
unsigned char beidou_eledeg; //卫星仰角
unsigned short beidou_azideg; //卫星方位角
unsigned char beidou_sn; //信噪比
}beidou_nmea_slmsg;
//UTC时间信息
__packed typedef struct
{
unsigned short year; //年份
unsigned char month; //月份
unsigned char date; //日期
unsigned char hour; //小时
unsigned char min; //分钟
unsigned char sec; //秒钟
}nmea_utc_time;
//NMEA 0183 协议解析后数据存放结构体
__packed typedef struct
{
unsigned char svnum; //可见GPS卫星数
unsigned char beidou_svnum; //可见北斗卫星数
nmea_slmsg slmsg[12]; //最多12颗GPS卫星
beidou_nmea_slmsg beidou_slmsg[12]; //暂且算最多12颗北斗卫星
nmea_utc_time utc; //UTC时间
unsigned int latitude; //纬度 分扩大100000倍,实际要除以100000
unsigned char nshemi; //北纬/南纬,N:北纬;S:南纬
unsigned int longitude; //经度 分扩大100000倍,实际要除以100000
unsigned char ewhemi; //东经/西经,E:东经;W:西经
unsigned char gpssta; //GPS状态:0,未定位;1,非差分定位;2,差分定位;6,正在估算.
unsigned char posslnum; //用于定位的GPS卫星数,0~12.
unsigned char possl[12]; //用于定位的卫星编号
unsigned char fixmode; //定位类型:1,没有定位;2,2D定位;3,3D定位
unsigned short pdop; //位置精度因子 0~500,对应实际值0~50.0
unsigned short hdop; //水平精度因子 0~500,对应实际值0~50.0
unsigned short vdop; //垂直精度因子 0~500,对应实际值0~50.0
int altitude; //海拔高度,放大了10倍,实际除以10.单位:0.1m
unsigned short speed; //地面速率,放大了1000倍,实际除以10.单位:0.001公里/小时
}nmea_msg;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置波特率结构体
__packed typedef struct
{
unsigned short sos; //启动序列,固定为0XA0A1
unsigned short PL; //有效数据长度0X0004;
unsigned char id; //ID,固定为0X05
unsigned char com_port; //COM口,固定为0X00,即COM1
unsigned char Baud_id; //波特率(0~8,4800,9600,19200,38400,57600,115200,230400,460800,921600)
unsigned char Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
unsigned char CS; //校验值
unsigned short end; //结束符:0X0D0A
}SkyTra_baudrate;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置输出信息结构体
__packed typedef struct
{
unsigned short sos; //启动序列,固定为0XA0A1
unsigned short PL; //有效数据长度0X0009;
unsigned char id; //ID,固定为0X08
unsigned char GGA; //1~255(s),0:disable
unsigned char GSA; //1~255(s),0:disable
unsigned char GSV; //1~255(s),0:disable
unsigned char GLL; //1~255(s),0:disable
unsigned char RMC; //1~255(s),0:disable
unsigned char VTG; //1~255(s),0:disable
unsigned char ZDA; //1~255(s),0:disable
unsigned char Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
unsigned char CS; //校验值
unsigned short end; //结束符:0X0D0A
}SkyTra_outmsg;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置位置更新率结构体
__packed typedef struct
{
unsigned short sos; //启动序列,固定为0XA0A1
unsigned short PL; //有效数据长度0X0003;
unsigned char id; //ID,固定为0X0E
unsigned char rate; //取值范围:1, 2, 4, 5, 8, 10, 20, 25, 40, 50
unsigned char Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
unsigned char CS; //校验值
unsigned short end; //结束符:0X0D0A
}SkyTra_PosRate;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置输出脉冲(PPS)宽度结构体
__packed typedef struct
{
unsigned short sos; //启动序列,固定为0XA0A1
unsigned short PL; //有效数据长度0X0007;
unsigned char id; //ID,固定为0X65
unsigned char Sub_ID; //0X01
unsigned int width; //1~100000(us)
unsigned char Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
unsigned char CS; //校验值
unsigned short end; //结束符:0X0D0A
}SkyTra_pps_width;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 ACK结构体
__packed typedef struct
{
unsigned short sos; //启动序列,固定为0XA0A1
unsigned short PL; //有效数据长度0X0002;
unsigned char id; //ID,固定为0X83
unsigned char ACK_ID; //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK message
unsigned char CS; //校验值
unsigned short end; //结束符
}SkyTra_ACK;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 NACK结构体
__packed typedef struct
{
unsigned short sos; //启动序列,固定为0XA0A1
unsigned short PL; //有效数据长度0X0002;
unsigned char id; //ID,固定为0X84
unsigned char NACK_ID; //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK message
unsigned char CS; //校验值
unsigned short end; //结束符
}SkyTra_NACK;
int NMEA_Str2num(unsigned char *buf,unsigned char*dx);
void GPS_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_GPGSV_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_BDGSV_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_GNRMC_Analysis(nmea_msg *gpsx,unsigned char *buf);
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,unsigned char *buf);
unsigned char SkyTra_Cfg_Prt(unsigned char baud_id);
unsigned char SkyTra_Cfg_Tp(unsigned int width);
unsigned char SkyTra_Cfg_Rate(unsigned char Frep);
void SkyTra_Send_Date(unsigned char* dbuf,unsigned short len);
#endif
gps.c
#include "gps.h"
#include "gpio.h"
#include "usart.h"
#include "stdio.h"
#include "stdarg.h"
#include "string.h"
#include "math.h"
const unsigned int BAUD_id[9]={4800,9600,19200,38400,57600,115200,230400,460800,921600};//模块支持波特率数组
//从buf里面得到第cx个逗号所在的位置
//返回值:0~0XFE,代表逗号所在位置的偏移.
// 0XFF,代表不存在第cx个逗号
unsigned char NMEA_Comma_Pos(unsigned char *buf,unsigned char cx)
{
unsigned char *p=buf;
while(cx)
{
if(*buf=='*'||*buf<' '||*buf>'z')return 0XFF;//遇到'*'或者非法字符,则不存在第cx个逗号
if(*buf==',')cx--;
buf++;
}
return buf-p;
}
//m^n函数
//返回值:m^n次方.
unsigned int NMEA_Pow(unsigned char m,unsigned char n)
{
unsigned int result=1;
while(n--)result*=m;
return result;
}
//str转换为数字,以','或者'*'结束
//buf:数字存储区
//dx:小数点位数,返回给调用函数
//返回值:转换后的数值
int NMEA_Str2num(unsigned char *buf,unsigned char*dx)
{
unsigned char *p=buf;
unsigned int ires=0,fres=0;
unsigned char ilen=0,flen=0,i;
unsigned char mask=0;
int res;
while(1) //得到整数和小数的长度
{
if(*p=='-'){mask|=0X02;p++;}//是负数
if(*p==','||(*p=='*'))break;//遇到结束了
if(*p=='.'){mask|=0X01;p++;}//遇到小数点了
else if(*p>'9'||(*p<'0')) //有非法字符
{
ilen=0;
flen=0;
break;
}
if(mask&0X01)flen++;
else ilen++;
p++;
}
if(mask&0X02)buf++; //去掉负号
for(i=0;i<ilen;i++) //得到整数部分数据
{
ires+=NMEA_Pow(10,ilen-1-i)*(buf[i]-'0');
}
if(flen>5)flen=5; //最多取5位小数
*dx=flen; //小数点位数
for(i=0;i<flen;i++) //得到小数部分数据
{
fres+=NMEA_Pow(10,flen-1-i)*(buf[ilen+1+i]-'0');
}
res=ires*NMEA_Pow(10,flen)+fres;
if(mask&0X02)res=-res;
return res;
}
//分析GPGSV信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPGSV_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
unsigned char *p,*p1,dx;
unsigned char len,i,j,slx=0;
unsigned char posx;
p=buf;
p1=(unsigned char*)strstr((const char *)p,"$GPGSV");
len=p1[7]-'0'; //得到GPGSV的条数
posx=NMEA_Comma_Pos(p1,3); //得到可见卫星总数
if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<len;i++)
{
p1=(unsigned char*)strstr((const char *)p,"$GPGSV");
for(j=0;j<4;j++)
{
posx=NMEA_Comma_Pos(p1,4+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
else break;
posx=NMEA_Comma_Pos(p1,5+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
else break;
posx=NMEA_Comma_Pos(p1,6+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
else break;
posx=NMEA_Comma_Pos(p1,7+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
else break;
slx++;
}
p=p1+1;//切换到下一个GPGSV信息
}
}
//分析BDGSV信息
//gpsx:nmea信息结构体
//buf:接收到的北斗数据缓冲区首地址
void NMEA_BDGSV_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
unsigned char *p,*p1,dx;
unsigned char len,i,j,slx=0;
unsigned char posx;
p=buf;
p1=(unsigned char*)strstr((const char *)p,"$BDGSV");
len=p1[7]-'0'; //得到BDGSV的条数
posx=NMEA_Comma_Pos(p1,3); //得到可见北斗卫星总数
if(posx!=0XFF)gpsx->beidou_svnum=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<len;i++)
{
p1=(unsigned char*)strstr((const char *)p,"$BDGSV");
for(j=0;j<4;j++)
{
posx=NMEA_Comma_Pos(p1,4+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
else break;
posx=NMEA_Comma_Pos(p1,5+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
else break;
posx=NMEA_Comma_Pos(p1,6+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
else break;
posx=NMEA_Comma_Pos(p1,7+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
else break;
slx++;
}
p=p1+1;//切换到下一个BDGSV信息
}
}
//分析GNGGA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS/北斗数据缓冲区首地址
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
unsigned char *p1,dx;
unsigned char posx;
p1=(unsigned char*)strstr((const char *)buf,"$GNGGA");
posx=NMEA_Comma_Pos(p1,6); //得到GPS状态
if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,7); //得到用于定位的卫星数
if(posx!=0XFF)gpsx->posslnum=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,9); //得到海拔高度
if(posx!=0XFF)gpsx->altitude=NMEA_Str2num(p1+posx,&dx);
}
//分析GNGSA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS/北斗数据缓冲区首地址
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
unsigned char *p1,dx;
unsigned char posx;
unsigned char i;
p1=(unsigned char*)strstr((const char *)buf,"$GNGSA");
posx=NMEA_Comma_Pos(p1,2); //得到定位类型
if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<12;i++) //得到定位卫星编号
{
posx=NMEA_Comma_Pos(p1,3+i);
if(posx!=0XFF)gpsx->possl[i]=NMEA_Str2num(p1+posx,&dx);
else break;
}
posx=NMEA_Comma_Pos(p1,15); //得到PDOP位置精度因子
if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,16); //得到HDOP位置精度因子
if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,17); //得到VDOP位置精度因子
if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx);
}
//分析GNRMC信息
//gpsx:nmea信息结构体
//buf:接收到的GPS/北斗数据缓冲区首地址
void NMEA_GNRMC_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
unsigned char *p1,dx;
unsigned char posx;
unsigned int temp;
float rs;
p1=(unsigned char*)strstr((const char *)buf,"GNRMC");//"$GNRMC",经常有&和GNRMC分开的情况,故只判断GPRMC.
posx=NMEA_Comma_Pos(p1,1); //得到UTC时间
if(posx!=0XFF)
{
temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx); //得到UTC时间,去掉ms
gpsx->utc.hour=(temp/10000)+8;
gpsx->utc.min=(temp/100)%100;
gpsx->utc.sec=temp%100;
}
posx=NMEA_Comma_Pos(p1,3); //得到纬度
if(posx!=0XFF)
{
temp=NMEA_Str2num(p1+posx,&dx);
gpsx->latitude=temp/NMEA_Pow(10,dx+2); //得到°
rs=temp%NMEA_Pow(10,dx+2); //得到'
gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为°
}
posx=NMEA_Comma_Pos(p1,4); //南纬还是北纬
if(posx!=0XFF)gpsx->nshemi=*(p1+posx);
posx=NMEA_Comma_Pos(p1,5); //得到经度
if(posx!=0XFF)
{
temp=NMEA_Str2num(p1+posx,&dx);
gpsx->longitude=temp/NMEA_Pow(10,dx+2); //得到°
rs=temp%NMEA_Pow(10,dx+2); //得到'
gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为°
}
posx=NMEA_Comma_Pos(p1,6); //东经还是西经
if(posx!=0XFF)gpsx->ewhemi=*(p1+posx);
posx=NMEA_Comma_Pos(p1,9); //得到UTC日期
if(posx!=0XFF)
{
temp=NMEA_Str2num(p1+posx,&dx); //得到UTC日期
gpsx->utc.date=temp/10000;
gpsx->utc.month=(temp/100)%100;
gpsx->utc.year=2000+temp%100;
}
}
//分析GNVTG信息
//gpsx:nmea信息结构体
//buf:接收到的GPS/北斗数据缓冲区首地址
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
unsigned char *p1,dx;
unsigned char posx;
p1=(unsigned char*)strstr((const char *)buf,"$GNVTG");
posx=NMEA_Comma_Pos(p1,7); //得到地面速率
if(posx!=0XFF)
{
gpsx->speed=NMEA_Str2num(p1+posx,&dx);
if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx); //确保扩大1000倍
}
}
//提取NMEA-0183信息
//gpsx:nmea信息结构体
//buf:接收到的GPS/北斗数据缓冲区首地址
void GPS_Analysis(nmea_msg *gpsx,unsigned char *buf)
{
NMEA_GPGSV_Analysis(gpsx,buf); //GPGSV解析
NMEA_BDGSV_Analysis(gpsx,buf); //BDGSV解析
NMEA_GNGGA_Analysis(gpsx,buf); //GNGGA解析
NMEA_GNGSA_Analysis(gpsx,buf); //GNGSA解析
NMEA_GNRMC_Analysis(gpsx,buf); //GNRMC解析
NMEA_GNVTG_Analysis(gpsx,buf); //GNVTG解析
}
///////////////////////////////////////////SkyTraq 配置代码/////////////////////////////////////
////检查CFG配置执行情况
////返回值:0,ACK成功
//// 1,接收超时错误
//// 2,没有找到同步字符
//// 3,接收到NACK应答
unsigned char SkyTra_Cfg_Ack_Check(void)
{
unsigned short len=0,i;
unsigned char rval=0;
while((USART3_RX_STA&0X8000)==0 && len<100)//等待接收到应答
{
len++;
HAL_Delay(5);
}
if(len<100) //超时错误.
{
len=USART3_RX_STA&0X7FFF; //此次接收到的数据长度
for(i=0;i<len;i++)
{
if(USART3_RX_BUF[i]==0X83)break;
else if(USART3_RX_BUF[i]==0X84)
{
rval=3;
break;
}
}
if(i==len)rval=2; //没有找到同步字符
}else rval=1; //接收超时错误
USART3_RX_STA=0; //清除接收
return rval;
}
//配置SkyTra_GPS/北斗模块波特率
//baud_id:0~8,对应波特率,4800/9600/19200/38400/57600/115200/230400/460800/921600
//返回值:0,执行成功;其他,执行失败(这里不会返回0了)
unsigned char SkyTra_Cfg_Prt(unsigned char baud_id)
{
SkyTra_baudrate *cfg_prt=(SkyTra_baudrate *)USART3_TX_BUF;
cfg_prt->sos=0XA1A0; //引导序列(小端模式)
cfg_prt->PL=0X0400; //有效数据长度(小端模式)
cfg_prt->id=0X05; //配置波特率的ID
cfg_prt->com_port=0X00; //操作串口1
cfg_prt->Baud_id=baud_id; ////波特率对应编号
cfg_prt->Attributes=1; //保存到SRAM&FLASH
cfg_prt->CS=cfg_prt->id^cfg_prt->com_port^cfg_prt->Baud_id^cfg_prt->Attributes;
cfg_prt->end=0X0A0D; //发送结束符(小端模式)
SkyTra_Send_Date((unsigned char*)cfg_prt,sizeof(SkyTra_baudrate));//发送数据给SkyTra
HAL_Delay(200); //等待发送完成
return SkyTra_Cfg_Ack_Check();
}
//配置SkyTra_GPS/北斗模块的时钟脉冲宽度
//width:脉冲宽度1~100000(us)
//返回值:0,发送成功;其他,发送失败.
unsigned char SkyTra_Cfg_Tp(unsigned int width)
{
unsigned int temp=width;
SkyTra_pps_width *cfg_tp=(SkyTra_pps_width *)USART3_TX_BUF;
temp=(width>>24)|((width>>8)&0X0000FF00)|((width<<8)&0X00FF0000)|((width<<24)&0XFF000000);//小端模式
cfg_tp->sos=0XA1A0; //cfg header(小端模式)
cfg_tp->PL=0X0700; //有效数据长度(小端模式)
cfg_tp->id=0X65 ; //cfg tp id
cfg_tp->Sub_ID=0X01; //数据区长度为20个字节.
cfg_tp->width=temp; //脉冲宽度,us
cfg_tp->Attributes=0X01; //保存到SRAM&FLASH
cfg_tp->CS=cfg_tp->id^cfg_tp->Sub_ID^(cfg_tp->width>>24)^(cfg_tp->width>>16)&0XFF^(cfg_tp->width>>8)&0XFF^cfg_tp->width&0XFF^cfg_tp->Attributes;
cfg_tp->end=0X0A0D; //发送结束符(小端模式)
SkyTra_Send_Date((unsigned char*)cfg_tp,sizeof(SkyTra_pps_width));//发送数据给SkyTraF8-BD
return SkyTra_Cfg_Ack_Check();
}
//配置SkyTraF8-BD的更新速率
//Frep:(取值范围:1,2,4,5,8,10,20)测量时间间隔,单位为Hz,最大不能大于20Hz
//返回值:0,发送成功;其他,发送失败.
unsigned char SkyTra_Cfg_Rate(unsigned char Frep)
{
SkyTra_PosRate *cfg_rate=(SkyTra_PosRate *)USART3_TX_BUF;
cfg_rate->sos=0XA1A0; //cfg header(小端模式)
cfg_rate->PL=0X0300; //有效数据长度(小端模式)
cfg_rate->id=0X0E; //cfg rate id
cfg_rate->rate=Frep; //更新速率
cfg_rate->Attributes=0X01; //保存到SRAM&FLASH .
cfg_rate->CS=cfg_rate->id^cfg_rate->rate^cfg_rate->Attributes; //校验值
cfg_rate->end=0X0A0D; //发送结束符(小端模式)
SkyTra_Send_Date((unsigned char*)cfg_rate,sizeof(SkyTra_PosRate));//发送数据给SkyTraF8-BD
return SkyTra_Cfg_Ack_Check();
}
//发送一批数据给SkyTraF8-BD,这里通过串口3发送
//dbuf:数据缓存首地址
//len:要发送的字节数
void SkyTra_Send_Date(unsigned char* dbuf,unsigned short len)
{
unsigned short j;
for(j=0;j<len;j++)//循环发送数据
{
while((USART3->ISR&0X40)==0);//循环发送,直到发送完毕
USART3->TDR=dbuf[j];
}
}
将以上两个代码放到项目中后再main.c函数中添加如下代码:
定义以下变量
uint8_t USART1_TX_BUF[USART3_MAX_RECV_LEN]; //串口1,发送缓存区
nmea_msg gpsx; //GPS信息
__align(4) uint8_t dtbuf[50]; //打印缓存器
const uint8_t*fixmode_tbl[4]={"Fail","Fail"," 2D "," 3D "}; //fix mode字符串
定义GPS数据显示函数:
void Gps_Msg_Show(void)
{
float tp;
tp=gpsx.longitude;
printf("Longitude:%.5f %1c ",tp/=100000,gpsx.ewhemi); //得到经度字符串
printf("\r\n");
tp=gpsx.latitude;
printf("Latitude:%.5f %1c ",tp/=100000,gpsx.nshemi); //得到纬度字符串
printf("\r\n");
tp=gpsx.altitude;
printf("Altitude:%.1fm ",tp/=10); //得到高度字符串
printf("\r\n");
tp=gpsx.speed;
printf("Speed:%.3fkm/h ",tp/=1000); //得到速度字符串
printf("\r\n");
if(gpsx.fixmode<=3) //定位状态
{
sprintf((char *)dtbuf,"Fix Mode:%s",fixmode_tbl[gpsx.fixmode]);
printf("\r\n");
}
printf("GPS+BD Valid satellite:%02d",gpsx.posslnum); //用于定位的GPS卫星数
printf("\r\n");
printf("GPS Visible satellite:%02d",gpsx.svnum%100); //可见GPS卫星数
printf("\r\n");
printf("BD Visible satellite:%02d",gpsx.beidou_svnum%100); //可见北斗卫星数
printf("\r\n");
printf("UTC Date:%04d/%02d/%02d ",gpsx.utc.year,gpsx.utc.month,gpsx.utc.date); //显示UTC日期
printf("\r\n");
printf("UTC Time:%02d:%02d:%02d ",gpsx.utc.hour,gpsx.utc.min,gpsx.utc.sec); //显示UTC时间
printf("\r\n\n\n");
}
在main函数的主循环内添加如下代码:
uint16_t i,rxlen;
uint16_t lenx;
uint8_t key=0XFF;
uint8_t upload=1;
while (1)
{
HAL_Delay(1);
if(USART3_RX_STA&0X8000) //接收到一次数据了
{
rxlen=USART3_RX_STA&0X7FFF; //得到数据长度
for(i=0;i<rxlen;i++)USART1_TX_BUF[i]=USART3_RX_BUF[i];
USART3_RX_STA=0; //启动下一次接收
USART1_TX_BUF[i]=0; //自动添加结束符
i=0;
GPS_Analysis(&gpsx,(uint8_t*)USART1_TX_BUF);//分析字符串
Gps_Msg_Show(); //显示信息
if(upload)printf("\r\n%s\r\n",USART1_TX_BUF);//发送接收到的数据到串口1
}
if((lenx%500)==0)
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
lenx++;
以上数据是将UART3接收到的数据通过转存区分析后根据分析出的数据通过Gps_Msg_Show()函数通过UART1打印出来。
upload的作用是是否将UART3收到的原始数据转发给UART1
编译、下载、看结果
三、实验验证
正所谓没有实验结果的教程都是耍流氓,出结果
等待约30秒的GPS冷启动后,收到卫星信息
该格式为NMEA-0183协议,是美国国家海洋电子协会为海用电子设备制定的标准格式,目前是GPS/北斗导航设备的标准协议,使用ASCII码传递GPS定位信息。
以上为upload=1时,在发送了我们需要的信息同时转发了UART3的接收信息,现在将upload改为0,看结果:
为了保证接收信息的正确性,上图我截取了我电脑的时间和GPS接收的时间,由图可知,GPS获取的时间为2019年9月1日14:41:01,我电脑右下角为2019年9月1日14:41,所以信息基本准确.
由于GPS收到的是国际标准时间UTC,但是中国北京在东8区,全国计时以北京时间为准,所以我在gps.c文件中的void NMEA_GNRMC_Analysis(nmea_msg *gpsx,unsigned char *buf)函数下,将收到的UTC时间的hour(小时部分)加了8小时,正好为北京时间。
到此试验成功。
Good Game!!!!!!
接下来会推出一系列的关于串口外设使用的分享,有需要的猿们敬请关注!!!!!
以上内容欢迎大家转载引用,标明出处即可!!!!!
标签:BD,p1,gpsx,unsigned,STM32Cube,char,NMEA,posx,串口 来源: https://blog.csdn.net/ASWaterbenben/article/details/100182544