MODBUS协议交互框架 21

前言

MODBUS协议是一种工业领域的串行通信协议,由 Modicon(现隶属于施耐德电气)于 1979 年开发,主要用于工业自动化系统中控制器与远程设备之间的通信。它具有结构简单、开源免费、跨平台兼容的特点,是目前常用的应用层通信协议。

MODBUS协议是OSI模型第 7 层上的应用层报文传输协议,通信方式分为主从通信,主机发送协议指令,从机收到指令之后产生应答,如果没有应答,主机会再次发送协议指令,直到超时,即停止发送。

这里对MODUBUS协议的格式及协议通信框架做一下总结,便于复用。

一、协议格式

MODBUS协议和自定义的协议基本差不多,是一种数据传输格式,也是由起始帧、数据帧、校验帧等组成,只不过Modbus协议更为规范。

MODBUS协议格式:从机地址+功能码+数据+校验码(CRC16)。

MODBUS协议帧格式如下图:

地址域:从机的地址,范围:1~255,1个地址表示一个设备;

功能码:有03,04,06,0x10等功能码,03/04:表示读数据功能码,06:表示写单个寄存器数据,0x10:表示写多个寄存器数据;

数据:主机发送协议中数据表示寄存器,从机应答协议中的数据表示上报的数据;

校验码:对地址域、功能码、数据这些进行CRC16校验,校验值低位在前,高位在后。

二、举例

2.1 03H,04H命令

------读输入寄存器。

主机请求数据:

从机返回数据:

2.2 06命令

------ 写单个寄存器

主机下发数据:

从机返回数据:

三、代码交互框架

3.1 主机发送读数据框架

主机发送数据设计为一个状态机,每个状态计时时间为150ms。

主机发送请求读数据之后,等待接收应答数据,当超过150ms没有收到应答数据时,计数变量加1,连续加到4时,判断为接收数据超时,通信异常标志位置1。

代码实现如下:

复制代码
void pri_mppt_send(void)
{
	static uint8_t su8MpptState = 1;
	
	switch(su8MpptState)
	{
		case 1:
			PS_MpptComm_Send_Soc();
			HAL_UART_Transmit(&huart4,(uint8_t*)&g_su8MpptSendCmd, sizeof(g_su8MpptSendCmd),100);
			MODBUS_CLR_BIT(SysTimHandle.g_su16SystemTimFlag,SYSTEM_150MS_FLAG);
			SysTimHandle.g_su16SysTim150ms = 0;
//			pri_mppt_clr_tim_2s();				//调试
			su8MpptState = 2;	
			break;
		case 2:
			if(MODBUS_GET_BIT(SysTimHandle.g_su16SystemTimFlag,SYSTEM_150MS_FLAG))
//			if(MODBUS_GET_BIT(SysTimHandle.g_su16SystemTimFlag,SYSTEM_2S_FLAG))				//调试
			{
				g_su8MpptSendCnt++;
				if(g_su8MpptSendCnt >= 4)			//通信超时计数14:2.1s超时
				{
					su8MpptState = 3;
				}
				else
				{
					su8MpptState = 1;
				}
			}				
			break;
		case 3:					//MPPT通信异常,故障码E40
			MpptFltFlag.Bit.g_ubPVCommFault = 1;
			SysIsFlt.g_sbMpptIsFlt = 1;
			su8MpptState = 1;
			g_su8MpptSendCnt = 0;
			break;
		default:
			break;
	}
}

3.2 主机接收应答数据框架

主机收到应答数据之后,首先判断是否接收完成?然后再判断接收的数据长度,接收数据的地址,接收数据的功能码,全都没问题,则进行CRC16位数据校验,校验也没问题,最后就可以处理数据。

代码实现如下:

复制代码
//返回数据
void pri_mppt_resp(void)
{	
	if(MpptDataHandle.g_sbUartRxOkFlag)
	{
		MpptDataHandle.g_sbUartRxOkFlag = 0;
		if((MpptDataHandle.g_su8RxCnt != 12) && (MpptDataHandle.g_su8RxBuf[0] != 1) && (MpptDataHandle.g_su8RxBuf[1] != 3) && MpptDataHandle.g_su8RxBuf[2] != 6)
		{
			MpptDataHandle.g_su8RxCnt = 0;
			return;	
		}
		
		PS_AlgorithmCalc_Crc_Check(MpptDataHandle.g_su8RxBuf,MpptDataHandle.g_su8RxCnt-2);
		if(su16CrcDate == (MpptDataHandle.g_su8RxBuf[MpptDataHandle.g_su8RxCnt-1]<<8)+MpptDataHandle.g_su8RxBuf[MpptDataHandle.g_su8RxCnt-2])
		{
			g_su8MpptSendCnt = 0;	
			MpptFltFlag.Bit.g_ubPVCommFault = 0;	
			SysIsFlt.g_sbMpptIsFlt = 0;
			
			......
			MpptDataHandle.g_su8RxCnt = 0;
			memset(MpptDataHandle.g_su8RxBuf, 0, sizeof(MpptDataHandle.g_su8RxBuf));
		}
		else
		{
			MpptDataHandle.g_su8RxCnt = 0;
		}
	}
}

四、总结

MODBUS协议交互应用起始蛮简单的,使用过一次熟悉之后,后面基本都是复制粘贴,代码都可以拿来复用。

有几个点需要注意下:

-发送数据超时,数据不能一直发送,要设计超时机制;

-接收数据判断,根据协议格式逐个判断数据的正确性,这样更严谨。

相关推荐
hqwest19 天前
WPF真入门教程36--真硬核【自动化生产管理平台】
运维·自动化·modbus通信·串口设备·自动化生产管理平台·wpf开发
棋影7 个月前
主流PLC串口自由协议通信标准化
串口通信·plc通信·modbus通信