FreeModbus线圈

线圈的访问属性为读写

对线圈的操作包括:读线圈(0x01)、写单个线圈(0x05)、写多个线圈(0x0F)

读线圈(0x01)

在一个远程设备中,使用该功能码读取线圈的1 至2000 连续状态。请求PDU 详细说明了起始地址,即指定的第一个线圈地址和线圈编号。从零开始寻址线圈。因此寻址线圈1-16 为0-15。根据数据域的每个比特将响应报文中的线圈分成为一个线圈。指示状态为1= ON 和0= OFF。第一个数据字节的LSB(最低有效位)包括在询问中寻址的输出。其它线圈依次类推,一直到这个字节的高位端为止,并在后续字节中从低位到高位的顺序。

如果返回的输出数量不是八的倍数,将用零填充最后数据字节中的剩余比特(一直到字节的高位端)。字节数量域说明了数据的完整字节数。

读线圈状态图

/* 读线圈 */
eMBException eMBFuncReadCoils(UCHAR *pucFrame, USHORT *usLen)
{
	USHORT usRegAddress;
	USHORT usCoilCount;
	UCHAR ucNBytes;
	UCHAR *pucFrameCur;
	eMBException eStatus = MB_EX_NONE;
	eMBErrorCode eRegStatus;

	/* 校验PDU长度是否合理 */
	if(*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN))
	{
		/* 线圈地址 */
		usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8);
		usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]);
		/* 第1个线圈寻址为0,所以地址加一 */
		usRegAddress++;

		/* 线圈数量 */
		usCoilCount = (USHORT)(pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8);
		usCoilCount |= (USHORT)(pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1]);

		/* 检查线圈数量是否合理 */
		if((usCoilCount >= 1) &&
			 (usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX))
		{
			/* 构建响应 */
			
			/* PDU指针 */
			pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
			/* PDU长度初始化为0 */
			*usLen = MB_PDU_FUNC_OFF;

			/* 功能码 */
			*pucFrameCur++ = MB_FUNC_READ_COILS;
			*usLen += 1;

			/* 字节数 */
			if((usCoilCount & 0x0007) != 0)
			{
				ucNBytes = (UCHAR)(usCoilCount / 8 + 1);
			}
			else
			{
				ucNBytes = (UCHAR)(usCoilCount / 8);
			}
			*pucFrameCur++ = ucNBytes;
			*usLen += 1;

			/* 读取线圈值 */
			eRegStatus = eMBRegCoilsCB(pucFrameCur, usRegAddress, usCoilCount, MB_REG_READ);
			/* 产生异常 */
			if(eRegStatus != MB_ENOERR)
			{
				/* 错误转化为异常码 */
				eStatus = prveMBError2Exception(eRegStatus);
			}
			/* 未产生异常 */
			else
			{
				/* 数据长度 */
				*usLen += ucNBytes;;
			}
		}
		/* 线圈数量不合理 */
		else
		{
			/* 非法数据值 */
			eStatus = MB_EX_ILLEGAL_DATA_VALUE;
		}
	}
	/* PDU长度不对 */
	else
	{
		/* 非法数据值 */
		eStatus = MB_EX_ILLEGAL_DATA_VALUE;
	}

	return eStatus;
}

写单个线圈(0x05)

在一个远程设备上,使用该功能码写单个输出为ON 或OFF。请求数据域中的常量说明请求的ON/OFF状态。十六进制值FF 00请求输出为ON。十六进制值00 00 请求输出为OFF。其它所有值均是非法的,并且对输出不起作用。请求PDU说明了强制的线圈地址。从零开始寻址线圈。因此,寻址线圈1 为0。线圈值域的常量说明请求的ON/OFF 状态。十六进制值0XFF00请求线圈为ON。十六进制值0X0000请求线圈为OFF。其它所有值均为非法的,并且对线圈不起作用。

正常响应是请求的应答,在写入线圈状态之后返回这个正常响应。

写单个线圈状态图

/* 写单个线圈 */
eMBException eMBFuncWriteCoil(UCHAR *pucFrame, USHORT *usLen)
{
	USHORT usRegAddress;
	UCHAR ucBuf[2];
	eMBException eStatus = MB_EX_NONE;
	eMBErrorCode eRegStatus;

	/* 校验PDU长度是否合理 */
	if(*usLen == (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN))
	{
		/* 线圈地址 */
		usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8);
		usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1]);
		/* 第1个线圈寻址为0,所以地址加一 */
		usRegAddress++;

		/* 判断值是否合法,ON:0xFF00 OFF:0x0000 */
		if((pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00) &&
			 ((pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF) ||
				(pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00)))
		{
			/* 将ON/OFF转换为位1/0 */
			ucBuf[1] = 0;
			if(pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF)
			{
				ucBuf[0] = 1;
			}
			else
			{
				ucBuf[0] = 0;
			}
			/* 写入线圈值 */
			eRegStatus = eMBRegCoilsCB(&ucBuf[0], usRegAddress, 1, MB_REG_WRITE);
			/* 产生异常 */
			if(eRegStatus != MB_ENOERR)
			{
				/* 错误转化为异常码 */
				eStatus = prveMBError2Exception(eRegStatus);
			}
		}
		/* 状态值错误 */
		else
		{
			/* 非法数据值 */
			eStatus = MB_EX_ILLEGAL_DATA_VALUE;
		}
	}
	/* PDU长度不对 */
	else
	{
		/* 非法数据值 */
		eStatus = MB_EX_ILLEGAL_DATA_VALUE;
	}

	return eStatus;
}

写多个线圈(0x0F)

在一个远程设备中,使用该功能码强制线圈序列中的每个线圈为ON 或OFF。请求PDU说明了强制的线圈参考。从零开始寻址线圈。因此,寻址线圈1 为0。请求数据域的内容说明了被请求的ON/OFF 状态。域比特位置中的逻辑“1”请求相应输出为ON。域比特位置中的逻辑“0”请求相应输出为OFF。

正常响应返回功能码、起始地址和强制的线圈数量。

写多个线圈状态图

/* 写多个线圈 */
eMBException eMBFuncWriteMultipleCoils(UCHAR *pucFrame, USHORT *usLen)
{
	USHORT usRegAddress;
	USHORT usCoilCnt;
	UCHAR ucByteCount;
	UCHAR ucByteCountVerify;
	eMBException eStatus = MB_EX_NONE;
	eMBErrorCode eRegStatus;

	/* 校验PDU长度是否合理 */
	if(*usLen > (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN))
	{
		/* 线圈地址 */
		usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8);
		usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1]);
		/* 第1个线圈寻址为0,所以地址加一 */
		usRegAddress++;

		/* 线圈数量 */
		usCoilCnt = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8);
		usCoilCnt |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1]);

		/* 字节数 */
		ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];

		/* 计算字节数 */
		if((usCoilCnt & 0x0007) != 0)
		{
			ucByteCountVerify = (UCHAR)(usCoilCnt / 8 + 1);
		}
		else
		{
			ucByteCountVerify = (UCHAR)(usCoilCnt / 8);
		}

		/* 检查线圈数量和字节数是否合理 */
		if((usCoilCnt >= 1) &&
			 (usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX) &&
			 (ucByteCountVerify == ucByteCount))
		{
			/* 写入线圈值 */
			eRegStatus = eMBRegCoilsCB(&pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
																 usRegAddress, usCoilCnt, MB_REG_WRITE);
			/* 产生异常 */
			if(eRegStatus != MB_ENOERR)
			{
				/* 错误转化为异常码 */
				eStatus = prveMBError2Exception(eRegStatus);
			}
			/* 未产生异常 */
			else
			{
				/* 数据长度 */
				*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
			}
		}
		/* 线圈数量或字节数不合理 */
		else
		{
			/* 非法数据值 */
			eStatus = MB_EX_ILLEGAL_DATA_VALUE;
		}
	}
	/* PDU长度不对 */
	else
	{
		/* 非法数据值 */
		eStatus = MB_EX_ILLEGAL_DATA_VALUE;
	}

	return eStatus;
}
发布了208 篇原创文章 · 获赞 90 · 访问量 25万+

猜你喜欢

转载自blog.csdn.net/lushoumin/article/details/89110602