VC++實(shí)現(xiàn)的ModBus-RTU主機(jī)接口函數(shù)(采用回調(diào)方式)
計(jì)算機(jī)上面使用Modbus讀取傳感器或相關(guān)設(shè)備還是比較常用的,之前寫(xiě)的Modbus-RTU協(xié)議將串口封裝到了協(xié)議棧內(nèi),使用的時(shí)候遇到短板了,比如我最新需要使用TCP來(lái)讀取Modbus設(shè)備,就不好用了,通過(guò)回調(diào)函數(shù)可以很簡(jiǎn)單的解決這個(gè)問(wèn)題。
//modbus-rtu.c
/************************************************************************************************************* ?*?文件名: MODBUS_RTU.c ?*?功能: MODBUS_RTU通信協(xié)議層 ?*?作者: cp1300@139.com ?*?創(chuàng)建時(shí)間: 2014-03-24 ?*?最后修改時(shí)間: 2016-11-04 ?*?詳細(xì): MODBUS?RTU通信協(xié)議層 2016-03-21:增加防止接收數(shù)據(jù)過(guò)短導(dǎo)致異常 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) *?功能 : 主機(jī)讀取從機(jī)指定多個(gè)連續(xù)寄存器數(shù)據(jù)打包 *?參數(shù) : pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長(zhǎng)度;RegType:讀取的寄存器類(lèi)型;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pError:返回錯(cuò)誤說(shuō)明 *?返回 : true:成功;false:錯(cuò)誤 *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 數(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ū)無(wú)效 { *pPackLen?=?0; if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無(wú)效!"; return?false; //句柄無(wú)效 } pFrame?=?(MRTU_READ_FRAME?*)pPackBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)RegType; //功能碼,讀取 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 if?((RegNum?>?127)?||?(RegNum?==?0)) { if?(pError?!=?nullptr)?*pError?=?"一次讀取的寄存器數(shù)量超出范圍!"; return?false; //寄存器數(shù)量錯(cuò)誤 } pFrame->RegNum?=?SWAP16(RegNum); //需要讀取的寄存器數(shù)量 crc16?=?usMBCRC16(pPackBuff,?6); //計(jì)算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) *?功能 : 主機(jī)讀取從機(jī)指定多個(gè)連續(xù)寄存器數(shù)據(jù)解包 *?參數(shù) : pPackBuff:數(shù)據(jù)包緩沖區(qū);PackLen:數(shù)據(jù)包大小;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍 返回的寄存器的值按照循序存放在pRegData中 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 數(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; //返回?cái)?shù)據(jù)幀格式 MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式 u16?crc16; u16?i; if?(pPackBuff?==?nullptr) //緩沖區(qū)無(wú)效 { if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無(wú)效!"; return?MRTU_HANDLE_ERROR; //句柄無(wú)效 } if?(PackLen?<?3)? { if?(pError?!=?nullptr)?*pError?=?"返回?cái)?shù)據(jù)長(zhǎng)度過(guò)短!"; return?MRTU_LEN_ERROR; //返回?cái)?shù)據(jù)長(zhǎng)度錯(cuò)誤 } pReFrame?=?(MRTU_RETURN_FRAME?*)pPackBuff; //檢查地址 if?(pReFrame->addr?!=?SlaveAddr) { if?(pError?!=?nullptr)?*pError?=?"返回的從機(jī)地址錯(cuò)誤!"; return?MRTU_ADDR_ERROR; } //對(duì)接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn) crc16?=?usMBCRC16(pPackBuff,?PackLen?-?2);//計(jì)算CRC16 if?((pPackBuff[PackLen?-?1]?!=?(crc16?>>?8))?||?(pPackBuff[PackLen?-?2]?!=?(crc16?&?0xff))) { if?(pError?!=?nullptr)?*pError?=?"CRC校驗(yàn)錯(cuò)誤"; return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤 } //返回的功能碼不一致 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?=?"返回功能碼錯(cuò)誤!"; return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)長(zhǎng)度 if?(pReFrame->DataLen?!=?(RegNum?*?2)) { if?(pError?!=?nullptr)?*pError?=?"返回?cái)?shù)據(jù)長(zhǎng)度錯(cuò)誤,長(zhǎng)度小于需要讀取的寄存器數(shù)量x2!"; return?MRTU_LEN_ERROR; //返回?cái)?shù)據(jù)長(zhǎng)度錯(cuò)誤 } //獲取返回的寄存器的值 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) *?功能 : 主機(jī)寫(xiě)從機(jī)一個(gè)指定寄存器數(shù)據(jù)打包 *?參數(shù) : pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長(zhǎng)度;SlaveAddr:從機(jī)地址;RegAddr:寫(xiě)寄存器地址;RegData:寄存器的值;pError:錯(cuò)誤提示 *?返回 : true:成功;false:錯(cuò)誤 *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 數(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ū)無(wú)效 { *pPackLen?=?0; if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無(wú)效!"; return?false; //句柄無(wú)效 } pFrame?=?(MRTU_WRITE_FRAME?*)pPackBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)MRTU_FUN_WRITE; //功能碼,預(yù)置單個(gè)寄存器 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 pFrame->RegData?=?SWAP16(RegData); //寫(xiě)入寄存器內(nèi)容 pFrame->crc16?=?usMBCRC16(pPackBuff,?6); //計(jì)算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) *?功能 : 主機(jī)寫(xiě)從機(jī)一個(gè)指定寄存器數(shù)據(jù)解包 *?參數(shù) : pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長(zhǎng)度;SlaveAddr:從機(jī)地址;RegAddr:寫(xiě)寄存器地址;RegData:寄存器的值;RegData:需要寫(xiě)入的值;pError:錯(cuò)誤說(shuō)明 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 數(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ū)無(wú)效 { if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無(wú)效!"; return?MRTU_HANDLE_ERROR; //句柄無(wú)效 } if?(PackLen?<?3) { if?(pError?!=?nullptr)?*pError?=?"返回?cái)?shù)據(jù)長(zhǎng)度過(guò)短!"; return?MRTU_LEN_ERROR; //返回?cái)?shù)據(jù)長(zhǎng)度錯(cuò)誤 } pReFrame?=?(MRTU_WRITE_FRAME?*)pPackBuff; //檢查地址 if?(pReFrame->addr?!=?SlaveAddr) { if?(pError?!=?nullptr)?*pError?=?"返回的從機(jī)地址錯(cuò)誤!"; return?MRTU_ADDR_ERROR; } //對(duì)接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn) crc16?=?usMBCRC16(pPackBuff,?PackLen?-?2);//計(jì)算CRC16 if?((pPackBuff[PackLen?-?1]?!=?(crc16?>>?8))?||?(pPackBuff[PackLen?-?2]?!=?(crc16?&?0xff))) { if?(pError?!=?nullptr)?*pError?=?"CRC校驗(yàn)錯(cuò)誤"; return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤 } //返回的功能碼不一致 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?=?"返回功能碼錯(cuò)誤!"; return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)是否寫(xiě)入 if?(SWAP16(pReFrame->StartReg)?!=?RegAddr) //返回的寄存器地址不一致 { if?(pError?!=?nullptr)?*pError?=?"返回寄存器地址錯(cuò)誤!"; return?MRTU_REG_ERROR; //返回寄存器錯(cuò)誤 } if?(SWAP16(pReFrame->RegData)?!=?RegData) { if?(pError?!=?nullptr)?*pError?=?"數(shù)據(jù)寫(xiě)入錯(cuò)誤,沒(méi)有寫(xiě)入成功!"; return?MRTU_WRITE_ERROR; //寫(xiě)入數(shù)據(jù)錯(cuò)誤 } if?(pError?!=?nullptr)?*pError?=?"寫(xiě)入成功!"; return?MRTU_OK; //返回成功? } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODBUS_RTU::WriteMultRegPack(BYTE?*pPackBuff,?DWORD?*pPackLen,?u8?SlaveAddr,?u16?RegAddr,?u16?pRegData[],?u8?RegNum,?,?char?**pError) *?功能 : 主機(jī)寫(xiě)從機(jī)多個(gè)指定寄存器數(shù)據(jù)打包 *?參數(shù) : pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長(zhǎng)度;SlaveAddr:從機(jī)地址;RegAddr:寫(xiě)寄存器地址;pRegData:需要寫(xiě)入的寄存器的值;RegNum:寄存器數(shù)量;pError:錯(cuò)誤說(shuō)明 *?返回 : true:成功;false:錯(cuò)誤 *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 寫(xiě)多個(gè)寄存器數(shù)據(jù)打包 寫(xiě)入寄存器的值按照循序排列,使用小端格式,大小必須為RegNum*2 最大只能一次寫(xiě)入不超過(guò)127個(gè)寄存器 *************************************************************************************************************************/ 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ū)無(wú)效 { *pPackLen?=?0; if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無(wú)效!"; return?false; //句柄無(wú)效 } pFrame?=?(MRTU_WRITE_MULT_FRAME?*)pPackBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)MRTU_FUN_MWRITE; //功能碼,預(yù)置多個(gè)寄存器 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 if?((RegNum?>?127)?||?(RegNum?==?0)) { *pPackLen?=?0; if?(pError?!=?nullptr)?*pError?=?"一次寫(xiě)入寄存器數(shù)量過(guò)多!"; return?FALSE; //寄存器數(shù)量錯(cuò)誤 } pFrame->RegNum?=?SWAP16(RegNum); //寫(xiě)入寄存器數(shù)量 pFrame->DataLen?=?2?*?RegNum; //數(shù)據(jù)長(zhǎng)度 //循環(huán)寫(xiě)入數(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); //計(jì)算CRC16,高低位對(duì)調(diào)過(guò) 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) *?功能 : 主機(jī)寫(xiě)從機(jī)多個(gè)指定寄存器數(shù)據(jù)解包 *?參數(shù) : pPackBuff:打包緩沖區(qū),pPackLen:打包的數(shù)據(jù)長(zhǎng)度;SlaveAddr:從機(jī)地址;RegAddr:寫(xiě)寄存器地址;RegNum:寄存器數(shù)量;pError:錯(cuò)誤說(shuō)明 *?返回 : MRTU_ERROR *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間: 2016-11-04 *?說(shuō)明 :? 寫(xiě)多個(gè)寄存器數(shù)據(jù)解包 *************************************************************************************************************************/ MRTU_ERROR?MODBUS_RTU::WriteMultRegUnpack(BYTE?*pPackBuff,?DWORD?PackLen,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?char?**pError) { MRTU_WRIT_EMULT_RFRAME?*pReFrame; //返回?cái)?shù)據(jù)幀格式 MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式 u16?crc16; u8?i; if?(pPackBuff?==?nullptr) //緩沖區(qū)無(wú)效 { if?(pError?!=?nullptr)?*pError?=?"緩沖區(qū)無(wú)效!"; return?MRTU_HANDLE_ERROR; //句柄無(wú)效 } if?(PackLen?<?3) { if?(pError?!=?nullptr)?*pError?=?"返回?cái)?shù)據(jù)長(zhǎng)度過(guò)短!"; return?MRTU_LEN_ERROR; //返回?cái)?shù)據(jù)長(zhǎng)度錯(cuò)誤 } pReFrame?=?(MRTU_WRIT_EMULT_RFRAME?*)pPackBuff; //檢查地址 if?(pReFrame->addr?!=?SlaveAddr) { if?(pError?!=?nullptr)?*pError?=?"返回的從機(jī)地址錯(cuò)誤!"; return?MRTU_ADDR_ERROR; } //對(duì)接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn) crc16?=?usMBCRC16(pPackBuff,?PackLen?-?2);//計(jì)算CRC16 if?((pPackBuff[PackLen?-?1]?!=?(crc16?>>?8))?||?(pPackBuff[PackLen?-?2]?!=?(crc16?&?0xff))) { if?(pError?!=?nullptr)?*pError?=?"CRC校驗(yàn)錯(cuò)誤"; return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤 } //返回的功能碼不一致 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?=?"返回功能碼錯(cuò)誤!"; return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)是否寫(xiě)入 if?(SWAP16(pReFrame->StartReg)?!=?RegAddr) //返回的寄存器地址不一致 { if?(pError?!=?nullptr)?*pError?=?"返回寄存器地址錯(cuò)誤!"; return?MRTU_REG_ERROR; //返回寄存器錯(cuò)誤 } if?(SWAP16(pReFrame->RegNum)?!=?RegNum) { if?(pError?!=?nullptr)?*pError?=?"數(shù)據(jù)寫(xiě)入錯(cuò)誤,返回的寄存器數(shù)量不一致!"; return?MRTU_WRITE_ERROR; //寫(xiě)入數(shù)據(jù)錯(cuò)誤 } if?(pError?!=?nullptr)?*pError?=?"寫(xiě)入成功!"; return?MRTU_OK; //返回成功? } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE?*pHandle,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[]) *?功能 : 主機(jī)讀取從機(jī)指定多個(gè)連續(xù)寄存器(需要初始化回調(diào)通信接口) *?參數(shù) : RegType:讀取的寄存器類(lèi)型;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍;pError:錯(cuò)誤信息 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 輸入輸出的數(shù)據(jù)都為小端模式 返回的寄存器的值按照循序存放在pRegData中 需要先初始化通信接口,并且會(huì)申請(qǐng)?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)進(jìn)行 if?(this->pSendDataCollBack?==?nullptr) { if?(pError?==?nullptr)?*pError?=?"發(fā)送回調(diào)函數(shù)無(wú)效!"; 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)進(jìn)行數(shù)據(jù)接收 if?(this->pReadDataCollBack?==?nullptr) { if?(pError?==?nullptr)?*pError?=?"接收回調(diào)函數(shù)無(wú)效!"; 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ù)超時(shí)!"; return?MRTU_TIME_OUT; } if?(len?>?(256?+?7)) { if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)溢出!"; return?MRTU_OVER_ERROR; } //數(shù)據(jù)接收完成了,開(kāi)始解析 return?ReadMultRegUnpack(PackBuff,?len,?RegType,?SlaveAddr,RegAddr,?RegNum,?pRegData,?pError); } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODBUS_RTU::WriteOnetReg(u8?SlaveAddr,?u16?RegAddr,?u16?RegData,?char?**pError) *?功能 : 主機(jī)寫(xiě)入從機(jī)一個(gè)寄存器(需要初始化回調(diào)通信接口) *?參數(shù) : SlaveAddr:從機(jī)地址;RegAddr:寫(xiě)寄存器地址;RegData:寄存器的值;pError:錯(cuò)誤提示 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間 : 2016-11-04 *?說(shuō)明 :? 輸入輸出的數(shù)據(jù)都為小端模式 需要先初始化通信接口,并且會(huì)申請(qǐng)?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)進(jìn)行 if?(this->pSendDataCollBack?==?nullptr) { if?(pError?==?nullptr)?*pError?=?"發(fā)送回調(diào)函數(shù)無(wú)效!"; 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)進(jìn)行數(shù)據(jù)接收 if?(this->pReadDataCollBack?==?nullptr) { if?(pError?==?nullptr)?*pError?=?"接收回調(diào)函數(shù)無(wú)效!"; 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ù)超時(shí)!"; return?MRTU_TIME_OUT; } if?(len?>?(256?+?7)) { if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)溢出!"; return?MRTU_OVER_ERROR; } //數(shù)據(jù)接收完成了,開(kāi)始解析 return?WriteOneRegUnpack(PackBuff,?len,?SlaveAddr,?RegAddr,??RegData,?pError); } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODBUS_RTU::WriteMultReg(u8?SlaveAddr,?u16?RegAddr,?u16?pRegData[],u8?RegNum,??char?**pError) *?功能 : 主機(jī)寫(xiě)從機(jī)多個(gè)指定寄存器(需要初始化回調(diào)通信接口) *?參數(shù) : SlaveAddr:從機(jī)地址;RegAddr:寫(xiě)寄存器地址;RegNum:寄存器數(shù)量;pError:錯(cuò)誤說(shuō)明 *?返回 : MRTU_ERROR *?依賴 : 底層通信驅(qū)動(dòng) *?作者 : cp1300@139.com *?時(shí)間 : 2014-03-24 *?最后修改時(shí)間: 2016-11-04 *?說(shuō)明 :? 寫(xiě)多個(gè)寄存器數(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)進(jìn)行 if?(this->pSendDataCollBack?==?nullptr) { if?(pError?==?nullptr)?*pError?=?"發(fā)送回調(diào)函數(shù)無(wú)效!"; 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)進(jìn)行數(shù)據(jù)接收 if?(this->pReadDataCollBack?==?nullptr) { if?(pError?==?nullptr)?*pError?=?"接收回調(diào)函數(shù)無(wú)效!"; 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ù)超時(shí)!"; return?MRTU_TIME_OUT; } if?(len?>?(256?+?7)) { if?(pError?==?nullptr)?*pError?=?"接收數(shù)據(jù)溢出!"; return?MRTU_OVER_ERROR; } //數(shù)據(jù)接收完成了,開(kāi)始解析 return?WriteMultRegUnpack(PackBuff,?len,?SlaveAddr,?RegAddr,?RegNum,?pError); } //MODBUS?CRC16計(jì)算 //結(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)建時(shí)間: 2014-03-24 *?最后修改時(shí)間: 2016-11-04 *?詳細(xì): MODBUS?RTU通信協(xié)議層 2016-03-21:增加防止接收數(shù)據(jù)過(guò)短導(dǎo)致異常 2016-11-04:增加回調(diào)接口,將數(shù)據(jù)收發(fā)接口使用回調(diào)函數(shù) *************************************************************************************************************/ #ifndef?_MODBUS_RTU_H_ #define?_MODBUS_RTU_H_ #include?"windows.h" //基本數(shù)據(jù)類(lèi)型定義 #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ù)高低對(duì)調(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 //讀保持寄存器,可讀寫(xiě)寄存器為保持寄存器 #define?MRTU_FUN_READ_INPUT 0x04 //讀輸入寄存器,為只讀寄存器 #define?MRTU_FUN_WRITE 0x06 //寫(xiě)單個(gè)保持寄存器 #define?MRTU_FUN_MWRITE 0x10 //寫(xiě)多個(gè)保持寄存器 //大端數(shù)據(jù)標(biāo)記 #define?BIG_U16 u16 //16位整形數(shù),需要轉(zhuǎn)換為大端模式,兼容modubus //讀取寄存器類(lèi)型選擇 typedef?enum { HOLD_REG? =? MRTU_FUN_READ_HOLD, //保持寄存器 INPUT_REG = MRTU_FUN_READ_INPUT, //輸入寄存器 }?READ_REG_TYPE; //數(shù)據(jù)讀取?主機(jī)數(shù)據(jù)幀,主機(jī)讀取從機(jī)的數(shù)據(jù)幀 typedef??struct { u8 addr; //地址?address u8 fun; //功能碼?function BIG_U16 StartReg; //數(shù)據(jù)起始地址 BIG_U16 RegNum; //需要讀取的寄存器個(gè)數(shù) BIG_U16 CRC16; //CRC16 }?MRTU_READ_FRAME; //MODBUS?RTU?master?Read?Reg?Frame //預(yù)置單個(gè)保持寄存器,主機(jī)寫(xiě)從機(jī)單個(gè)寄存器的數(shù)據(jù)幀 //從機(jī)返回?cái)?shù)據(jù)幀與主機(jī)預(yù)置單個(gè)寄存器數(shù)據(jù)幀一樣 typedef??struct { u8 addr; //地址?address u8 fun; //功能碼?function BIG_U16 StartReg; //數(shù)據(jù)起始地址 BIG_U16 RegData; //數(shù)據(jù)值 BIG_U16?crc16; //CRC校驗(yàn)值 }?MRTU_WRITE_FRAME; //MODBUS?RTU?master?Write?Reg?Frame //預(yù)置多個(gè)保持寄存器,主機(jī)寫(xiě)從機(jī)多個(gè)寄存器的數(shù)據(jù)幀 typedef??struct { u8 addr; //地址?address u8 fun; //功能碼?function BIG_U16 StartReg; //數(shù)據(jù)起始地址 BIG_U16 RegNum; //寄存器數(shù)量 u8 DataLen; //數(shù)據(jù)長(zhǎng)度 u8 DataBuff[2]; //寄存器的值 }?MRTU_WRITE_MULT_FRAME; //預(yù)置多個(gè)保持寄存器后返回?cái)?shù)據(jù)幀,從機(jī)返回主機(jī)的數(shù)據(jù)幀 typedef??struct { u8 addr; //地址?address u8 fun; //功能碼?function BIG_U16 StartReg; //數(shù)據(jù)起始地址 BIG_U16 RegNum; //寄存器數(shù)量 BIG_U16?crc16; //CRC校驗(yàn)值 }?MRTU_WRIT_EMULT_RFRAME; //讀取從機(jī)返回?cái)?shù)據(jù)幀格式,從機(jī)返回給主機(jī)的數(shù)據(jù)幀 typedef??struct { u8 addr; //地址?address u8 fun; //功能碼?function u8 DataLen; //數(shù)據(jù)長(zhǎng)度 u8 DataBuff[2]; //數(shù)據(jù)區(qū),CRC16放在最后結(jié)尾處 //MRTU_REG16 CRC16; //CRC16 }?MRTU_RETURN_FRAME; //MODBUS?RTU?master?Read?Reg?Frame //從機(jī)返回的異常數(shù)據(jù)幀,從機(jī)返回的異常數(shù)據(jù)幀 typedef??struct { u8 addr; //地址?address u8 ErrorFun; //錯(cuò)誤功能碼?function+0x80 u8 unu; //異常碼 u8 crc16H; //CRC16放在最后結(jié)尾處 u8 crc16L; //CRC16放在最后結(jié)尾處 }?MRTU_UNU_FRAME; //從機(jī)數(shù)據(jù)包解析后的相關(guān)信息 typedef?struct { u8 SlaveAddr; //主機(jī)發(fā)送的從機(jī)地址 u8? RegNum; //主機(jī)需要讀取從機(jī)的寄存器數(shù)量 u8 fun; //主機(jī)發(fā)送給從機(jī)的功能碼 u16?StartReg; //主機(jī)需要讀寫(xiě)的從機(jī)寄存器地址 }?MRTU_SLAVE_INFO; //異常碼定義 typedef?enum { MRTU_UNUS1 = 0x01, //異常碼1,無(wú)效的操作碼 MRTU_UNUS2 = 0x02, //異常碼2,無(wú)效的數(shù)據(jù)地址 MRTU_UNUS3 = 0x03, //異常碼3,無(wú)效的數(shù)據(jù)值 MRTU_UNUS4 = 0x04, //異常碼4,無(wú)效操作 MRTU_UNUS5 = 0x05, //異常碼5 MRTU_UNUS6 = 0x06, //異常碼6 }?MRTU_UNUS; //錯(cuò)誤狀態(tài) typedef?enum { MRTU_OK? =? 0, //OK MRTU_TIME_OUT? =? 1, //超時(shí) MRTU_OVER_ERROR? =? 2, //溢出 MRTU_CRC_ERROR = 3, //CRC錯(cuò)誤 MRTU_ADDR_ERROR = 4, //地址錯(cuò)誤,返回地址不一致 MRTU_REG_ERROR = 5, //寄存器地址錯(cuò)誤,返回寄存器地址不一致 MRTU_FUNR_ERROR = 6, //功能碼錯(cuò)誤,返回功能碼不一致或者不支持的功能碼 MRTU_HANDLE_ERROR = 7, //通信回調(diào)接口錯(cuò)誤,或緩沖區(qū)錯(cuò)誤 MRTU_REGN_ERROR = 8, //寄存器數(shù)量錯(cuò)誤 MRTU_LEN_ERROR = 9, //返回?cái)?shù)據(jù)長(zhǎng)度錯(cuò)誤 MRTU_WRITE_ERROR = 10, //寫(xiě)寄存器錯(cuò)誤,寫(xiě)入與讀取不一致 MRTU_SEND_ERROR = 11, //發(fā)送數(shù)據(jù)失敗 MRTU_READ_ERROR = 12, //讀取數(shù)據(jù)失敗 MRTU_UNUS1_ERROR = 0x81, //異常碼1,無(wú)效的操作碼 MRTU_UNUS2_ERROR = 0x82, //異常碼2,無(wú)效的數(shù)據(jù)地址 MRTU_UNUS3_ERROR = 0x83, //異常碼3,無(wú)效的數(shù)據(jù)值 MRTU_UNUS4_ERROR = 0x84, //異常碼4,無(wú)效操作 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ù)大?。环祷兀喊l(fā)送成功返回true,發(fā)送失敗返回false //接收回調(diào)函數(shù)定義 typedef?bool(*MODBUS_ReadDataCollBack)(BYTE?*,?DWORD?*); //接收緩沖區(qū)與接收數(shù)據(jù)長(zhǎng)度;返回:讀取成功返回true,讀取失敗,接口錯(cuò)誤返回false,返回true后數(shù)據(jù)長(zhǎng)度為0算作超時(shí),返回false一般都是接口錯(cuò)誤 class?MODBUS_RTU { private: MODBUS_SendDataCollBack?pSendDataCollBack; //發(fā)送回調(diào)函數(shù)指針 MODBUS_ReadDataCollBack?pReadDataCollBack; //接收回調(diào)函數(shù)指針 u16?usMBCRC16(u8?*?pucFrame,?u16?usLen); //crc計(jì)算 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:接收超時(shí)時(shí)間 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; //通信接口錯(cuò)誤 } else { *pDataLen?=?len; return?true; //讀取成功了 } } else { *pDataLen?=?0; //長(zhǎng)度為0,沒(méi)有讀取到數(shù)據(jù) return?true; //通信接口沒(méi)有發(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)指針 //初