stm32HAL库串口收发GPS

1.GPS数据格式

帧格式形如: a a c c c , d d d , d d d , … , d d d ∗ h h ( C R ) ( L F ) 1 、 “ aaccc,ddd,ddd,…,ddd*hh(CR)(LF) 1、 “ aaccc,ddd,ddd,,dddhh(CR)(LF)1” :帧命令起始位
2、 aaccc:地址域,前两位为识别符(aa),后三位为语句名(ccc)
3、 ddd…ddd:数据
4、 “” :校验和前缀(也可以作为语句数据结束的标志)
5、 hh:校验和(check sum), $与
之间所有字符ASCII码的校验和(各字节做异或运算,得到
校验和后,再转换16进制格式的ASCII字符)
6、 (CR)(LF):帧结束,回车和换行符

一帧数据格式

$GPRMC,032524.00,A,2303.00591,N,11324.42138,E,0.689,270814,D7E
$GPVTG,T,M,0.689,N,1.276,K,D
23
$GPGGA,032524.00,2303.00591,N,11324.42138,E,2,12,0.78,13.2,M,-5.1,M,00007E
$GPGSA,A,3,01,11,08,30,07,32,13,42,28,04,27,17,1.18,0.78,0.89
01
$GPGSV,5,1,17,01,69,151,35,04,34,198,31,07,75,258,26,08,79,286,1674
$GPGSV,5,2,17,11,77,052,28,13,15,203,20,16,07,101,17,15,254,27
74
$GPGSV,5,3,17,19,29,036,40,20,12,162,23,04,181,08,27,06,052,157A
$GPGSV,5,4,17,28,21,314,19,30,49,311,17,32,10,122,20,42,50,128,39
73
$GPGSV,5,5,17,50,45,122,334A
$GPGLL,2303.00591,N,11324.42138,E,032524.00,A,D
68

串口接收流程

定义GPS数据结构体
typedef struct SaveData
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData;
char isParseData;
char UTCTime[UTCTime_Length];
char latitude[latitude_Length];
char N_S[N_S_Length];
char longitude[longitude_Length];
char E_W[E_W_Length];
char isUsefull;
} _SaveData;

只接收$GPRMC的内容

  1. 开启串口接收中断,接收一个字符存入res中
  2. 在串口中断回调函数中,判断当接收到‘$’时是接收到新的一行,u16 point为0
  3. 将每次回调接收的res存入 USART_RX_BUF[point]中,[USART_REC_LEN最大200]
  4. 判定当USART_RX_BUF[0] == 'KaTeX parse error: Expected 'EOF', got '&' at position 3: ' &̲& USART_RX_BUF[…GPRMC行时
  5. 当res==‘\n’,即一行结束
  6. 将USART_RX_BUF,中point1长的数据存入char GPS_Buffer[GPS_Buffer_Length=80]中,在存入之前要将GPS_Buffer全部清空
  7. 判定GPS获得数据isGetData=true,point长度清空, USART_RX_BUF[USART_REC_LEN]清空
  8. 如果point >= USART_REC_LEN,point= USART_REC_LEN;

解析GPS数据

  1. 如果isGetData==true,令其复为false,打印输出GPS_Buffer以供查看

$GPRMC,032525.00,A,2303.00594,N,11324.42136,E

通过提取subString=strstr(GPS_Buffer, “,”),循环6次
2. 当第一次循环,找不到,时报错errorLog(1);输出error 1;
3. 如果第一次能找到,subString+1到逗号之后
4. 再令subStringNext = strstr(subString, “,”)下一个逗号,如果找不到,则报错2
5. 将每一个从subString开始subStringNext - subString范围的数据依次memcpy存入时间,有效,维度,N,经度,E中
6. 判定isParseData=true解析完成,如果有效为A,isUsefull = true,否则为false
7. 打印GPS数据中各个成员,判定是否有效,如果无效,给定一个默认值

gps.h

编写GPS结构体用来存放接收GPRMC缓存和提取经纬度信息

#define GPS_Buffer_Length 80
#define true 1
#define false 0
#define	latitude_Length 10 
#define longitude_Length 11
typedef struct GPS_Data 
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData;
char isUseful; 
char latitude[latitude_Length];
char longitude[longitude_Length];
}_GPS_Data;
/
void user_common_init(void);//开启串口接收中断,初始化结构体
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//接收缓存
void parseGPS(void);//解析提取经纬度
void printGPS(void);//判断A/V是否有效,否则输出默认经纬度
extern _GPS_Data GPSData;

GPS.c

#define u8 uint8_t
#define u16 uint16_t
u8 rdata[1];
u8 rdata1[1];
u16 point;

#define RX_BUF_MAXLEN 200
char USART_RX_BUF[RX_BUF_MAXLEN];
_GPS_Data GPSData;
u8 latitude[]="2303.00591";
u8 longitude[]="11324.42138";

void user_common_init(void)
{	
	do{
	}while(HAL_OK!=HAL_UART_Receive_IT(&huart5,(u8*)&rdata,1));//开启接收中断
	//清空GPSData
	memset(GPSData.GPS_Buffer,0,GPS_Buffer_Length);
	memset(GPSData.latitude,0,latitude_Length);
	memset(GPSData.longitude,0,longitude_Length);
	GPSData.isGetData=false;
	GPSData.isUseful=false;
	//清空串口发送协议的起止符
	serial_rx_data.syn=serial_rx_data.syn_CR=serial_rx_data.syn_LF=serial_rx_data.type=0;		
}

//接收$GPRMC存入GPSData.buffer
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	u8 rec;
	if(huart->Instance==UART5)
	{
		rec=rdata[0];
		if(rec=='$')
		{
			point=0;
		}
		USART_RX_BUF[point++]=rec;
		if(USART_RX_BUF[0]=='$'&&USART_RX_BUF[4]=='M'&&USART_RX_BUF[5]=='C')
		{
			if(rec=='\n')
			{
				memset(GPSData.GPS_Buffer,0,GPS_Buffer_Length);
				memcpy(GPSData.GPS_Buffer,USART_RX_BUF,point);
				memset(USART_RX_BUF,0,RX_BUF_MAXLEN);
				GPSData.isGetData=true;
				point=0;
			}
		}
		if(point>=RX_BUF_MAXLEN)
		{
			point=RX_BUF_MAXLEN;
		}
		HAL_UART_Receive_IT(&huart5,(u8*)&rdata,1);
	}		
}
//解析GPS
void parseGPS()
{
	char *subString;
	char *subNext;
	if(GPSData.isGetData)
	{
		GPSData.isGetData=false;
		//HAL_UART_Transmit(&huart1,(u8*)GPSData.GPS_Buffer,sizeof(GPSData.GPS_Buffer),1000);
		for(int i=0;i<9;i++)
		{
			if((subString=strstr(GPSData.GPS_Buffer,","))!=NULL)
			{				
				subString++;
				if((subNext=strstr(subString,","))!=NULL)
				{
					char usefullBuffer[2];
					switch(i)
					{
						case 1:memcpy(usefullBuffer,subString,subNext-subString);
						case 2:memcpy(GPSData.latitude,subString,subNext-subString); break;
						case 4:memcpy(GPSData.longitude,subString,subNext-subString); break;
						default:break;
					}
					subString=subNext;

					if(usefullBuffer[0]=='A')
						GPSData.isUseful=true;
					else if(usefullBuffer[0]=='V')			
					{
						GPSData.isUseful=false;
					
					}
				}
			}
		}
	}
}
//使用默认
void printGPS()
{
	parseGPS();
	if(!GPSData.isUseful)//如果无效,则使用默认GPS
	{
		memcpy(GPSData.latitude,latitude,sizeof(latitude));
		memcpy(GPSData.longitude,longitude,sizeof(longitude));
	}
	GPSData.isGetData=false;	
	}	
}

串口发送协议

使用结构体和枚举型,选择不同类型TYPE数据发送

#ifndef _USER_PROTCOL_H_
#define _USER_PROTCOL_H_

#include "stdio.h"

/*protcol*/
enum _ptl_type
{
	VAL_START=0,
	VAL_POSE,
	VAL_IMU_RAW,
	VAL_VEL,
	VAL_PID,
	VAL_IMU,
	VAL_GPS,
	VAL_END
};

#define _SERIAL_SYN_CODE_START 0XFA 
#pragma pack(1)
typedef struct _serial_data
{
	uint8_t syn; 
	uint8_t type;
	union{
		struct{
			float liner[3],angular[3];
		}vel;
		struct{
			bool rot_ok,acc_ok,mag_ok;
			double rot[3],acc[3],mag[3];
		}imu;	
		struct{
			char latitude[11],longitude[12];
		}gps;
		float pid[3];
	}dat;
	uint8_t syn_CR;
	uint8_t syn_LF;
}serialData;
#pragma pack()
#endif

发送

void serial2_ros_data()
{
	static serialData data;
	data.syn=_SERIAL_SYN_CODE_START;
	data.syn_CR='\r';
	data.syn_LF='\n';
	float *quar_rpy;
/*************************************VEL*********************************************/
	while(HAL_UART_GetState(&huart4)==HAL_UART_STATE_BUSY_TX_RX) {}
	data.type=VAL_POSE;
	data.dat.vel.liner[0]=xrobot->robot_linear_vel_x;
	data.dat.vel.liner[1]=0;
  	data.dat.vel.liner[2]=0;	
  	HAL_UART_Transmit_DMA(&huart4,(uint8_t*)&data,sizeof(serialData));
/******************************************IMU*************************************/
  	quar_rpy=imu_print();
  	while(HAL_UART_GetState(&huart4)==HAL_UART_STATE_BUSY_TX_RX){}  
  	data.type=VAL_IMU;	
  	data.dat.vel.angular[0]=quar_rpy[0];
  	data.dat.vel.angular[1]=quar_rpy[1];
  	data.dat.vel.angular[2]=quar_rpy[2];
 	HAL_UART_Transmit_DMA(&huart4,(uint8_t*)&data,sizeof(data)); 
/***************************GPS***********************/
	while(HAL_UART_GetState(&huart4)==HAL_UART_STATE_BUSY_TX_RX){}	
	data.type=VAL_GPS;
	memcpy(data.dat.gps.latitude,	GPSData.latitude,sizeof(GPSData.latitude));	
	memcpy(data.dat.gps.longitude,	GPSData.longitude,sizeof(GPSData.longitude));	
	HAL_UART_Transmit_DMA(&huart4,(uint8_t*)&data,sizeof(serialData));
}
  • 5
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值