当前位置:首页 > 芯闻号 > 充电吧
[导读]计算机上面使用Modbus读取传感器或相关设备还是比较常用的,之前写的Modbus-RTU协议将串口封装到了协议栈内,使用的时候遇到短板了,比如我最新需要使用TCP来读取Modbus设备,就不好用了,

计算机上面使用Modbus读取传感器或相关设备还是比较常用的,之前写的Modbus-RTU协议将串口封装到了协议栈内,使用的时候遇到短板了,比如我最新需要使用TCP来读取Modbus设备,就不好用了,通过回调函数可以很简单的解决这个问题。


//modbus-rtu.c


/*************************************************************************************************************
 * 文件名:		MODBUS_RTU.c
 * 功能:			MODBUS_RTU通信协议层
 * 作者:			cp1300@139.com
 * 创建时间:		2014-03-24
 * 最后修改时间:	2016-11-04
 * 详细:			MODBUS RTU通信协议层
				2016-03-21:增加防止接收数据过短导致异常
				2016-11-04:增加回调接口,将数据收发接口使用回调函数
*************************************************************************************************************/
#include "StdAfx.h"
#include "MODBUS_RTU.h"
#include "windows.h"

using namespace System;

/*************************************************************************************************************************
* 函数		:	bool MODBUS_RTU::ReadMultRegPack(BYTE *pPackBuff, DWORD *pPackLen, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, char **pError)
* 功能		:	主机读取从机指定多个连续寄存器数据打包
* 参数		:	pPackBuff:打包缓冲区,pPackLen:打包的数据长度;RegType:读取的寄存器类型;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegNum:寄存器数量;pError:返回错误说明
* 返回		:	true:成功;false:错误
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	数据打包,不涉及发送
*************************************************************************************************************************/
bool MODBUS_RTU::ReadMultRegPack(BYTE *pPackBuff, DWORD *pPackLen, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, char **pError)
{
	MRTU_READ_FRAME *pFrame;		//发送数据帧格式
	u16 crc16;

	if (pPackBuff == nullptr)		//缓冲区无效
	{
		*pPackLen = 0;
		if (pError != nullptr) *pError = "缓冲区无效!";
		return false;	//句柄无效
	}
		
	pFrame = (MRTU_READ_FRAME *)pPackBuff;
	//数据结构填充
	pFrame->addr = SlaveAddr;						//从机地址
	pFrame->fun = (u8)RegType;						//功能码,读取
	pFrame->StartReg = SWAP16(RegAddr);				//寄存器起始地址
	if ((RegNum > 127) || (RegNum == 0))
	{
		if (pError != nullptr) *pError = "一次读取的寄存器数量超出范围!";
		return false;								//寄存器数量错误
	}	
	pFrame->RegNum = SWAP16(RegNum);				//需要读取的寄存器数量
	crc16 = usMBCRC16(pPackBuff, 6);				//计算CRC16
	pFrame->CRC16 = crc16;							//crc16
	*pPackLen = 6+2;

	if (pError != nullptr) *pError = "打包成功!";
	return true;
}




/*************************************************************************************************************************
* 函数		:	MRTU_ERROR  MODBUS_RTU::ReadMultRegUnpack(BYTE *pPackBuff, DWORD PackLen, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[], char **pError)
* 功能		:	主机读取从机指定多个连续寄存器数据解包
* 参数		:	pPackBuff:数据包缓冲区;PackLen:数据包大小;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegNum:寄存器数量;pRegData:返回寄存器的值,至少为RegNum的2倍
					返回的寄存器的值按照循序存放在pRegData中
* 返回		:	MRTU_ERROR:通信状态
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	数据包解析
*************************************************************************************************************************/
MRTU_ERROR  MODBUS_RTU::ReadMultRegUnpack(BYTE *pPackBuff, DWORD PackLen, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[], char **pError)
{
	MRTU_RETURN_FRAME *pReFrame;	//返回数据帧格式
	MRTU_UNU_FRAME	*pUnuFrame;		//返回的异常数据帧格式
	u16 crc16;
	u16 i;

	if (pPackBuff == nullptr)		//缓冲区无效
	{
		if (pError != nullptr) *pError = "缓冲区无效!";
		return MRTU_HANDLE_ERROR;	//句柄无效
	}

	if (PackLen < 3) 
	{
		if (pError != nullptr) *pError = "返回数据长度过短!";
		return MRTU_LEN_ERROR;	//返回数据长度错误
	}
	
	pReFrame = (MRTU_RETURN_FRAME *)pPackBuff;
	//检查地址
	if (pReFrame->addr != SlaveAddr)
	{
		if (pError != nullptr) *pError = "返回的从机地址错误!";
		return MRTU_ADDR_ERROR;
	}
	//对接受的数据进行CRC校验
	crc16 = usMBCRC16(pPackBuff, PackLen - 2);//计算CRC16
	if ((pPackBuff[PackLen - 1] != (crc16 >> 8)) || (pPackBuff[PackLen - 2] != (crc16 & 0xff)))
	{
		if (pError != nullptr) *pError = "CRC校验错误";
		return MRTU_CRC_ERROR;				//返回CRC校验错误
	}

	//返回的功能码不一致
	if (pReFrame->fun != (u8)RegType)
	{
		pUnuFrame = (MRTU_UNU_FRAME *)pPackBuff;				//异常数据帧
		if (pUnuFrame->ErrorFun == ((u8)RegType | 0x80))		//返回有异常
		{
			switch (pUnuFrame->unu)
			{
				case 1: //异常码1
				{
					if (pError != nullptr) *pError = "返回异常码1!";
					return MRTU_UNUS1_ERROR;			
				}
				case 2: //异常码2
				{
					if (pError != nullptr) *pError = "返回异常码2!";
						return MRTU_UNUS2_ERROR;
				}
				case 3: //异常码3
				{
					if (pError != nullptr) *pError = "返回异常码3!";
					return MRTU_UNUS3_ERROR;
				}
				case 4: //异常码4
				{
					if (pError != nullptr) *pError = "返回异常码4!";
					return MRTU_UNUS4_ERROR;
				}
				case 5://异常码5
				{
					if (pError != nullptr) *pError = "返回异常码5!";
					return MRTU_UNUS5_ERROR;
				}
				case 6://异常码6
				{
					if (pError != nullptr) *pError = "返回异常码6!";
					return MRTU_UNUS6_ERROR;
				}
				default:
				{
					if (pError != nullptr) *pError = "返回未知异常码!";
					return MRTU_OTHER_ERROR;
				}
			}
		}
		else
		{
			if (pError != nullptr) *pError = "返回功能码错误!";
			return MRTU_FUNR_ERROR;
		}
	}
	//判断数据长度
	if (pReFrame->DataLen != (RegNum * 2))
	{
		if (pError != nullptr) *pError = "返回数据长度错误,长度小于需要读取的寄存器数量x2!";
		return MRTU_LEN_ERROR;				//返回数据长度错误
	}
	//获取返回的寄存器的值
	for (i = 0; i < RegNum; i++)
	{
		pRegData[i] = pReFrame->DataBuff[i * 2];
		pRegData[i] <DataBuff[i * 2 + 1];
	}

	if (pError != nullptr) *pError = "读取成功!";
	return MRTU_OK;						//返回成功 
}




/*************************************************************************************************************************
* 函数		:	bool WriteOnetRegPack(BYTE *pPackBuff, DWORD *pPackLen, u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError)
* 功能		:	主机写从机一个指定寄存器数据打包
* 参数		:	pPackBuff:打包缓冲区,pPackLen:打包的数据长度;SlaveAddr:从机地址;RegAddr:写寄存器地址;RegData:寄存器的值;pError:错误提示
* 返回		:	true:成功;false:错误
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	数据打包,不涉及发送
*************************************************************************************************************************/
bool MODBUS_RTU::WriteOnetRegPack(BYTE *pPackBuff, DWORD *pPackLen, u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError)
{
	MRTU_WRITE_FRAME *pFrame;//发送数据帧格式
	u16 crc16;


	if (pPackBuff == nullptr)		//缓冲区无效
	{
		*pPackLen = 0;
		if (pError != nullptr) *pError = "缓冲区无效!";
		return false;	//句柄无效
	}

	pFrame = (MRTU_WRITE_FRAME *)pPackBuff;
	//数据结构填充
	pFrame->addr = SlaveAddr;						//从机地址
	pFrame->fun = (u8)MRTU_FUN_WRITE;				//功能码,预置单个寄存器
	pFrame->StartReg = SWAP16(RegAddr);				//寄存器起始地址
	pFrame->RegData = SWAP16(RegData);				//写入寄存器内容
	pFrame->crc16 = usMBCRC16(pPackBuff, 6);		//计算CRC16
	*pPackLen = 6+2;

	if (pError != nullptr) *pError = "打包成功!";
	return true;
}





/*************************************************************************************************************************
* 函数		:	MRTU_ERROR MODBUS_RTU::WriteOneRegUnpack(BYTE *pPackBuff, DWORD PackLen, u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError)
* 功能		:	主机写从机一个指定寄存器数据解包
* 参数		:	pPackBuff:打包缓冲区,pPackLen:打包的数据长度;SlaveAddr:从机地址;RegAddr:写寄存器地址;RegData:寄存器的值;RegData:需要写入的值;pError:错误说明
* 返回		:	MRTU_ERROR:通信状态
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	数据包解包
*************************************************************************************************************************/
MRTU_ERROR MODBUS_RTU::WriteOneRegUnpack(BYTE *pPackBuff, DWORD PackLen, u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError)
{
	MRTU_WRITE_FRAME *pReFrame;//发送数据帧格式
	MRTU_UNU_FRAME	*pUnuFrame;			//返回的异常数据帧格式
	u16 crc16;

	if (pPackBuff == nullptr)		//缓冲区无效
	{
		if (pError != nullptr) *pError = "缓冲区无效!";
		return MRTU_HANDLE_ERROR;	//句柄无效
	}
	if (PackLen < 3)
	{
		if (pError != nullptr) *pError = "返回数据长度过短!";
		return MRTU_LEN_ERROR;	//返回数据长度错误
	}

	pReFrame = (MRTU_WRITE_FRAME *)pPackBuff;
	//检查地址
	if (pReFrame->addr != SlaveAddr)
	{
		if (pError != nullptr) *pError = "返回的从机地址错误!";
		return MRTU_ADDR_ERROR;
	}
	//对接受的数据进行CRC校验
	crc16 = usMBCRC16(pPackBuff, PackLen - 2);//计算CRC16
	if ((pPackBuff[PackLen - 1] != (crc16 >> 8)) || (pPackBuff[PackLen - 2] != (crc16 & 0xff)))
	{
		if (pError != nullptr) *pError = "CRC校验错误";
		return MRTU_CRC_ERROR;				//返回CRC校验错误
	}
	//返回的功能码不一致
	if (pReFrame->fun != (u8)MRTU_FUN_WRITE)
	{
		pUnuFrame = (MRTU_UNU_FRAME *)pPackBuff;		//异常数据帧
		if (pUnuFrame->ErrorFun == ((u8)MRTU_FUN_WRITE | 0x80))//返回有异常
		{
			switch (pUnuFrame->unu)
			{
				case 1: //异常码1
				{
					if (pError != nullptr) *pError = "返回异常码1!";
					return MRTU_UNUS1_ERROR;
				}
				case 2: //异常码2
				{
					if (pError != nullptr) *pError = "返回异常码2!";
					return MRTU_UNUS2_ERROR;
				}
				case 3: //异常码3
				{
					if (pError != nullptr) *pError = "返回异常码3!";
					return MRTU_UNUS3_ERROR;
				}
				case 4: //异常码4
				{
					if (pError != nullptr) *pError = "返回异常码4!";
					return MRTU_UNUS4_ERROR;
				}
				case 5://异常码5
				{
					if (pError != nullptr) *pError = "返回异常码5!";
					return MRTU_UNUS5_ERROR;
				}
				case 6://异常码6
				{
					if (pError != nullptr) *pError = "返回异常码6!";
					return MRTU_UNUS6_ERROR;
				}
				default:
				{
					if (pError != nullptr) *pError = "返回未知异常码!";
					return MRTU_OTHER_ERROR;
				}
			}
		}
		else
		{
			if (pError != nullptr) *pError = "返回功能码错误!";
			return MRTU_FUNR_ERROR;
		}
	}
	//判断数据是否写入
	if (SWAP16(pReFrame->StartReg) != RegAddr)	//返回的寄存器地址不一致
	{
		if (pError != nullptr) *pError = "返回寄存器地址错误!";
		return MRTU_REG_ERROR;					//返回寄存器错误
	}
	if (SWAP16(pReFrame->RegData) != RegData)
	{
		if (pError != nullptr) *pError = "数据写入错误,没有写入成功!";
		return MRTU_WRITE_ERROR;				//写入数据错误
	}

	if (pError != nullptr) *pError = "写入成功!";
	return MRTU_OK;								//返回成功 
}





/*************************************************************************************************************************
* 函数		:	MRTU_ERROR MODBUS_RTU::WriteMultRegPack(BYTE *pPackBuff, DWORD *pPackLen, u8 SlaveAddr, u16 RegAddr, u16 pRegData[], u8 RegNum, , char **pError)
* 功能		:	主机写从机多个指定寄存器数据打包
* 参数		:	pPackBuff:打包缓冲区,pPackLen:打包的数据长度;SlaveAddr:从机地址;RegAddr:写寄存器地址;pRegData:需要写入的寄存器的值;RegNum:寄存器数量;pError:错误说明
* 返回		:	true:成功;false:错误
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	写多个寄存器数据打包
				写入寄存器的值按照循序排列,使用小端格式,大小必须为RegNum*2
				最大只能一次写入不超过127个寄存器
*************************************************************************************************************************/
bool MODBUS_RTU::WriteMultRegPack(BYTE *pPackBuff, DWORD *pPackLen, u8 SlaveAddr, u16 RegAddr, u16 pRegData[], u8 RegNum, char **pError)
{
	MRTU_WRITE_MULT_FRAME *pFrame;					//发送数据帧格式
	DWORD i;
	WORD crc16;

	if (pPackBuff == nullptr)		//缓冲区无效
	{
		*pPackLen = 0;
		if (pError != nullptr) *pError = "缓冲区无效!";
		return false;	//句柄无效
	}
	pFrame = (MRTU_WRITE_MULT_FRAME *)pPackBuff;
	//数据结构填充
	pFrame->addr = SlaveAddr;						//从机地址
	pFrame->fun = (u8)MRTU_FUN_MWRITE;				//功能码,预置多个寄存器
	pFrame->StartReg = SWAP16(RegAddr);				//寄存器起始地址
	if ((RegNum > 127) || (RegNum == 0))
	{
		*pPackLen = 0;
		if (pError != nullptr) *pError = "一次写入寄存器数量过多!";
		return FALSE;	//寄存器数量错误
	}
		
	pFrame->RegNum = SWAP16(RegNum);				//写入寄存器数量
	pFrame->DataLen = 2 * RegNum;						//数据长度
	//循环写入数据
	for (i = 0; i < RegNum; i++)
	{
		pFrame->DataBuff[2 * i] = pRegData[i] >> 8;		//高位
		pFrame->DataBuff[2 * i + 1] = pRegData[i] & 0xff;	//低位
	}
	crc16 = usMBCRC16(pPackBuff, 7 + pFrame->DataLen);	//计算CRC16,高低位对调过
	pFrame->DataBuff[pFrame->DataLen] = crc16 & 0xff;	//高位
	pFrame->DataBuff[pFrame->DataLen + 1] = crc16 >> 8;	//低位
	*pPackLen = 7 + pFrame->DataLen + 2;

	if (pError != nullptr) *pError = "打包成功!";
	return true;
}




/*************************************************************************************************************************
* 函数		:	MRTU_ERROR MODBUS_RTU::WriteMultRegUnpack(BYTE *pPackBuff, DWORD PackLen, u8 SlaveAddr, u16 RegAddr, u8 RegNum, char **pError)
* 功能		:	主机写从机多个指定寄存器数据解包
* 参数		:	pPackBuff:打包缓冲区,pPackLen:打包的数据长度;SlaveAddr:从机地址;RegAddr:写寄存器地址;RegNum:寄存器数量;pError:错误说明
* 返回		:	MRTU_ERROR
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间:	2016-11-04
* 说明		: 	写多个寄存器数据解包
*************************************************************************************************************************/
MRTU_ERROR MODBUS_RTU::WriteMultRegUnpack(BYTE *pPackBuff, DWORD PackLen, u8 SlaveAddr, u16 RegAddr, u8 RegNum, char **pError)
{
	MRTU_WRIT_EMULT_RFRAME *pReFrame;				//返回数据帧格式
	MRTU_UNU_FRAME	*pUnuFrame;						//返回的异常数据帧格式
	u16 crc16;
	u8 i;

	if (pPackBuff == nullptr)		//缓冲区无效
	{
		if (pError != nullptr) *pError = "缓冲区无效!";
		return MRTU_HANDLE_ERROR;	//句柄无效
	}
	if (PackLen < 3)
	{
		if (pError != nullptr) *pError = "返回数据长度过短!";
		return MRTU_LEN_ERROR;	//返回数据长度错误
	}

	pReFrame = (MRTU_WRIT_EMULT_RFRAME *)pPackBuff;
	//检查地址
	if (pReFrame->addr != SlaveAddr)
	{
		if (pError != nullptr) *pError = "返回的从机地址错误!";
		return MRTU_ADDR_ERROR;
	}
	//对接受的数据进行CRC校验
	crc16 = usMBCRC16(pPackBuff, PackLen - 2);//计算CRC16
	if ((pPackBuff[PackLen - 1] != (crc16 >> 8)) || (pPackBuff[PackLen - 2] != (crc16 & 0xff)))
	{
		if (pError != nullptr) *pError = "CRC校验错误";
		return MRTU_CRC_ERROR;				//返回CRC校验错误
	}
	//返回的功能码不一致
	if (pReFrame->fun != (u8)MRTU_FUN_MWRITE)
	{
		pUnuFrame = (MRTU_UNU_FRAME *)pPackBuff;		//异常数据帧
		if (pUnuFrame->ErrorFun == ((u8)MRTU_FUN_MWRITE | 0x80))//返回有异常
		{
			switch (pUnuFrame->unu)
			{
				case 1: //异常码1
				{
					if (pError != nullptr) *pError = "返回异常码1!";
					return MRTU_UNUS1_ERROR;
				}
				case 2: //异常码2
				{
					if (pError != nullptr) *pError = "返回异常码2!";
					return MRTU_UNUS2_ERROR;
				}
				case 3: //异常码3
				{
					if (pError != nullptr) *pError = "返回异常码3!";
					return MRTU_UNUS3_ERROR;
				}
				case 4: //异常码4
				{
					if (pError != nullptr) *pError = "返回异常码4!";
					return MRTU_UNUS4_ERROR;
				}
				case 5://异常码5
				{
					if (pError != nullptr) *pError = "返回异常码5!";
					return MRTU_UNUS5_ERROR;
				}
				case 6://异常码6
				{
					if (pError != nullptr) *pError = "返回异常码6!";
					return MRTU_UNUS6_ERROR;
				}
				default:
				{
					if (pError != nullptr) *pError = "返回未知异常码!";
					return MRTU_OTHER_ERROR;
				}
			}
		}
		else
		{
			if (pError != nullptr) *pError = "返回功能码错误!";
			return MRTU_FUNR_ERROR;
		}
	}
	//判断数据是否写入
	if (SWAP16(pReFrame->StartReg) != RegAddr)	//返回的寄存器地址不一致
	{
		if (pError != nullptr) *pError = "返回寄存器地址错误!";
		return MRTU_REG_ERROR;					//返回寄存器错误
	}
	if (SWAP16(pReFrame->RegNum) != RegNum)
	{
		if (pError != nullptr) *pError = "数据写入错误,返回的寄存器数量不一致!";
		return MRTU_WRITE_ERROR;				//写入数据错误
	}

	if (pError != nullptr) *pError = "写入成功!";
	return MRTU_OK;								//返回成功 
}




/*************************************************************************************************************************
* 函数		:	MRTU_ERROR MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
* 功能		:	主机读取从机指定多个连续寄存器(需要初始化回调通信接口)
* 参数		:	RegType:读取的寄存器类型;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegNum:寄存器数量;pRegData:返回寄存器的值,至少为RegNum的2倍;pError:错误信息
* 返回		:	MRTU_ERROR:通信状态
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	输入输出的数据都为小端模式
				返回的寄存器的值按照循序存放在pRegData中
				需要先初始化通信接口,并且会申请 MODBUS_RTU_PACK_MAX_SIZE+1 字节堆内存用于支持可重入
*************************************************************************************************************************/
MRTU_ERROR  MODBUS_RTU::ReadMultReg(READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[], char **pError)
{
	BYTE PackBuff[MODBUS_RTU_PACK_MAX_SIZE+1];
	DWORD len;

	if (ReadMultRegPack(PackBuff, &len, RegType, SlaveAddr, RegAddr, RegNum, pError) == false)
	{
		return MRTU_HANDLE_ERROR;
	}
	//调用回调进行
	if (this->pSendDataCollBack == nullptr)
	{
		if (pError == nullptr) *pError = "发送回调函数无效!";
		return MRTU_HANDLE_ERROR;
	}
	try
	{
		if (this->pSendDataCollBack(PackBuff, len) == false)
		{
			if (pError == nullptr) *pError = "发送数据失败!";
			return MRTU_SEND_ERROR;
		}
	}
	catch (Exception^ e)
	{
		if (pError == nullptr) *pError = "发送数据发生了异常!";
		return MRTU_SEND_ERROR;
	}
	//发送完成了,调用接收回调进行数据接收
	if (this->pReadDataCollBack == nullptr)
	{
		if (pError == nullptr) *pError = "接收回调函数无效!";
		return MRTU_READ_ERROR;
	}
	try
	{
		if (this->pReadDataCollBack(PackBuff, &len) == false)
		{
			if (pError == nullptr) *pError = "接收数据失败!";
			return MRTU_READ_ERROR;
		}
	}
	catch (Exception^ e)
	{
		if (pError == nullptr) *pError = "接收数据发生了异常!";
		return MRTU_READ_ERROR;
	}
	if (len == 0)
	{
		if (pError == nullptr) *pError = "接收数据超时!";
		return MRTU_TIME_OUT;
	}
	if (len > (256 + 7))
	{
		if (pError == nullptr) *pError = "接收数据溢出!";
		return MRTU_OVER_ERROR;
	}
	//数据接收完成了,开始解析
	return ReadMultRegUnpack(PackBuff, len, RegType, SlaveAddr,RegAddr, RegNum, pRegData, pError);
}



/*************************************************************************************************************************
* 函数		:	MRTU_ERROR MODBUS_RTU::WriteOnetReg(u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError)
* 功能		:	主机写入从机一个寄存器(需要初始化回调通信接口)
* 参数		:	SlaveAddr:从机地址;RegAddr:写寄存器地址;RegData:寄存器的值;pError:错误提示
* 返回		:	MRTU_ERROR:通信状态
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间	:	2016-11-04
* 说明		: 	输入输出的数据都为小端模式
				需要先初始化通信接口,并且会申请 MODBUS_RTU_PACK_MAX_SIZE+1 字节堆内存用于支持可重入
*************************************************************************************************************************/
MRTU_ERROR MODBUS_RTU::WriteOnetReg(u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError)
{
	BYTE PackBuff[MODBUS_RTU_PACK_MAX_SIZE + 1];
	DWORD len;

	if (WriteOnetRegPack(PackBuff, &len, SlaveAddr, RegAddr, RegData, pError) == false)
	{
		return MRTU_HANDLE_ERROR;
	}
	//调用回调进行
	if (this->pSendDataCollBack == nullptr)
	{
		if (pError == nullptr) *pError = "发送回调函数无效!";
		return MRTU_HANDLE_ERROR;
	}
	try
	{
		if (this->pSendDataCollBack(PackBuff, len) == false)
		{
			if (pError == nullptr) *pError = "发送数据失败!";
			return MRTU_SEND_ERROR;
		}
	}
	catch (Exception^ e)
	{
		if (pError == nullptr) *pError = "发送数据发生了异常!";
		return MRTU_SEND_ERROR;
	}
	//发送完成了,调用接收回调进行数据接收
	if (this->pReadDataCollBack == nullptr)
	{
		if (pError == nullptr) *pError = "接收回调函数无效!";
		return MRTU_READ_ERROR;
	}
	try
	{
		if (this->pReadDataCollBack(PackBuff, &len) == false)
		{
			if (pError == nullptr) *pError = "接收数据失败!";
			return MRTU_READ_ERROR;
		}
	}
	catch (Exception^ e)
	{
		if (pError == nullptr) *pError = "接收数据发生了异常!";
		return MRTU_READ_ERROR;
	}
	if (len == 0)
	{
		if (pError == nullptr) *pError = "接收数据超时!";
		return MRTU_TIME_OUT;
	}
	if (len > (256 + 7))
	{
		if (pError == nullptr) *pError = "接收数据溢出!";
		return MRTU_OVER_ERROR;
	}
	//数据接收完成了,开始解析
	return WriteOneRegUnpack(PackBuff, len, SlaveAddr, RegAddr,  RegData, pError);
}


/*************************************************************************************************************************
* 函数		:	MRTU_ERROR MODBUS_RTU::WriteMultReg(u8 SlaveAddr, u16 RegAddr, u16 pRegData[],u8 RegNum,  char **pError)
* 功能		:	主机写从机多个指定寄存器(需要初始化回调通信接口)
* 参数		:	SlaveAddr:从机地址;RegAddr:写寄存器地址;RegNum:寄存器数量;pError:错误说明
* 返回		:	MRTU_ERROR
* 依赖		:	底层通信驱动
* 作者		:	cp1300@139.com
* 时间		:	2014-03-24
* 最后修改时间:	2016-11-04
* 说明		: 	写多个寄存器数据解包
*************************************************************************************************************************/
MRTU_ERROR MODBUS_RTU::WriteMultReg(u8 SlaveAddr, u16 RegAddr, u16 pRegData[],u8 RegNum,  char **pError)
{
	BYTE PackBuff[MODBUS_RTU_PACK_MAX_SIZE + 1];
	DWORD len;

	if (WriteMultRegPack(PackBuff, &len, SlaveAddr, RegAddr, pRegData, RegNum, pError) == false)
	{
		return MRTU_HANDLE_ERROR;
	}
	//调用回调进行
	if (this->pSendDataCollBack == nullptr)
	{
		if (pError == nullptr) *pError = "发送回调函数无效!";
		return MRTU_HANDLE_ERROR;
	}
	try
	{
		if (this->pSendDataCollBack(PackBuff, len) == false)
		{
			if (pError == nullptr) *pError = "发送数据失败!";
			return MRTU_SEND_ERROR;
		}
	}
	catch (Exception^ e)
	{
		if (pError == nullptr) *pError = "发送数据发生了异常!";
		return MRTU_SEND_ERROR;
	}
	//发送完成了,调用接收回调进行数据接收
	if (this->pReadDataCollBack == nullptr)
	{
		if (pError == nullptr) *pError = "接收回调函数无效!";
		return MRTU_READ_ERROR;
	}
	try
	{
		if (this->pReadDataCollBack(PackBuff, &len) == false)
		{
			if (pError == nullptr) *pError = "接收数据失败!";
			return MRTU_READ_ERROR;
		}
	}
	catch (Exception^ e)
	{
		if (pError == nullptr) *pError = "接收数据发生了异常!";
		return MRTU_READ_ERROR;
	}
	if (len == 0)
	{
		if (pError == nullptr) *pError = "接收数据超时!";
		return MRTU_TIME_OUT;
	}
	if (len > (256 + 7))
	{
		if (pError == nullptr) *pError = "接收数据溢出!";
		return MRTU_OVER_ERROR;
	}
	//数据接收完成了,开始解析
	return WriteMultRegUnpack(PackBuff, len, SlaveAddr, RegAddr, RegNum, pError);
}




//MODBUS CRC16计算
//结果为大端模式
BIG_U16  MODBUS_RTU::usMBCRC16( u8 * pucFrame, u16 usLen )
{
	static const u8 aucCRCHi[] = {
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40
	};

	static const u8 aucCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
    0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 
    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 
    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
    0x41, 0x81, 0x80, 0x40
	};

    u8           ucCRCHi = 0xFF;
    u8           ucCRCLo = 0xFF;
    int             iIndex;
	

    while( usLen-- )
    {
        iIndex = ucCRCLo ^ *( pucFrame++ );
        ucCRCLo = ( u8 )( ucCRCHi ^ aucCRCHi[iIndex] );
        ucCRCHi = aucCRCLo[iIndex];
    }
    return ( u16 )( ucCRCHi << 8 | ucCRCLo );
}




//modbus-rtu.h


/*************************************************************************************************************
* 文件名:			MODBUS_RTU.h
* 功能:			MODBUS_RTU通信协议层
* 作者:			cp1300@139.com
* 创建时间:		2014-03-24
* 最后修改时间:	2016-11-04
* 详细:			MODBUS RTU通信协议层
2016-03-21:增加防止接收数据过短导致异常
2016-11-04:增加回调接口,将数据收发接口使用回调函数
*************************************************************************************************************/
#ifndef _MODBUS_RTU_H_
#define _MODBUS_RTU_H_

#include "windows.h"

//基本数据类型定义
#ifndef u8
#define u8 BYTE
#endif //u8
#ifndef u16
#define u16 WORD
#endif //u16
#ifndef u32
#define u32 DWORD
#endif //u32
#ifndef s16
#define s16 INT16
#endif //s16
#ifndef s32
#define s32 int
#endif //s32


//16位整形数高低对调
#define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))

//最大数据包大小
#define MODBUS_RTU_PACK_MAX_SIZE		300

//支持的功能码
#define MRTU_FUN_READ_HOLD		0x03			//读保持寄存器,可读写寄存器为保持寄存器
#define MRTU_FUN_READ_INPUT		0x04			//读输入寄存器,为只读寄存器
#define MRTU_FUN_WRITE			0x06			//写单个保持寄存器
#define MRTU_FUN_MWRITE			0x10			//写多个保持寄存器

//大端数据标记
#define BIG_U16		u16							//16位整形数,需要转换为大端模式,兼容modubus




//读取寄存器类型选择
typedef enum
{
	HOLD_REG 	= 	MRTU_FUN_READ_HOLD,			//保持寄存器
	INPUT_REG	=	MRTU_FUN_READ_INPUT,		//输入寄存器
} READ_REG_TYPE;


//数据读取 主机数据帧,主机读取从机的数据帧
typedef  struct
{
	u8	addr;				//地址 address
	u8	fun;				//功能码 function
	BIG_U16	StartReg;		//数据起始地址
	BIG_U16	RegNum;			//需要读取的寄存器个数
	BIG_U16	CRC16;			//CRC16
} MRTU_READ_FRAME;			//MODBUS RTU master Read Reg Frame



//预置单个保持寄存器,主机写从机单个寄存器的数据帧
//从机返回数据帧与主机预置单个寄存器数据帧一样
typedef  struct
{
	u8	addr;				//地址 address
	u8	fun;				//功能码 function
	BIG_U16	StartReg;		//数据起始地址
	BIG_U16	RegData;		//数据值
	BIG_U16 crc16;			//CRC校验值
} MRTU_WRITE_FRAME;			//MODBUS RTU master Write Reg Frame





//预置多个保持寄存器,主机写从机多个寄存器的数据帧
typedef  struct
{
	u8	addr;				//地址 address
	u8	fun;				//功能码 function
	BIG_U16	StartReg;		//数据起始地址
	BIG_U16	RegNum;			//寄存器数量
	u8	DataLen;			//数据长度
	u8	DataBuff[2];		//寄存器的值	
} MRTU_WRITE_MULT_FRAME;			


//预置多个保持寄存器后返回数据帧,从机返回主机的数据帧
typedef  struct
{
	u8	addr;				//地址 address
	u8	fun;				//功能码 function
	BIG_U16	StartReg;		//数据起始地址
	BIG_U16	RegNum;			//寄存器数量
	BIG_U16 crc16;			//CRC校验值
} MRTU_WRIT_EMULT_RFRAME;			


//读取从机返回数据帧格式,从机返回给主机的数据帧
typedef  struct
{
	u8	addr;				//地址 address
	u8	fun;				//功能码 function
	u8	DataLen;			//数据长度
	u8	DataBuff[2];		//数据区,CRC16放在最后结尾处
	//MRTU_REG16	CRC16;	//CRC16
} MRTU_RETURN_FRAME;	//MODBUS RTU master Read Reg Frame


//从机返回的异常数据帧,从机返回的异常数据帧
typedef  struct
{
	u8	addr;				//地址 address
	u8	ErrorFun;			//错误功能码 function+0x80
	u8	unu;				//异常码
	u8	crc16H;				//CRC16放在最后结尾处
	u8	crc16L;				//CRC16放在最后结尾处
} MRTU_UNU_FRAME;	


//从机数据包解析后的相关信息
typedef struct
{
	u8	SlaveAddr;	//主机发送的从机地址
	u8 	RegNum;		//主机需要读取从机的寄存器数量
	u8	fun;		//主机发送给从机的功能码
	u16 StartReg;	//主机需要读写的从机寄存器地址
} MRTU_SLAVE_INFO;


//异常码定义
typedef enum
{
	MRTU_UNUS1		=	0x01,	//异常码1,无效的操作码
	MRTU_UNUS2		=	0x02,	//异常码2,无效的数据地址
	MRTU_UNUS3		=	0x03,	//异常码3,无效的数据值
	MRTU_UNUS4		=	0x04,	//异常码4,无效操作
	MRTU_UNUS5		=	0x05,	//异常码5
	MRTU_UNUS6		=	0x06,	//异常码6
} MRTU_UNUS;


//错误状态
typedef enum
{
	MRTU_OK 				= 	0,		//OK
	MRTU_TIME_OUT 			= 	1,		//超时
	MRTU_OVER_ERROR 		= 	2,		//溢出
	MRTU_CRC_ERROR			=	3,		//CRC错误
	MRTU_ADDR_ERROR			=	4,		//地址错误,返回地址不一致
	MRTU_REG_ERROR			=	5,		//寄存器地址错误,返回寄存器地址不一致
	MRTU_FUNR_ERROR			=	6,		//功能码错误,返回功能码不一致或者不支持的功能码
	MRTU_HANDLE_ERROR		=	7,		//通信回调接口错误,或缓冲区错误
	MRTU_REGN_ERROR			=	8,		//寄存器数量错误
	MRTU_LEN_ERROR			=	9,		//返回数据长度错误
	MRTU_WRITE_ERROR		=	10,		//写寄存器错误,写入与读取不一致
	MRTU_SEND_ERROR			=	11,		//发送数据失败
	MRTU_READ_ERROR			=	12,		//读取数据失败
	MRTU_UNUS1_ERROR		=	0x81,	//异常码1,无效的操作码
	MRTU_UNUS2_ERROR		=	0x82,	//异常码2,无效的数据地址
	MRTU_UNUS3_ERROR		=	0x83,	//异常码3,无效的数据值
	MRTU_UNUS4_ERROR		=	0x84,	//异常码4,无效操作
	MRTU_UNUS5_ERROR		=	0x85,	//异常码5
	MRTU_UNUS6_ERROR		=	0x86,	//异常码6
	MRTU_OTHER_ERROR = 0xff
} MRTU_ERROR;


//发送回调函数定义
typedef bool(*MODBUS_SendDataCollBack)(BYTE *, DWORD);			//发送缓冲区与发送数据大小;返回:发送成功返回true,发送失败返回false
//接收回调函数定义
typedef bool(*MODBUS_ReadDataCollBack)(BYTE *, DWORD *);			//接收缓冲区与接收数据长度;返回:读取成功返回true,读取失败,接口错误返回false,返回true后数据长度为0算作超时,返回false一般都是接口错误



class MODBUS_RTU
{
private:
	MODBUS_SendDataCollBack pSendDataCollBack;	//发送回调函数指针
	MODBUS_ReadDataCollBack pReadDataCollBack;	//接收回调函数指针
	u16 usMBCRC16(u8 * pucFrame, u16 usLen);	//crc计算

public:
	//数据包打包与解包接口-不涉及到数据发送与接收
	bool ReadMultRegPack(BYTE *pPackBuff, DWORD *pPackLen, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, char **pError);
	MRTU_ERROR ReadMultRegUnpack(BYTE *pPackBuff, DWORD PackLen, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[], char **pError);
	bool WriteOnetRegPack(BYTE *pPackBuff, DWORD *pPackLen, u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError);
	MRTU_ERROR WriteOneRegUnpack(BYTE *pPackBuff, DWORD PackLen, u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError);
	bool WriteMultRegPack(BYTE *pPackBuff, DWORD *pPackLen, u8 SlaveAddr, u16 RegAddr, u16 pRegData[], u8 RegNum, char **pError);
	MRTU_ERROR WriteMultRegUnpack(BYTE *pPackBuff, DWORD PackLen, u8 SlaveAddr, u16 RegAddr, u8 RegNum, char **pError);

	//带回调模式通信接口初始化
	//pSendDataCollBack:发送回调函数指针;pReadDataCollBack:接收回调函数指针;TimeOut:接收超时时间
	void MODBUS_RTU::InterfaceInit(MODBUS_SendDataCollBack pSendDataCollBack, MODBUS_ReadDataCollBack pReadDataCollBack)
	{
		this->pSendDataCollBack = pSendDataCollBack;	//发送回调函数指针
		this->pReadDataCollBack = pReadDataCollBack;	//接收回调函数指针
	}
	MRTU_ERROR ReadMultReg(READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[], char **pError);
	MRTU_ERROR WriteOnetReg(u8 SlaveAddr, u16 RegAddr, u16 RegData, char **pError);
	MRTU_ERROR WriteMultReg(u8 SlaveAddr, u16 RegAddr, u16 pRegData[], u8 RegNum, char **pError);


	//构造函数
	MODBUS_RTU()
	{
		this->pSendDataCollBack = nullptr;
		this->pReadDataCollBack = nullptr;
	}

	//析构函数
	~MODBUS_RTU()
	{

	}
} ;



#endif /*_MODBUS_RTU_H_*/



//托管回调定义



delegate bool ProcessDelegateSend(BYTE *, DWORD);	//定义发送数据回调函数托管
delegate bool ProcessDelegateRead(BYTE *, DWORD *);	//定义发接收据回调函数托管
ProcessDelegateSend ^SendCallBack;					//声明发送回调函数托管
ProcessDelegateRead ^ReadCallBack;					//声明接收回调函数托管
this->SendCallBack = gcnew ProcessDelegateSend(this, &温湿度采集::Form1::Uart_Send);
this->ReadCallBack = gcnew ProcessDelegateRead(this, &温湿度采集::Form1::Uart_WaitAndRead);



//接口定义



//串口发送函数-用于回调
		bool Uart_Send(BYTE *pData, DWORD DataLen)
		{
			this->mUart->UART_ClearRxBuff(this->mHandle);	//清空接收缓冲区
			this->mUart->UART_ClearTxBuff(this->mHandle);	//清空发送缓冲区
			return this->mUart->UART_SendData(this->mHandle, pData, DataLen);	//调用串口发送数据
		}

		//串口接收函数-用于回调
		bool Uart_WaitAndRead(BYTE *pData, DWORD *pDataLen)
		{
			DWORD len;

			len = UartWait(20, 500);
			if (len)
			{
				if (len > MODBUS_RTU_PACK_MAX_SIZE) len = MODBUS_RTU_PACK_MAX_SIZE;							//必须限制数据包大小
				if (this->mUart->UART_ReadData(this->mHandle, pData, len) <= 0)							//读取串口接收到的数据
				{
					*pDataLen = 0;
					return false;	//通信接口错误
				}
				else
				{
					*pDataLen = len;
					return true;	//读取成功了
				}
			}
			else
			{
				*pDataLen = 0;		//长度为0,没有读取到数据
				return true;		//通信接口没有发生异常	
			}
		}


		//等待串口接收完成
		DWORD UartWait(WORD ByteTimeOut, WORD RxTimeOut)
		{
			DWORD cnt = 0;
			DWORD i, j = RxTimeOut / ByteTimeOut + 1;

			for (i = 0; i < j;i ++)
			{
				cnt = this->mUart->UART_GetRxCnt(this->mHandle);
				Sleep(ByteTimeOut);
				if ((cnt > 0) && cnt == (this->mUart->UART_GetRxCnt(this->mHandle)))
				{
					return cnt;
				}
			}

			return 0;
		}


//初始化回调接口道modbus-RTU



IntPtr pvFun1, pvFun2;


			pvFun1 = Marshal::GetFunctionPointerForDelegate(this->SendCallBack);//获取发送托管的回调指针
			pvFun2 = Marshal::GetFunctionPointerForDelegate(this->ReadCallBack);//获取接收托管的回调指针
			//初
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

最近一直在研究mod音乐,很好玩,和midi差不多,mod音乐也细分为很多格式,如it,xm,mod等,如果你使用过keygen,那你一定听过那 里面的动听音乐吧~呵呵~撒卡也是因此而着迷,上高中的时

关键字: vc++ mod音乐

MFC控件随着窗口大小变化VC++刚接触MFC不久,对MFC的许多函数和功能还不是很了解。所以,在仿照书本开发一个仿QQ的通讯程序的时候,就碰到了一个怎么样使控件随着窗体变化的问题。好了,废话不多说,

关键字: mfc vc++

vc++ 中开发汇编语言 汇编程序结构 一个显示字符串的汇编程序程序格式 一、模式定义二、includelib语句三、函数声明语句四、数据和代码部分Visual C/C++环境 建立工程汇编程序的调试

关键字: vc++ 汇编语言

[摘要:VC摹拟键盘输进 找了一周,终究找到摹拟键盘输进的方式了,不外话道照样要看靠谱的开源项目,才干快速找到办理题目的方式啊,空话未几道,进进主题。 摹拟键盘的方式有三种(我]           

关键字: vc++ 模拟键盘

因为我是做嵌入式开发的,每次设备程序更新后都需要修改上位机,并且多个上位机,修改起来特麻烦,又不想用C#主要是底层使用的是C语言,配置解析通信等在单片机里面写好后可以直接复制到C++中使用,比较方便,

关键字: .net vc++ 反射

这几天放假在家无聊编一个程序,在加载png时遇到了麻烦,后来用了两个方法解决了。一个是用GDI+,另外就是用vs.net MFC自带的CImage。先看看GDI+的方法方法1:1.GDI+画透明图层

关键字: vc++ gdi+

最近编写了一个升级设备的控件,可以集成到不同的配置程序中,但是每次关闭工程或者关闭编辑页面的时候就会出现这个错误,但是编译和运行时没有任何问题,仅仅在关闭编辑窗体页面的时候会出现。添加的控件关闭编辑就

关键字: vc++ 析构函数 升级控件

这次我想和大家一起讨论一下 Windows 的 Shell 扩展编程,首先在阅读以下内容之前我还是推荐大家看一下《COM技术内幕》这本大作,不过即使您没有有关的基础知识其实也是无所谓的,因为以下讲解是

关键字: shell vc++ 扩展编程

MFC控件随着窗口大小变化VC++刚接触MFC不久,对MFC的许多函数和功能还不是很了解。所以,在仿照书本开发一个仿QQ的通讯程序的时候,就碰到了一个怎么样使控件随着窗体变化的问题。好了,废话不多说,

关键字: mfc vc++

由于GPS信号位置均是经纬度球面坐标,国家从安全角度考虑不允许直接引用,因此凯立德为了方便导航者易于导航,就把经纬度坐标网格化,每一个网格单位代表纵横向0.1秒。K码的具体格式如下:1. K码是9位码

关键字: vc++ k码
关闭
关闭