串口系列
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_TXPB11——>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倍,实际要除以100000unsigned char nshemi;                    //北纬/南纬,N:北纬;S:南纬                 unsigned int longitude;               //经度 分扩大100000倍,实际要除以100000unsigned 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.0unsigned short hdop;                  //水平精度因子 0~500,对应实际值0~50.0unsigned 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;            //启动序列,固定为0XA0A1unsigned short PL;             //有效数据长度0X0004; unsigned char id;             //ID,固定为0X05unsigned 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;            //启动序列,固定为0XA0A1unsigned short PL;             //有效数据长度0X0009; unsigned char id;             //ID,固定为0X08unsigned char GGA;            //1~255(s),0:disableunsigned char GSA;            //1~255(s),0:disableunsigned char GSV;            //1~255(s),0:disableunsigned char GLL;            //1~255(s),0:disableunsigned char RMC;            //1~255(s),0:disableunsigned char VTG;            //1~255(s),0:disableunsigned char ZDA;            //1~255(s),0:disableunsigned 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;            //启动序列,固定为0XA0A1unsigned short PL;             //有效数据长度0X0003; unsigned char id;             //ID,固定为0X0Eunsigned char rate;           //取值范围:1, 2, 4, 5, 8, 10, 20, 25, 40, 50unsigned 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;            //启动序列,固定为0XA0A1unsigned short PL;             //有效数据长度0X0007; unsigned char id;             //ID,固定为0X65unsigned char Sub_ID;         //0X01unsigned 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;            //启动序列,固定为0XA0A1unsigned short PL;             //有效数据长度0X0002; unsigned char id;             //ID,固定为0X83unsigned char ACK_ID;         //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK messageunsigned char CS;             //校验值unsigned short end;            //结束符
}SkyTra_ACK;//SkyTra S1216F8 NACK结构体
__packed typedef struct
{unsigned short sos;            //启动序列,固定为0XA0A1unsigned short PL;             //有效数据长度0X0002; unsigned char id;             //ID,固定为0X84unsigned char NACK_ID;         //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK messageunsigned 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时间,去掉msgpsx->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;          //操作串口1cfg_prt->Baud_id=baud_id;        波特率对应编号cfg_prt->Attributes=1;         //保存到SRAM&FLASHcfg_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 idcfg_tp->Sub_ID=0X01;         //数据区长度为20个字节.cfg_tp->width=temp;         //脉冲宽度,uscfg_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 idcfg_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!!!!!!接下来会推出一系列的关于串口外设使用的分享,有需要的猿们敬请关注!!!!!

以上内容欢迎大家转载引用,标明出处即可!!!!!

STM32Cube的串口实战(一)GPS+BD模块相关推荐

  1. 树莓派3b连接GPS+BD模块并用python获取数据(串口版)

    目的:树莓派用串口连接GPS+BD模块获取位置信息 材料:树莓派3b(Ubuntu MATE系统),GPS+BD模块,GPS有源天线,杜邦线 步骤: 1. 连接各模块 2. 修改串口设置,由于树莓派3 ...

  2. Windows USB串口接收GPS北斗模块数据和数据说明

    陈拓 2022/05/07-2022/05/09 1. 简介 本文以GPS+北斗卫星定位授时导航模块HT1818Z3G5L为例,在Win10下读数据. 产品参数 引脚定义 2. 连接PC机和HT181 ...

  3. ESP32 ESP-IDF串口的使用-读GPS北斗模块数据

    陈拓 2022/04/27-2022/05/10 1. 简介 在<Windows USB串口接收GPS北斗模块数据和数据说明> https://zhuanlan.zhihu.com/p/5 ...

  4. BetaFlight深入传感设计之四:GPS传感模块

    BetaFlight深入传感设计之四:GPS传感模块 1. HwPreInit/HwInit阶段 1.1 [业务HwPreInit]gpsInit 1.2 [业务HwInit]gpsInitHardw ...

  5. ESP32 ESP-IDF SD(TF)卡保存GPS北斗模块数据

    陈拓 2022/05/13-2022/05/15 1. 简介 在<ESP32 ESP-IDF 获取GPS北斗模块的经纬度和日期时间> https://zhuanlan.zhihu.com/ ...

  6. android qt 串口通信,Qt串口通信开发之QSerialPort模块详细使用方法与实例

    Qt串口通信开发之QSerialPort模块详细使用方法与实例 发布时间:2020-10-23 12:19:05 来源:脚本之家 阅读:111 作者:沧海一笑-dj Qt串口通信基础及名词说明 串口通 ...

  7. GPS授时模块:UTC时间,GMT,GPS时,北斗时,北京时间及其关系

    GPS授时模块:UTC时间,GMT,GPS时,北斗时,北京时间及其关系 2018-12-17 10:55 以下是SKYLAB小编整理的关于GPS授时模块和北斗授时模块的基础知识,包括UTC时间,GMT ...

  8. can 串口 can 232 can 485 串口转CANbus总线网关模块CAN232/485MB转换器CANCOM

    RS232/485串口转CANbus总线网关模块CAN232/485MB转换器CANCOM 1,串口转CANbus总线网关模块简介: 智能CAN/串口协议转换器LCNET Pro RS-232/485 ...

  9. 北斗/GPS芯片/模块基本常识问答:

    北斗/GPS芯片/模块基本常识问答: 1.什么叫双模芯片?有单独北斗芯片? 答: 北斗 GPS两用为双模.目前,没有单独北斗芯片的产品,单独北斗芯片都是测试实验.目前双模的芯片都可以设置成单独的北斗或 ...

最新文章

  1. S3C2440时钟体系结构
  2. php 文章搜索,登录 - 文章搜索 - phpStudy - phpStudy
  3. 这是什么操作?java中的变量竟然可以先使用后声明?
  4. Java 基础——构造器和方法的区别
  5. zbb20180415 cs 1.6 half-life launcher已停止工作
  6. Redis签到功能设计与实现
  7. 3.Python data types
  8. 《嵌入式-STM32开发指南》第三部分 外设篇 - 第5章 光敏传感器
  9. 什么是软件架构?常用的软件架构
  10. 毕业设计:深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序
  11. DFD数据流图的基本要素及易错点详细介绍
  12. 算法——实现随机拿到30道不重复的20以内的加减法题目
  13. 红米手机4开启root超级权限的步骤
  14. Vue_实现五星好评效果
  15. 【Google论文】The Google File System 译文
  16. 常用汇编数据传输指令
  17. 梯形法 微积分 c语言,关于 用辛普森法和梯形法求微积分的 程序!
  18. 2022双11/双十一天猫喵果总动员/京东穿行寻宝一键完成,自动任务脚本软件,分享源码学习
  19. matlab二维势阱简谐振动程序,常规解法与MATLAB解决一维无限深势阱中的粒子问题...
  20. 从零开始,砥砺前行,不忘初心

热门文章

  1. 用记账本记录借款、还款管理
  2. 数据结构与算法A实验六图论---7-4 公路村村通(最小生成树Prime和Kruskal算法)
  3. 四、py2neo 使用及构建图谱(知识图谱构建射雕人物关系)
  4. 《调和分析与非线性发展方程》简介
  5. 12条标准判定穷富:整天工作的人当不了富翁
  6. 有知群产品经理必修TOP班学习笔记
  7. kurento API解读
  8. CSS选择器完整参考手册
  9. qq空间 上传html,qq空间怎么上传本地视频两种上传方式(说说/日志)
  10. Saber仿真软件no active design解决方法