打印
[应用相关]

STM32Cube的串口实战------GPS+BD模块

[复制链接]
657|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
实验目的


【将串口3连接的GPS+BD模块发送的信号转送到串口1通过USB打印出来,搜集其中相关信息获取需要的信息,单独打印】

一、基本思路


1、需要了解GPS+BD模块的波特率以及工作特性,确保UART3可以收到模块发送的数据
2、接收到数据后,转存至数据处理区,将数据条条单独分析
3、数据分析完毕之后将需要的经纬度位置、世界标准时间、GPS卫星数、BD卫星数等信息放到相应存储空间
4、向UART1发送UART3的原数据
5、向UART1发送处理后的数据

【GPS+BD模块是一个与卫星的通信装置,但是它只能向卫星请求当地的定位,所以与STM32的连接部分只存在GPS+BD的单方面发送信息,为单工传输,不涉及UART3的发送】



使用特权

评论回复
沙发
heimaojingzhang|  楼主 | 2021-7-1 17:18 | 只看该作者
二、操作步骤

要求:通过串口向PC发送一段字符

1、根据自己的stm32的芯片型号来选择,我这里是STM32F767IGTx


使用特权

评论回复
板凳
heimaojingzhang|  楼主 | 2021-7-1 17:18 | 只看该作者
2、选好芯片之后照旧设置RCC为外部时钟


使用特权

评论回复
地板
heimaojingzhang|  楼主 | 2021-7-1 17:18 | 只看该作者
3、使能串口1、3(usart1、usart3),如图:

模式设为异步(Asynchronous)其他默认,波特率可以自己改,USART1为115200Bits/s,USART3为38400Bits/s。


之后再使能串口1、3中断


使用特权

评论回复
5
heimaojingzhang|  楼主 | 2021-7-1 17:18 | 只看该作者
4、设置中断优先级,如图:


设置中断优先级


使用特权

评论回复
6
heimaojingzhang|  楼主 | 2021-7-1 17:18 | 只看该作者
5、看原理图,找到串口对应引脚,如图:

我这里是

PA10——>USART1_RX
PA9——>USART1_TX
PB11——>USART3_RX  
PB10——>USART3_TX





使用特权

评论回复
7
heimaojingzhang|  楼主 | 2021-7-1 17:19 | 只看该作者
6、根据对应引脚设置串口引脚,如图:

找到PA9、PA10引脚左键点击分别选择USART1_TX和USART1_RX
(不用担心选错选反,针脚的功能是ST公司已经定义好了的)



使用特权

评论回复
8
heimaojingzhang|  楼主 | 2021-7-1 17:20 | 只看该作者
7、设置时钟树,如图:

这里会搞的按自己习惯搞,不会搞的默认就好,但是不能有里面是红色的框(红色框就是错了意思)


使用特权

评论回复
9
heimaojingzhang|  楼主 | 2021-7-1 17:20 | 只看该作者
8、项目设置,如图:

红框里的按照自己的Keil版本来


个人喜欢把.c/.h文件分开


使用特权

评论回复
10
heimaojingzhang|  楼主 | 2021-7-1 17:20 | 只看该作者
9、点击右上角的‘GENERATE CODE’直接生成代码,如图:


使用特权

评论回复
11
heimaojingzhang|  楼主 | 2021-7-1 17:20 | 只看该作者
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代替。


使用特权

评论回复
12
heimaojingzhang|  楼主 | 2021-7-1 17:21 | 只看该作者
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,操作简单,不涉及数据处理。


使用特权

评论回复
13
heimaojingzhang|  楼主 | 2021-7-1 17:21 | 只看该作者
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


使用特权

评论回复
14
heimaojingzhang|  楼主 | 2021-7-1 17:22 | 只看该作者
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];  
        }       
}


使用特权

评论回复
15
heimaojingzhang|  楼主 | 2021-7-1 17:22 | 只看该作者
将以上两个代码放到项目中后再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");       
}  


使用特权

评论回复
16
heimaojingzhang|  楼主 | 2021-7-1 17:22 | 只看该作者
在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

编译、下载、看结果


使用特权

评论回复
17
heimaojingzhang|  楼主 | 2021-7-1 17:23 | 只看该作者
三、实验验证
正所谓没有实验结果的教程都是耍流氓,出结果

等待约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小时,正好为北京时间。

到此试验成功。


使用特权

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

本版积分规则

77

主题

3908

帖子

4

粉丝