串口系列
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!!!!!!
接下來會推出一系列的關於串口外設使用的分享,有需要的猿們敬請關注!!!!!
以上內容歡迎大家轉載引用,標明出處即可!!!!!