基于HMI串口屏的协议(STM32)

基于HMI串口屏的协议(STM32)

提示:
硬件:STM32H750VBT6、USART_HMI(3.5寸基本型)(TJC4832T035_011X)
官方资料网站:HMI

文章目录

前言

一、协议

提示:此处仅作为演示,完整版在文章末尾会有下载方式

注:一帧完整的数据一共有7Byte,所以在发送功能类数据时需要把其他位用0x00补全。
基于HMI串口屏的协议(STM32)
数据的缩放等级有0x000x010x02三个等级,分别对应数据扩大0倍数据扩大10倍数据扩大100倍。数据采用低端模式,即低字节在地址的低地址中,(例如:发送0x43AA,则协议中的数据位的顺序是AA 43,所以在单片机解析数据中需要注意)。STM32也是采用小端模式。

二、协议示例

在调试的时候可以把这些数据采用上位机的形式发送给单片机。
基于HMI串口屏的协议(STM32)

三、协议程序

1、Hmi_Agreements.c

代码如下(示例):

#include "hmi_agreement.h"
#include "stdlib.h"
#include "stdio.h"

_usarthmi UHMI;

// _User HMI_User;		//用户数据

/******************************
**** 函数功能:HMI复位
**** 形参:			无
**** 返回值:		无
*******************************/
void HMI_Usart_Rest(void)		//显示屏复位
{
	uint8_t End_Bit[3] = {0xff,0xff,0xff};
	uint8_t Rest[4] = "rest";
	HAL_UART_Transmit(&uart, (uint8_t*)&Rest, 4, 0xffff);				//发送数据
	HAL_UART_Transmit(&uart, (uint8_t*)&End_Bit, 3, 0xffff);		//发送结束位
}

/******************************
**** 函数功能:刷新HMI界面
**** 形参:				Page:需要刷新的页面(字符串形式)
**** 返回值:			无
*******************************/
void HMI_Usart_Refresh(uint8_t *Page)		//刷新页面
{
	uint8_t End_Bit[3] = {0xff,0xff,0xff};
	uint8_t Head[5] = "page ";
	uint8_t *str;
	uint16_t size = strlen((char*)Page);
	str = (uint8_t*)malloc(size + 5);		//申请内存
	if(str != NULL)	//申请内存成功
	{
		// sprintf((char*)str,"%s %s",Head,Page);
		memcpy(str,Head,5);
		memcpy(str + 5,Page,size);		
		HAL_UART_Transmit(&uart, (uint8_t*)str, size + 5, 0xffff);	//发送数据
		HAL_UART_Transmit(&uart, (uint8_t*)&End_Bit, 3, 0xffff);		//发送结束位
		free(str);	//释放内存
	}
}

// /******************************
// **** 函数功能:发送数据到HMI屏幕
// **** 形参:				SData:需要发送的数值(字符串形式)
// **** 返回值:			无
// *******************************/
// void HMI_Usart_SendDataValue(uint8_t *SData)		//串口发送数值数据到HMI屏幕
// {
// 	uint8_t End_Bit[3] = {0xff,0xff,0xff};
// 	HAL_UART_Transmit(&uart, (uint8_t*)&SData, strlen((char*)SData), 0xffff);				//发送数据
// 	HAL_UART_Transmit(&uart, (uint8_t*)&End_Bit, sizeof(End_Bit), 0xffff);		//发送结束位
// }

/******************************
**** 函数功能:隐藏或显示控件
**** 形参:				Obj:控件名字,State:状态(1,显示。0,隐藏)
**** 返回值:			无
*******************************/
void HMI_Usart_ShowHideobj(uint8_t *Obj,uint8_t State)		//对指定的控件的显示和隐藏进行操作
{
	uint8_t End_Bit[3] = {0xff,0xff,0xff};
	uint8_t Sho[4] = "vis ";
	uint8_t *str;
	uint16_t size = sizeof(Obj);
	str = (uint8_t*)malloc(size + 6);
	if(str != NULL)
	{
		memcpy(str,Sho,4);
		memcpy(str + 4,Obj,size);
		memcpy(str + 4 + size,(uint8_t*)",",1);
		if(State)
			memcpy(str + 5 + size,(uint8_t*)"1",1);
		else
			memcpy(str + 5 + size,(uint8_t*)"0",1);
		HAL_UART_Transmit(&uart, (uint8_t*)str, size + 6, 0xffff);	//发送数据
		HAL_UART_Transmit(&uart, (uint8_t*)&End_Bit, 3, 0xffff);		//发送结束位
		free(str);	//释放内存
	}
}

/******************************
**** 函数功能:发送字符数据到HMI
**** 形参:				Head:控件的名字,SData:显示的字符
**** 返回值:			无
*******************************/
void HMI_Usart_SendDataText(uint8_t *Head, uint8_t *SData)		//串口发送字符数据到HMI屏幕
{
	uint8_t End_Bit[3] = {0xff,0xff,0xff};
	uint8_t *str;
	uint16_t size1 = strlen((char*)Head);
	uint16_t size2 = strlen((char*)SData);
	str = (uint8_t*)malloc(size1 + size2 + 3);
	if(str != NULL)
	{
		memcpy(str,Head,size1);
		memcpy(str + size1,(uint8_t*)"=",1);
		memcpy(str + size1 + 1,(uint8_t*)"\"",1);
		memcpy(str + size1 + 2,SData,size2);
		memcpy(str + size1 + size2 + 2,(uint8_t*)"\"",1);
		HAL_UART_Transmit(&uart, (uint8_t*)str, size1 + size2 + 3, 0xffff);				//发送数据
		HAL_UART_Transmit(&uart, (uint8_t*)&End_Bit, 3, 0xffff);			//发送结束位
		free(str);	//释放内存
	}
}

/******************************
**** 函数功能:发送数据到控件(value)
**** 形参:				Head:控件的名字,data:数据
**** 返回值:			无
*******************************/
void HMI_Usart_SendDataValue(uint8_t *Head, int16_t data)
{
	uint8_t End_Bit[3] = {0xff,0xff,0xff};
	uint8_t buf[10];
	uint8_t *str;
	uint16_t size1 = strlen((char*)Head);
	sprintf((char*)&buf,"%d",data);
	uint16_t size2 = strlen((char*)buf);

	str = (uint8_t*)malloc(size1 + 1);
	if(str != NULL)
	{
		memcpy(str,Head,size1);
		memcpy(str + size1,(uint8_t*)"=",1);
		str = (uint8_t*)realloc(str,size1 + 1 + size2);		//再申请内存
		memcpy(str + size1 + 1, buf,size2);
		HAL_UART_Transmit(&uart, (uint8_t*)str, size1 + size2 + 1, 0xffff);	//发送数据
		HAL_UART_Transmit(&uart, (uint8_t*)&End_Bit, 3, 0xffff);			//发送结束位
		free(str);	//释放内存
	}
}

/******************************
**** 函数功能:	数据解算
**** 形参:		_DA接收到的数据
**** 返回值:	数据
*******************************/
static float ResolvingData(uint8_t *_DA)
{
	int16_t DataBUf = 0;
	switch (_DA[2])		//数据缩放等级(0(0),1(10),2(100))
	{
		case _1E_0:		//无缩放
			DataBUf = *((int16_t*)(&_DA[3]));
			return (float)DataBUf;		//解算数据

		case _1E_1:		//10倍缩放
			DataBUf = *((int16_t*)(&_DA[3]));
			return (float)DataBUf / 10.f;		//解算数据

		case _1E_2:		//100倍缩放
			DataBUf = *((int16_t*)(&_DA[3]));
			return (float)DataBUf / 100.f;		//解算数据
	
		default:
			return -1.f;
	}
}

/******************************
**** 函数功能:	接收数据处理
**** 形参:		_DA接收到的数据
**** 返回值:	无
*******************************/
static void Acceptance_Data(uint8_t *_DA)
{
	float DataBuf = 0;
	DataBuf = ResolvingData(_DA);		//数据解算
	if(DataBuf != -1)		//解算成功
	{
		UHMI.ID = _DA[1];		
		switch (_DA[1])	//数据ID
		{
			case _INT_VAID1: UHMI._IntRecData->_Data01 = (int16_t)DataBuf; break;
			case _INT_VAID2: UHMI._IntRecData->_Data02 = (int16_t)DataBuf; break;
			case _INT_VAID3: UHMI._IntRecData->_Data03 = (int16_t)DataBuf; break;
			case _INT_VAID4: UHMI._IntRecData->_Data04 = (int16_t)DataBuf; break;
			case _INT_VAID5: UHMI._IntRecData->_Data05 = (int16_t)DataBuf; break;	//整型数据

			case _FLO_VAID1: UHMI._FloatRecData->_Data10 = DataBuf; break;
			case _FLO_VAID2: UHMI._FloatRecData->_Data20 = DataBuf; break;
			case _FLO_VAID3: UHMI._FloatRecData->_Data30 = DataBuf; break;
			case _FLO_VAID4: UHMI._FloatRecData->_Data40 = DataBuf; break;
			case _FLO_VAID5: UHMI._FloatRecData->_Data50 = DataBuf; break;	//小数数据
		}
	}
}

/******************************
**** 函数功能:HMI接收数据函数
**** 形参:				RData:接收到的数据
**** 返回值:			无
*******************************/
void HMI_Usart_ReciveData(uint8_t *RData,uint8_t size)
{
	if(size == 7)	//数据长度正确
	{
		if(RData[0] == 0xCC)			//数值类帧,帧头正确
			Acceptance_Data(RData);		//数据处理
		else if(RData[0] == 0xDD)		//功能类,帧头正确
			HMI_Usart_FunctionSelect(&RData[1]);	//功能执行
	}
}

/******************************
**** 函数功能:HMI功能类执行函数选择
**** 形参:				Rfun:接收的数据
**** 返回值:			无
*******************************/
void HMI_Usart_FunctionSelect(uint8_t *Rfun)
{
	switch (*Rfun)
	{
		case Start:	UHMI.StartFlag = 1;	 break;	
		case Stop:	UHMI.StartFlag = 0;  break;
		case mode1:	UHMI.Mode = 1;	break;
		case mode2:	UHMI.Mode = 2;	break;
		case mode3:	UHMI.Mode = 3;	break;
		case mode4:	UHMI.Mode = 4;	break;
		case mode5:	UHMI.Mode = 5;	break;
		default: UHMI.Mode = 0; UHMI.StartFlag = 0; break;
	}
}

2、Hmi_Agreements.h

代码如下(示例):

#ifndef __HMI_AGREEMENT_H
#define __HMI_AGREEMENT_H	 

#include "stm32h7xx.h"                  // Device header
#include "stdio.h"
#include "string.h"
#include "usart.h"

#define uart		huart2		//使用的串口
#define _DataNum	5			//可接收数据数量		

enum _Var		
{
	Start 	=	0x00,
	Stop 	= 	0x01,	//工作状态

	mode1 	= 	0x11,
	mode2 	= 	0x12,
	mode3 	= 	0x13,
	mode4 	= 	0x14,
	mode5 	= 	0x15,	//模式

	_1E_0	= 	0,		//数据缩放等级
	_1E_1,
	_1E_2,

	_INT_VAID1 	= 	0x01,	//整型数据ID
	_INT_VAID2,
	_INT_VAID3,
	_INT_VAID4,
	_INT_VAID5,

	_FLO_VAID1	=	0x10,	//小数数据ID
	_FLO_VAID2,
	_FLO_VAID3,
	_FLO_VAID4,
	_FLO_VAID5,
};

struct IntRecData	//接收的数据缓存(整数)
{
	int16_t _Data01;
	int16_t _Data02;
	int16_t _Data03;
	int16_t _Data04;
	int16_t _Data05;
};

struct FloatRecData	//接收的数据缓存(小数)
{
	float _Data10;
	float _Data20;
	float _Data30;
	float _Data40;
	float _Data50;
};

typedef struct 
{
	uint8_t StartFlag;			//程序开始运行标志位
	uint8_t ID;					//数据ID	
	uint8_t Mode;				//工作模式
	struct IntRecData _IntRecData[_DataNum/5];		//接收的数据结构体
	struct FloatRecData _FloatRecData[_DataNum/5];		//接收的数据结构体
}_usarthmi;

extern _usarthmi UHMI;

/********************** 用户上传指令 ********************/

void HMI_Usart_Rest(void);										//HMI显示屏复位
void HMI_Usart_Refresh(uint8_t *Page);							//HMI刷新页面
void HMI_Usart_SendDataValue(uint8_t *Head, int16_t data);		//串口发送数据到HMI屏幕
void HMI_Usart_SendDataText(uint8_t *Head, uint8_t *SData);		//串口发送字符数据到HMI屏幕
void HMI_Usart_ShowHideobj(uint8_t *Obj,uint8_t State);			//对指定的控件的显示和隐藏进行操作

/********************* 用户接收数据处理 *******************/

static float ResolvingData(uint8_t *_DA);						//数据解算
static void Acceptance_Data(uint8_t *_DA);						//接收数据处理

/********************* 用户可调用的函数 *******************/

void HMI_Usart_ReciveData(uint8_t *RData,uint8_t size);						//HMI接收数据函数
void HMI_Usart_FunctionSelect(uint8_t *Rfun);					//HMI功能类执行函数选择


#endif

四、使用说明

1、接收数据

本程序暂未采用DMA形式发送接收数据,只需在串口回调函数中调用数据接收处理函数

void HMI_Usart_ReciveData(uint8_t *RData,uint8_t size)

接收的数据会分为两类:整型和浮点型的数据,整型数据保存在以下结构体中:

struct IntRecData	//接收的数据缓存(整数)
{
	int16_t _Data01;
	int16_t _Data02;
	int16_t _Data03;
	int16_t _Data04;
	int16_t _Data05;
};

浮点型数据保存在以下结构体中:

struct FloatRecData	//接收的数据缓存(小数)
{
	float _Data10;
	float _Data20;
	float _Data30;
	float _Data40;
	float _Data50;
};

他们的IDHMI发送的数据的ID相同(注:发送时整型和浮点型数据开始的ID不一样)
而他们都在以下结构体中:

typedef struct 
{
	uint8_t StartFlag;			//程序开始运行标志位
	uint8_t ID;					//数据ID	
	uint8_t Mode;				//工作模式
	struct IntRecData _IntRecData[_DataNum/5];		//接收的数据结构体
	struct FloatRecData _FloatRecData[_DataNum/5];		//接收的数据结构体
}_usarthmi;

2、发送数据

发送数据可使用以下函数:

void HMI_Usart_SendDataValue(uint8_t *Head, int16_t data);		//串口发送数据到HMI屏幕
void HMI_Usart_SendDataText(uint8_t *Head, uint8_t *SData);		//串口发送字符数据到HMI屏幕

五、下载方式

有积分的同学可以用csdn下载哦,没积分的同学可以去我GitHub仓库下载

上一篇:《Python参考手册(第4版•修订版)》——导读


下一篇:INT16乘累加防溢出量化训练——Overflow-aware Quantization