當前位置:首頁 > 芯聞號 > 充電吧
[導讀]計算機上面使用Modbus讀取傳感器或相關(guān)設(shè)備還是比較常用的,之前寫的Modbus-RTU協(xié)議將串口封裝到了協(xié)議棧內(nèi),使用的時候遇到短板了,比如我最新需要使用TCP來讀取Modbus設(shè)備,就不好用了,

計算機上面使用Modbus讀取傳感器或相關(guān)設(shè)備還是比較常用的,之前寫的Modbus-RTU協(xié)議將串口封裝到了協(xié)議棧內(nèi),使用的時候遇到短板了,比如我最新需要使用TCP來讀取Modbus設(shè)備,就不好用了,通過回調(diào)函數(shù)可以很簡單的解決這個問題。


//modbus-rtu.c


/*************************************************************************************************************
?*?文件名:		MODBUS_RTU.c
?*?功能:			MODBUS_RTU通信協(xié)議層
?*?作者:			cp1300@139.com
?*?創(chuàng)建時間:		2014-03-24
?*?最后修改時間:	2016-11-04
?*?詳細:			MODBUS?RTU通信協(xié)議層
				2016-03-21:增加防止接收數(shù)據(jù)過短導致異常
				2016-11-04:增加回調(diào)接口,將數(shù)據(jù)收發(fā)接口使用回調(diào)函數(shù)
*************************************************************************************************************/
#include?"StdAfx.h"
#include?"MODBUS_RTU.h"
#include?"windows.h"

using?namespace?System;

/*************************************************************************************************************************
*?函數(shù)		:	bool?MODBUS_RTU::ReadMultRegPack(BYTE?*pPackBuff,?DWORD?*pPackLen,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?char?**pError)
*?功能		:	主機讀取從機指定多個連續(xù)寄存器數(shù)據(jù)打包
*?參數(shù)		:	pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長度;RegType:讀取的寄存器類型;SlaveAddr:從機地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pError:返回錯誤說明
*?返回		:	true:成功;false:錯誤
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	數(shù)據(jù)打包,不涉及發(fā)送
*************************************************************************************************************************/
bool?MODBUS_RTU::ReadMultRegPack(BYTE?*pPackBuff,?DWORD?*pPackLen,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?char?**pError)
{
	MRTU_READ_FRAME?*pFrame;		//發(fā)送數(shù)據(jù)幀格式
	u16?crc16;

	if?(pPackBuff?==?nullptr)		//緩沖區(qū)無效
	{
		*pPackLen?=?0;
		if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無效!";
		return?false;	//句柄無效
	}
		
	pFrame?=?(MRTU_READ_FRAME?*)pPackBuff;
	//數(shù)據(jù)結(jié)構(gòu)填充
	pFrame->addr?=?SlaveAddr;						//從機地址
	pFrame->fun?=?(u8)RegType;						//功能碼,讀取
	pFrame->StartReg?=?SWAP16(RegAddr);				//寄存器起始地址
	if?((RegNum?>?127)?||?(RegNum?==?0))
	{
		if?(pError?!=?nullptr)?*pError?=?"一次讀取的寄存器數(shù)量超出范圍!";
		return?false;								//寄存器數(shù)量錯誤
	}	
	pFrame->RegNum?=?SWAP16(RegNum);				//需要讀取的寄存器數(shù)量
	crc16?=?usMBCRC16(pPackBuff,?6);				//計算CRC16
	pFrame->CRC16?=?crc16;							//crc16
	*pPackLen?=?6+2;

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




/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR??MODBUS_RTU::ReadMultRegUnpack(BYTE?*pPackBuff,?DWORD?PackLen,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[],?char?**pError)
*?功能		:	主機讀取從機指定多個連續(xù)寄存器數(shù)據(jù)解包
*?參數(shù)		:	pPackBuff:數(shù)據(jù)包緩沖區(qū);PackLen:數(shù)據(jù)包大小;SlaveAddr:從機地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍
					返回的寄存器的值按照循序存放在pRegData中
*?返回		:	MRTU_ERROR:通信狀態(tài)
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	數(shù)據(jù)包解析
*************************************************************************************************************************/
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;	//返回數(shù)據(jù)幀格式
	MRTU_UNU_FRAME	*pUnuFrame;		//返回的異常數(shù)據(jù)幀格式
	u16?crc16;
	u16?i;

	if?(pPackBuff?==?nullptr)		//緩沖區(qū)無效
	{
		if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無效!";
		return?MRTU_HANDLE_ERROR;	//句柄無效
	}

	if?(PackLen?<?3)?
	{
		if?(pError?!=?nullptr)?*pError?=?"返回數(shù)據(jù)長度過短!";
		return?MRTU_LEN_ERROR;	//返回數(shù)據(jù)長度錯誤
	}
	
	pReFrame?=?(MRTU_RETURN_FRAME?*)pPackBuff;
	//檢查地址
	if?(pReFrame->addr?!=?SlaveAddr)
	{
		if?(pError?!=?nullptr)?*pError?=?"返回的從機地址錯誤!";
		return?MRTU_ADDR_ERROR;
	}
	//對接受的數(shù)據(jù)進行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;				//異常數(shù)據(jù)幀
		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;
		}
	}
	//判斷數(shù)據(jù)長度
	if?(pReFrame->DataLen?!=?(RegNum?*?2))
	{
		if?(pError?!=?nullptr)?*pError?=?"返回數(shù)據(jù)長度錯誤,長度小于需要讀取的寄存器數(shù)量x2!";
		return?MRTU_LEN_ERROR;				//返回數(shù)據(jù)長度錯誤
	}
	//獲取返回的寄存器的值
	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;						//返回成功?
}




/*************************************************************************************************************************
*?函數(shù)		:	bool?WriteOnetRegPack(BYTE?*pPackBuff,?DWORD?*pPackLen,?u8?SlaveAddr,?u16?RegAddr,?u16?RegData,?char?**pError)
*?功能		:	主機寫從機一個指定寄存器數(shù)據(jù)打包
*?參數(shù)		:	pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長度;SlaveAddr:從機地址;RegAddr:寫寄存器地址;RegData:寄存器的值;pError:錯誤提示
*?返回		:	true:成功;false:錯誤
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	數(shù)據(jù)打包,不涉及發(fā)送
*************************************************************************************************************************/
bool?MODBUS_RTU::WriteOnetRegPack(BYTE?*pPackBuff,?DWORD?*pPackLen,?u8?SlaveAddr,?u16?RegAddr,?u16?RegData,?char?**pError)
{
	MRTU_WRITE_FRAME?*pFrame;//發(fā)送數(shù)據(jù)幀格式
	u16?crc16;


	if?(pPackBuff?==?nullptr)		//緩沖區(qū)無效
	{
		*pPackLen?=?0;
		if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無效!";
		return?false;	//句柄無效
	}

	pFrame?=?(MRTU_WRITE_FRAME?*)pPackBuff;
	//數(shù)據(jù)結(jié)構(gòu)填充
	pFrame->addr?=?SlaveAddr;						//從機地址
	pFrame->fun?=?(u8)MRTU_FUN_WRITE;				//功能碼,預置單個寄存器
	pFrame->StartReg?=?SWAP16(RegAddr);				//寄存器起始地址
	pFrame->RegData?=?SWAP16(RegData);				//寫入寄存器內(nèi)容
	pFrame->crc16?=?usMBCRC16(pPackBuff,?6);		//計算CRC16
	*pPackLen?=?6+2;

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





/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR?MODBUS_RTU::WriteOneRegUnpack(BYTE?*pPackBuff,?DWORD?PackLen,?u8?SlaveAddr,?u16?RegAddr,?u16?RegData,?char?**pError)
*?功能		:	主機寫從機一個指定寄存器數(shù)據(jù)解包
*?參數(shù)		:	pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長度;SlaveAddr:從機地址;RegAddr:寫寄存器地址;RegData:寄存器的值;RegData:需要寫入的值;pError:錯誤說明
*?返回		:	MRTU_ERROR:通信狀態(tài)
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	數(shù)據(jù)包解包
*************************************************************************************************************************/
MRTU_ERROR?MODBUS_RTU::WriteOneRegUnpack(BYTE?*pPackBuff,?DWORD?PackLen,?u8?SlaveAddr,?u16?RegAddr,?u16?RegData,?char?**pError)
{
	MRTU_WRITE_FRAME?*pReFrame;//發(fā)送數(shù)據(jù)幀格式
	MRTU_UNU_FRAME	*pUnuFrame;			//返回的異常數(shù)據(jù)幀格式
	u16?crc16;

	if?(pPackBuff?==?nullptr)		//緩沖區(qū)無效
	{
		if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無效!";
		return?MRTU_HANDLE_ERROR;	//句柄無效
	}
	if?(PackLen?<?3)
	{
		if?(pError?!=?nullptr)?*pError?=?"返回數(shù)據(jù)長度過短!";
		return?MRTU_LEN_ERROR;	//返回數(shù)據(jù)長度錯誤
	}

	pReFrame?=?(MRTU_WRITE_FRAME?*)pPackBuff;
	//檢查地址
	if?(pReFrame->addr?!=?SlaveAddr)
	{
		if?(pError?!=?nullptr)?*pError?=?"返回的從機地址錯誤!";
		return?MRTU_ADDR_ERROR;
	}
	//對接受的數(shù)據(jù)進行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;		//異常數(shù)據(jù)幀
		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;
		}
	}
	//判斷數(shù)據(jù)是否寫入
	if?(SWAP16(pReFrame->StartReg)?!=?RegAddr)	//返回的寄存器地址不一致
	{
		if?(pError?!=?nullptr)?*pError?=?"返回寄存器地址錯誤!";
		return?MRTU_REG_ERROR;					//返回寄存器錯誤
	}
	if?(SWAP16(pReFrame->RegData)?!=?RegData)
	{
		if?(pError?!=?nullptr)?*pError?=?"數(shù)據(jù)寫入錯誤,沒有寫入成功!";
		return?MRTU_WRITE_ERROR;				//寫入數(shù)據(jù)錯誤
	}

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





/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR?MODBUS_RTU::WriteMultRegPack(BYTE?*pPackBuff,?DWORD?*pPackLen,?u8?SlaveAddr,?u16?RegAddr,?u16?pRegData[],?u8?RegNum,?,?char?**pError)
*?功能		:	主機寫從機多個指定寄存器數(shù)據(jù)打包
*?參數(shù)		:	pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長度;SlaveAddr:從機地址;RegAddr:寫寄存器地址;pRegData:需要寫入的寄存器的值;RegNum:寄存器數(shù)量;pError:錯誤說明
*?返回		:	true:成功;false:錯誤
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	寫多個寄存器數(shù)據(jù)打包
				寫入寄存器的值按照循序排列,使用小端格式,大小必須為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;					//發(fā)送數(shù)據(jù)幀格式
	DWORD?i;
	WORD?crc16;

	if?(pPackBuff?==?nullptr)		//緩沖區(qū)無效
	{
		*pPackLen?=?0;
		if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無效!";
		return?false;	//句柄無效
	}
	pFrame?=?(MRTU_WRITE_MULT_FRAME?*)pPackBuff;
	//數(shù)據(jù)結(jié)構(gòu)填充
	pFrame->addr?=?SlaveAddr;						//從機地址
	pFrame->fun?=?(u8)MRTU_FUN_MWRITE;				//功能碼,預置多個寄存器
	pFrame->StartReg?=?SWAP16(RegAddr);				//寄存器起始地址
	if?((RegNum?>?127)?||?(RegNum?==?0))
	{
		*pPackLen?=?0;
		if?(pError?!=?nullptr)?*pError?=?"一次寫入寄存器數(shù)量過多!";
		return?FALSE;	//寄存器數(shù)量錯誤
	}
		
	pFrame->RegNum?=?SWAP16(RegNum);				//寫入寄存器數(shù)量
	pFrame->DataLen?=?2?*?RegNum;						//數(shù)據(jù)長度
	//循環(huán)寫入數(shù)據(jù)
	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,高低位對調(diào)過
	pFrame->DataBuff[pFrame->DataLen]?=?crc16?&?0xff;	//高位
	pFrame->DataBuff[pFrame->DataLen?+?1]?=?crc16?>>?8;	//低位
	*pPackLen?=?7?+?pFrame->DataLen?+?2;

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




/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR?MODBUS_RTU::WriteMultRegUnpack(BYTE?*pPackBuff,?DWORD?PackLen,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?char?**pError)
*?功能		:	主機寫從機多個指定寄存器數(shù)據(jù)解包
*?參數(shù)		:	pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長度;SlaveAddr:從機地址;RegAddr:寫寄存器地址;RegNum:寄存器數(shù)量;pError:錯誤說明
*?返回		:	MRTU_ERROR
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間:	2016-11-04
*?說明		:?	寫多個寄存器數(shù)據(jù)解包
*************************************************************************************************************************/
MRTU_ERROR?MODBUS_RTU::WriteMultRegUnpack(BYTE?*pPackBuff,?DWORD?PackLen,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?char?**pError)
{
	MRTU_WRIT_EMULT_RFRAME?*pReFrame;				//返回數(shù)據(jù)幀格式
	MRTU_UNU_FRAME	*pUnuFrame;						//返回的異常數(shù)據(jù)幀格式
	u16?crc16;
	u8?i;

	if?(pPackBuff?==?nullptr)		//緩沖區(qū)無效
	{
		if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無效!";
		return?MRTU_HANDLE_ERROR;	//句柄無效
	}
	if?(PackLen?<?3)
	{
		if?(pError?!=?nullptr)?*pError?=?"返回數(shù)據(jù)長度過短!";
		return?MRTU_LEN_ERROR;	//返回數(shù)據(jù)長度錯誤
	}

	pReFrame?=?(MRTU_WRIT_EMULT_RFRAME?*)pPackBuff;
	//檢查地址
	if?(pReFrame->addr?!=?SlaveAddr)
	{
		if?(pError?!=?nullptr)?*pError?=?"返回的從機地址錯誤!";
		return?MRTU_ADDR_ERROR;
	}
	//對接受的數(shù)據(jù)進行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;		//異常數(shù)據(jù)幀
		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;
		}
	}
	//判斷數(shù)據(jù)是否寫入
	if?(SWAP16(pReFrame->StartReg)?!=?RegAddr)	//返回的寄存器地址不一致
	{
		if?(pError?!=?nullptr)?*pError?=?"返回寄存器地址錯誤!";
		return?MRTU_REG_ERROR;					//返回寄存器錯誤
	}
	if?(SWAP16(pReFrame->RegNum)?!=?RegNum)
	{
		if?(pError?!=?nullptr)?*pError?=?"數(shù)據(jù)寫入錯誤,返回的寄存器數(shù)量不一致!";
		return?MRTU_WRITE_ERROR;				//寫入數(shù)據(jù)錯誤
	}

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




/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR?MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE?*pHandle,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[])
*?功能		:	主機讀取從機指定多個連續(xù)寄存器(需要初始化回調(diào)通信接口)
*?參數(shù)		:	RegType:讀取的寄存器類型;SlaveAddr:從機地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍;pError:錯誤信息
*?返回		:	MRTU_ERROR:通信狀態(tài)
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	輸入輸出的數(shù)據(jù)都為小端模式
				返回的寄存器的值按照循序存放在pRegData中
				需要先初始化通信接口,并且會申請?MODBUS_RTU_PACK_MAX_SIZE+1?字節(jié)堆內(nèi)存用于支持可重入
*************************************************************************************************************************/
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;
	}
	//調(diào)用回調(diào)進行
	if?(this->pSendDataCollBack?==?nullptr)
	{
		if?(pError?==?nullptr)?*pError?=?"發(fā)送回調(diào)函數(shù)無效!";
		return?MRTU_HANDLE_ERROR;
	}
	try
	{
		if?(this->pSendDataCollBack(PackBuff,?len)?==?false)
		{
			if?(pError?==?nullptr)?*pError?=?"發(fā)送數(shù)據(jù)失敗!";
			return?MRTU_SEND_ERROR;
		}
	}
	catch?(Exception^?e)
	{
		if?(pError?==?nullptr)?*pError?=?"發(fā)送數(shù)據(jù)發(fā)生了異常!";
		return?MRTU_SEND_ERROR;
	}
	//發(fā)送完成了,調(diào)用接收回調(diào)進行數(shù)據(jù)接收
	if?(this->pReadDataCollBack?==?nullptr)
	{
		if?(pError?==?nullptr)?*pError?=?"接收回調(diào)函數(shù)無效!";
		return?MRTU_READ_ERROR;
	}
	try
	{
		if?(this->pReadDataCollBack(PackBuff,?&len)?==?false)
		{
			if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)失敗!";
			return?MRTU_READ_ERROR;
		}
	}
	catch?(Exception^?e)
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)發(fā)生了異常!";
		return?MRTU_READ_ERROR;
	}
	if?(len?==?0)
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)超時!";
		return?MRTU_TIME_OUT;
	}
	if?(len?>?(256?+?7))
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)溢出!";
		return?MRTU_OVER_ERROR;
	}
	//數(shù)據(jù)接收完成了,開始解析
	return?ReadMultRegUnpack(PackBuff,?len,?RegType,?SlaveAddr,RegAddr,?RegNum,?pRegData,?pError);
}



/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR?MODBUS_RTU::WriteOnetReg(u8?SlaveAddr,?u16?RegAddr,?u16?RegData,?char?**pError)
*?功能		:	主機寫入從機一個寄存器(需要初始化回調(diào)通信接口)
*?參數(shù)		:	SlaveAddr:從機地址;RegAddr:寫寄存器地址;RegData:寄存器的值;pError:錯誤提示
*?返回		:	MRTU_ERROR:通信狀態(tài)
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間	:	2016-11-04
*?說明		:?	輸入輸出的數(shù)據(jù)都為小端模式
				需要先初始化通信接口,并且會申請?MODBUS_RTU_PACK_MAX_SIZE+1?字節(jié)堆內(nèi)存用于支持可重入
*************************************************************************************************************************/
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;
	}
	//調(diào)用回調(diào)進行
	if?(this->pSendDataCollBack?==?nullptr)
	{
		if?(pError?==?nullptr)?*pError?=?"發(fā)送回調(diào)函數(shù)無效!";
		return?MRTU_HANDLE_ERROR;
	}
	try
	{
		if?(this->pSendDataCollBack(PackBuff,?len)?==?false)
		{
			if?(pError?==?nullptr)?*pError?=?"發(fā)送數(shù)據(jù)失敗!";
			return?MRTU_SEND_ERROR;
		}
	}
	catch?(Exception^?e)
	{
		if?(pError?==?nullptr)?*pError?=?"發(fā)送數(shù)據(jù)發(fā)生了異常!";
		return?MRTU_SEND_ERROR;
	}
	//發(fā)送完成了,調(diào)用接收回調(diào)進行數(shù)據(jù)接收
	if?(this->pReadDataCollBack?==?nullptr)
	{
		if?(pError?==?nullptr)?*pError?=?"接收回調(diào)函數(shù)無效!";
		return?MRTU_READ_ERROR;
	}
	try
	{
		if?(this->pReadDataCollBack(PackBuff,?&len)?==?false)
		{
			if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)失敗!";
			return?MRTU_READ_ERROR;
		}
	}
	catch?(Exception^?e)
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)發(fā)生了異常!";
		return?MRTU_READ_ERROR;
	}
	if?(len?==?0)
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)超時!";
		return?MRTU_TIME_OUT;
	}
	if?(len?>?(256?+?7))
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)溢出!";
		return?MRTU_OVER_ERROR;
	}
	//數(shù)據(jù)接收完成了,開始解析
	return?WriteOneRegUnpack(PackBuff,?len,?SlaveAddr,?RegAddr,??RegData,?pError);
}


/*************************************************************************************************************************
*?函數(shù)		:	MRTU_ERROR?MODBUS_RTU::WriteMultReg(u8?SlaveAddr,?u16?RegAddr,?u16?pRegData[],u8?RegNum,??char?**pError)
*?功能		:	主機寫從機多個指定寄存器(需要初始化回調(diào)通信接口)
*?參數(shù)		:	SlaveAddr:從機地址;RegAddr:寫寄存器地址;RegNum:寄存器數(shù)量;pError:錯誤說明
*?返回		:	MRTU_ERROR
*?依賴		:	底層通信驅(qū)動
*?作者		:	cp1300@139.com
*?時間		:	2014-03-24
*?最后修改時間:	2016-11-04
*?說明		:?	寫多個寄存器數(shù)據(jù)解包
*************************************************************************************************************************/
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;
	}
	//調(diào)用回調(diào)進行
	if?(this->pSendDataCollBack?==?nullptr)
	{
		if?(pError?==?nullptr)?*pError?=?"發(fā)送回調(diào)函數(shù)無效!";
		return?MRTU_HANDLE_ERROR;
	}
	try
	{
		if?(this->pSendDataCollBack(PackBuff,?len)?==?false)
		{
			if?(pError?==?nullptr)?*pError?=?"發(fā)送數(shù)據(jù)失敗!";
			return?MRTU_SEND_ERROR;
		}
	}
	catch?(Exception^?e)
	{
		if?(pError?==?nullptr)?*pError?=?"發(fā)送數(shù)據(jù)發(fā)生了異常!";
		return?MRTU_SEND_ERROR;
	}
	//發(fā)送完成了,調(diào)用接收回調(diào)進行數(shù)據(jù)接收
	if?(this->pReadDataCollBack?==?nullptr)
	{
		if?(pError?==?nullptr)?*pError?=?"接收回調(diào)函數(shù)無效!";
		return?MRTU_READ_ERROR;
	}
	try
	{
		if?(this->pReadDataCollBack(PackBuff,?&len)?==?false)
		{
			if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)失敗!";
			return?MRTU_READ_ERROR;
		}
	}
	catch?(Exception^?e)
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)發(fā)生了異常!";
		return?MRTU_READ_ERROR;
	}
	if?(len?==?0)
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)超時!";
		return?MRTU_TIME_OUT;
	}
	if?(len?>?(256?+?7))
	{
		if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)溢出!";
		return?MRTU_OVER_ERROR;
	}
	//數(shù)據(jù)接收完成了,開始解析
	return?WriteMultRegUnpack(PackBuff,?len,?SlaveAddr,?RegAddr,?RegNum,?pError);
}




//MODBUS?CRC16計算
//結(jié)果為大端模式
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通信協(xié)議層
*?作者:			cp1300@139.com
*?創(chuàng)建時間:		2014-03-24
*?最后修改時間:	2016-11-04
*?詳細:			MODBUS?RTU通信協(xié)議層
2016-03-21:增加防止接收數(shù)據(jù)過短導致異常
2016-11-04:增加回調(diào)接口,將數(shù)據(jù)收發(fā)接口使用回調(diào)函數(shù)
*************************************************************************************************************/
#ifndef?_MODBUS_RTU_H_
#define?_MODBUS_RTU_H_

#include?"windows.h"

//基本數(shù)據(jù)類型定義
#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位整形數(shù)高低對調(diào)
#define?SWAP16(x)???(((x?&?0xff00)?>>?8)?|?((x?&?0xff)?<<?8))

//最大數(shù)據(jù)包大小
#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			//寫多個保持寄存器

//大端數(shù)據(jù)標記
#define?BIG_U16		u16							//16位整形數(shù),需要轉(zhuǎn)換為大端模式,兼容modubus




//讀取寄存器類型選擇
typedef?enum
{
	HOLD_REG?	=?	MRTU_FUN_READ_HOLD,			//保持寄存器
	INPUT_REG	=	MRTU_FUN_READ_INPUT,		//輸入寄存器
}?READ_REG_TYPE;


//數(shù)據(jù)讀取?主機數(shù)據(jù)幀,主機讀取從機的數(shù)據(jù)幀
typedef??struct
{
	u8	addr;				//地址?address
	u8	fun;				//功能碼?function
	BIG_U16	StartReg;		//數(shù)據(jù)起始地址
	BIG_U16	RegNum;			//需要讀取的寄存器個數(shù)
	BIG_U16	CRC16;			//CRC16
}?MRTU_READ_FRAME;			//MODBUS?RTU?master?Read?Reg?Frame



//預置單個保持寄存器,主機寫從機單個寄存器的數(shù)據(jù)幀
//從機返回數(shù)據(jù)幀與主機預置單個寄存器數(shù)據(jù)幀一樣
typedef??struct
{
	u8	addr;				//地址?address
	u8	fun;				//功能碼?function
	BIG_U16	StartReg;		//數(shù)據(jù)起始地址
	BIG_U16	RegData;		//數(shù)據(jù)值
	BIG_U16?crc16;			//CRC校驗值
}?MRTU_WRITE_FRAME;			//MODBUS?RTU?master?Write?Reg?Frame





//預置多個保持寄存器,主機寫從機多個寄存器的數(shù)據(jù)幀
typedef??struct
{
	u8	addr;				//地址?address
	u8	fun;				//功能碼?function
	BIG_U16	StartReg;		//數(shù)據(jù)起始地址
	BIG_U16	RegNum;			//寄存器數(shù)量
	u8	DataLen;			//數(shù)據(jù)長度
	u8	DataBuff[2];		//寄存器的值	
}?MRTU_WRITE_MULT_FRAME;			


//預置多個保持寄存器后返回數(shù)據(jù)幀,從機返回主機的數(shù)據(jù)幀
typedef??struct
{
	u8	addr;				//地址?address
	u8	fun;				//功能碼?function
	BIG_U16	StartReg;		//數(shù)據(jù)起始地址
	BIG_U16	RegNum;			//寄存器數(shù)量
	BIG_U16?crc16;			//CRC校驗值
}?MRTU_WRIT_EMULT_RFRAME;			


//讀取從機返回數(shù)據(jù)幀格式,從機返回給主機的數(shù)據(jù)幀
typedef??struct
{
	u8	addr;				//地址?address
	u8	fun;				//功能碼?function
	u8	DataLen;			//數(shù)據(jù)長度
	u8	DataBuff[2];		//數(shù)據(jù)區(qū),CRC16放在最后結(jié)尾處
	//MRTU_REG16	CRC16;	//CRC16
}?MRTU_RETURN_FRAME;	//MODBUS?RTU?master?Read?Reg?Frame


//從機返回的異常數(shù)據(jù)幀,從機返回的異常數(shù)據(jù)幀
typedef??struct
{
	u8	addr;				//地址?address
	u8	ErrorFun;			//錯誤功能碼?function+0x80
	u8	unu;				//異常碼
	u8	crc16H;				//CRC16放在最后結(jié)尾處
	u8	crc16L;				//CRC16放在最后結(jié)尾處
}?MRTU_UNU_FRAME;	


//從機數(shù)據(jù)包解析后的相關(guān)信息
typedef?struct
{
	u8	SlaveAddr;	//主機發(fā)送的從機地址
	u8?	RegNum;		//主機需要讀取從機的寄存器數(shù)量
	u8	fun;		//主機發(fā)送給從機的功能碼
	u16?StartReg;	//主機需要讀寫的從機寄存器地址
}?MRTU_SLAVE_INFO;


//異常碼定義
typedef?enum
{
	MRTU_UNUS1		=	0x01,	//異常碼1,無效的操作碼
	MRTU_UNUS2		=	0x02,	//異常碼2,無效的數(shù)據(jù)地址
	MRTU_UNUS3		=	0x03,	//異常碼3,無效的數(shù)據(jù)值
	MRTU_UNUS4		=	0x04,	//異常碼4,無效操作
	MRTU_UNUS5		=	0x05,	//異常碼5
	MRTU_UNUS6		=	0x06,	//異常碼6
}?MRTU_UNUS;


//錯誤狀態(tài)
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,		//通信回調(diào)接口錯誤,或緩沖區(qū)錯誤
	MRTU_REGN_ERROR			=	8,		//寄存器數(shù)量錯誤
	MRTU_LEN_ERROR			=	9,		//返回數(shù)據(jù)長度錯誤
	MRTU_WRITE_ERROR		=	10,		//寫寄存器錯誤,寫入與讀取不一致
	MRTU_SEND_ERROR			=	11,		//發(fā)送數(shù)據(jù)失敗
	MRTU_READ_ERROR			=	12,		//讀取數(shù)據(jù)失敗
	MRTU_UNUS1_ERROR		=	0x81,	//異常碼1,無效的操作碼
	MRTU_UNUS2_ERROR		=	0x82,	//異常碼2,無效的數(shù)據(jù)地址
	MRTU_UNUS3_ERROR		=	0x83,	//異常碼3,無效的數(shù)據(jù)值
	MRTU_UNUS4_ERROR		=	0x84,	//異常碼4,無效操作
	MRTU_UNUS5_ERROR		=	0x85,	//異常碼5
	MRTU_UNUS6_ERROR		=	0x86,	//異常碼6
	MRTU_OTHER_ERROR?=?0xff
}?MRTU_ERROR;


//發(fā)送回調(diào)函數(shù)定義
typedef?bool(*MODBUS_SendDataCollBack)(BYTE?*,?DWORD);			//發(fā)送緩沖區(qū)與發(fā)送數(shù)據(jù)大??;返回:發(fā)送成功返回true,發(fā)送失敗返回false
//接收回調(diào)函數(shù)定義
typedef?bool(*MODBUS_ReadDataCollBack)(BYTE?*,?DWORD?*);			//接收緩沖區(qū)與接收數(shù)據(jù)長度;返回:讀取成功返回true,讀取失敗,接口錯誤返回false,返回true后數(shù)據(jù)長度為0算作超時,返回false一般都是接口錯誤



class?MODBUS_RTU
{
private:
	MODBUS_SendDataCollBack?pSendDataCollBack;	//發(fā)送回調(diào)函數(shù)指針
	MODBUS_ReadDataCollBack?pReadDataCollBack;	//接收回調(diào)函數(shù)指針
	u16?usMBCRC16(u8?*?pucFrame,?u16?usLen);	//crc計算

public:
	//數(shù)據(jù)包打包與解包接口-不涉及到數(shù)據(jù)發(fā)送與接收
	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);

	//帶回調(diào)模式通信接口初始化
	//pSendDataCollBack:發(fā)送回調(diào)函數(shù)指針;pReadDataCollBack:接收回調(diào)函數(shù)指針;TimeOut:接收超時時間
	void?MODBUS_RTU::InterfaceInit(MODBUS_SendDataCollBack?pSendDataCollBack,?MODBUS_ReadDataCollBack?pReadDataCollBack)
	{
		this->pSendDataCollBack?=?pSendDataCollBack;	//發(fā)送回調(diào)函數(shù)指針
		this->pReadDataCollBack?=?pReadDataCollBack;	//接收回調(diào)函數(shù)指針
	}
	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);


	//構(gòu)造函數(shù)
	MODBUS_RTU()
	{
		this->pSendDataCollBack?=?nullptr;
		this->pReadDataCollBack?=?nullptr;
	}

	//析構(gòu)函數(shù)
	~MODBUS_RTU()
	{

	}
}?;



#endif?/*_MODBUS_RTU_H_*/



//托管回調(diào)定義



delegate?bool?ProcessDelegateSend(BYTE?*,?DWORD);	//定義發(fā)送數(shù)據(jù)回調(diào)函數(shù)托管
delegate?bool?ProcessDelegateRead(BYTE?*,?DWORD?*);	//定義發(fā)接收據(jù)回調(diào)函數(shù)托管
ProcessDelegateSend?^SendCallBack;					//聲明發(fā)送回調(diào)函數(shù)托管
ProcessDelegateRead?^ReadCallBack;					//聲明接收回調(diào)函數(shù)托管
this->SendCallBack?=?gcnew?ProcessDelegateSend(this,?&溫濕度采集::Form1::Uart_Send);
this->ReadCallBack?=?gcnew?ProcessDelegateRead(this,?&溫濕度采集::Form1::Uart_WaitAndRead);



//接口定義



//串口發(fā)送函數(shù)-用于回調(diào)
		bool?Uart_Send(BYTE?*pData,?DWORD?DataLen)
		{
			this->mUart->UART_ClearRxBuff(this->mHandle);	//清空接收緩沖區(qū)
			this->mUart->UART_ClearTxBuff(this->mHandle);	//清空發(fā)送緩沖區(qū)
			return?this->mUart->UART_SendData(this->mHandle,?pData,?DataLen);	//調(diào)用串口發(fā)送數(shù)據(jù)
		}

		//串口接收函數(shù)-用于回調(diào)
		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;							//必須限制數(shù)據(jù)包大小
				if?(this->mUart->UART_ReadData(this->mHandle,?pData,?len)?<=?0)							//讀取串口接收到的數(shù)據(jù)
				{
					*pDataLen?=?0;
					return?false;	//通信接口錯誤
				}
				else
				{
					*pDataLen?=?len;
					return?true;	//讀取成功了
				}
			}
			else
			{
				*pDataLen?=?0;		//長度為0,沒有讀取到數(shù)據(jù)
				return?true;		//通信接口沒有發(fā)生異常	
			}
		}


		//等待串口接收完成
		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;
		}


//初始化回調(diào)接口道m(xù)odbus-RTU



IntPtr?pvFun1,?pvFun2;


			pvFun1?=?Marshal::GetFunctionPointerForDelegate(this->SendCallBack);//獲取發(fā)送托管的回調(diào)指針
			pvFun2?=?Marshal::GetFunctionPointerForDelegate(this->ReadCallBack);//獲取接收托管的回調(diào)指針
			//初
本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉