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_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模块相关推荐
- 树莓派3b连接GPS+BD模块并用python获取数据(串口版)
目的:树莓派用串口连接GPS+BD模块获取位置信息 材料:树莓派3b(Ubuntu MATE系统),GPS+BD模块,GPS有源天线,杜邦线 步骤: 1. 连接各模块 2. 修改串口设置,由于树莓派3 ...
- Windows USB串口接收GPS北斗模块数据和数据说明
陈拓 2022/05/07-2022/05/09 1. 简介 本文以GPS+北斗卫星定位授时导航模块HT1818Z3G5L为例,在Win10下读数据. 产品参数 引脚定义 2. 连接PC机和HT181 ...
- ESP32 ESP-IDF串口的使用-读GPS北斗模块数据
陈拓 2022/04/27-2022/05/10 1. 简介 在<Windows USB串口接收GPS北斗模块数据和数据说明> https://zhuanlan.zhihu.com/p/5 ...
- BetaFlight深入传感设计之四:GPS传感模块
BetaFlight深入传感设计之四:GPS传感模块 1. HwPreInit/HwInit阶段 1.1 [业务HwPreInit]gpsInit 1.2 [业务HwInit]gpsInitHardw ...
- ESP32 ESP-IDF SD(TF)卡保存GPS北斗模块数据
陈拓 2022/05/13-2022/05/15 1. 简介 在<ESP32 ESP-IDF 获取GPS北斗模块的经纬度和日期时间> https://zhuanlan.zhihu.com/ ...
- android qt 串口通信,Qt串口通信开发之QSerialPort模块详细使用方法与实例
Qt串口通信开发之QSerialPort模块详细使用方法与实例 发布时间:2020-10-23 12:19:05 来源:脚本之家 阅读:111 作者:沧海一笑-dj Qt串口通信基础及名词说明 串口通 ...
- GPS授时模块:UTC时间,GMT,GPS时,北斗时,北京时间及其关系
GPS授时模块:UTC时间,GMT,GPS时,北斗时,北京时间及其关系 2018-12-17 10:55 以下是SKYLAB小编整理的关于GPS授时模块和北斗授时模块的基础知识,包括UTC时间,GMT ...
- can 串口 can 232 can 485 串口转CANbus总线网关模块CAN232/485MB转换器CANCOM
RS232/485串口转CANbus总线网关模块CAN232/485MB转换器CANCOM 1,串口转CANbus总线网关模块简介: 智能CAN/串口协议转换器LCNET Pro RS-232/485 ...
- 北斗/GPS芯片/模块基本常识问答:
北斗/GPS芯片/模块基本常识问答: 1.什么叫双模芯片?有单独北斗芯片? 答: 北斗 GPS两用为双模.目前,没有单独北斗芯片的产品,单独北斗芯片都是测试实验.目前双模的芯片都可以设置成单独的北斗或 ...
最新文章
- S3C2440时钟体系结构
- php 文章搜索,登录 - 文章搜索 - phpStudy - phpStudy
- 这是什么操作?java中的变量竟然可以先使用后声明?
- Java 基础——构造器和方法的区别
- zbb20180415 cs 1.6 half-life launcher已停止工作
- Redis签到功能设计与实现
- 3.Python data types
- 《嵌入式-STM32开发指南》第三部分 外设篇 - 第5章 光敏传感器
- 什么是软件架构?常用的软件架构
- 毕业设计:深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序
- DFD数据流图的基本要素及易错点详细介绍
- 算法——实现随机拿到30道不重复的20以内的加减法题目
- 红米手机4开启root超级权限的步骤
- Vue_实现五星好评效果
- 【Google论文】The Google File System 译文
- 常用汇编数据传输指令
- 梯形法 微积分 c语言,关于 用辛普森法和梯形法求微积分的 程序!
- 2022双11/双十一天猫喵果总动员/京东穿行寻宝一键完成,自动任务脚本软件,分享源码学习
- matlab二维势阱简谐振动程序,常规解法与MATLAB解决一维无限深势阱中的粒子问题...
- 从零开始,砥砺前行,不忘初心