VC++實現(xiàn)的ModBus-RTU主機接口函數(shù)(采用回調(diào)方式)
計算機上面使用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)指針 //初





