C語言編程:單片機(jī)modebus RTU通信實(shí)現(xiàn),可適用于單片機(jī),VC,安卓等
當(dāng)前使用的是STM32+ucos_ii編寫的,可以移植到安卓以及VC .NET等方便移植使用,采用modebus poll測試過.
只需要修改響應(yīng)的通信接口即可,方便多串口使用
//modebus_rtu.c
/************************************************************************************************************* ?*?文件名: MODEBUS_RTU.c ?*?功能: MODEBUS_RTU通信協(xié)議層 ?*?作者: cp1300@139.com ?*?創(chuàng)建時間: 2014-03-24 ?*?最后修改時間:2014-11-17 ?*?詳細(xì): MODEBUS?RTU通信協(xié)議層 *************************************************************************************************************/ #include?"system.h" #include?"usart.h" #include?"delay.h" #include?"MODEBUS_RTU.h" //調(diào)試開關(guān) #define?MODEBUS_RTU_DBUG 1 #if?MODEBUS_RTU_DBUG #include?"system.h" #define?modebus_debug(format,...) uart_printf(format,##__VA_ARGS__) #else #define?modebus_debug(format,...) / / #endif //MODEBUS_RTU_DBUG /************************************************************************************************************************* *?函數(shù) : bool?MODEBUS_Init(MODEBUS_HANDLE?*pHandle,?u8?UartCh,?u32?BaudRate,?u8?*pRxBuff,u8?*pTxBuff,?u32?RxBuffSize,?u32?TimeOut) *?功能 : MODEBUS?初始化 *?參數(shù) : pHandle:當(dāng)前初始化的modebus句柄,UartCh:使用的串口通道;BaudRate:使用的波特率;pRxBuff:接收緩沖區(qū)指針; RxBuffSize:接收緩沖區(qū)大小;pTxBuff:發(fā)送緩沖區(qū)指針;TimeOut:接收超時,單位ms *?返回 : FALSE:初始化失敗;TRUE:初始化成功 *?依賴 : 串口 *?作者 : cp1300@139.com *?時間 : 2014-09-25 *?最后修改時間?:?2014-11-10 *?說明 :? 收發(fā)緩沖區(qū)可以與發(fā)送緩沖區(qū)使用同一緩沖區(qū) 發(fā)送緩沖區(qū)必須大于最大數(shù)據(jù)包大小,否則會出現(xiàn)內(nèi)存溢出 *************************************************************************************************************************/ bool?MODEBUS_Init(MODEBUS_HANDLE?*pHandle,?u8?UartCh,?u32?BaudRate,?u8?*pRxBuff,u8?*pTxBuff,?u32?RxBuffSize,?u32?TimeOut) { if(pHandle?==?NULL)?return?FALSE; pHandle->TxPacketNum?=?0; //發(fā)送數(shù)據(jù)包計數(shù) pHandle->RxPacketNum?=?0; //接收數(shù)據(jù)包計數(shù) pHandle->ErrorNum?=?0; //通信錯誤計數(shù) pHandle->ReturnTime?=?0; //數(shù)據(jù)返回時間 //設(shè)置串口 if(MODEBUS_UartInit(UartCh,?BaudRate)?==?FALSE) //初始化串口 { pHandle->UartCh?=?0xff; //通道無效 pHandle->pRxBuff?=?pHandle->pTxBuff?=?NULL; //緩沖區(qū)無效 pHandle->RxBuffSize?=?0; //緩沖區(qū)大小為0 } MODEBUS_SetRxBuff(UartCh,?pRxBuff,?RxBuffSize); MODEBUS_DisableRx(UartCh); //關(guān)閉串口接收 pHandle->UartCh?=?UartCh; //通道 pHandle->pRxBuff?=?pRxBuff; pHandle->pTxBuff?=?pTxBuff; //緩沖區(qū) pHandle->RxBuffSize?=?RxBuffSize; //緩沖區(qū)大小 if(TimeOut?==?0)?TimeOut?=?1; pHandle->TimeOut?=?TimeOut; pHandle->BaudRate?=?BaudRate; return?TRUE; } #if(MODEBUS_RTU_HOST)?//開啟主機(jī)模式 /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_HOST_ReadReg(MODEBUS_HANDLE?*pHandle,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u16?*pRegData) *?功能 : 主機(jī)讀取從機(jī)一個指定寄存器 *?參數(shù) : pHandle:modebus句柄;RegType:讀取的寄存器類型;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;pRegData:寄存器的值 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU讀取數(shù)據(jù),讀取一個寄存器 輸入輸出的數(shù)據(jù)都為小端模式 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_HOST_ReadReg(MODEBUS_HANDLE?*pHandle,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u16?*pRegData) { MRTU_READ_FRAME?*pFrame; //發(fā)送數(shù)據(jù)幀格式 MRTU_RETURN_FRAME?*pReFrame; //返回數(shù)據(jù)幀格式 MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式 u16?crc16; u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計數(shù)器 u16?TimeOut; u16?TimeDelay?=?0; //用于計算數(shù)據(jù)接收延時 if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 TimeOut?=?pHandle->TimeOut/10+1; //超時初值 pFrame?=?(MRTU_READ_FRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)RegType; //功能碼,讀取 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 pFrame->RegNum?=?SWAP16(1); //需要讀取的寄存器數(shù)量,1 crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計算CRC16 pFrame->CRC16?=?crc16; //crc16 #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn?MODEBUS?RTU?RXD(%dB)(ping:%dmS):rn",cnt1,TimeDelay*10); for(i?=?0;i?<?cnt1;i?++) { modebus_debug("0x%02X?",?pHandle->pRxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG pReFrame?=?(MRTU_RETURN_FRAME?*)pHandle->pRxBuff; //檢查地址 if(pReFrame->addr?!=?SlaveAddr) { modebus_debug("地址錯誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr); return?MRTU_ADDR_ERROR; } //對接受的數(shù)據(jù)進(jìn)行CRC校驗 crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計算CRC16 if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff))) { modebus_debug("CRC校驗錯誤,計算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]); return?MRTU_CRC_ERROR; //返回CRC校驗錯誤 } //返回的功能碼不一致 if(pReFrame->fun?!=?(u8)RegType) { pUnuFrame?=?(MRTU_UNU_FRAME?*)pHandle->pRxBuff; //異常數(shù)據(jù)幀 if(pUnuFrame->ErrorFun?==?((u8)RegType|0x80)) //返回有異常 { modebus_debug("返回異常,異常碼%drn",?pUnuFrame->unu); switch(pUnuFrame->unu) { case?1:?return?MRTU_UNUS1_ERROR; //異常碼1 case?2:?return?MRTU_UNUS2_ERROR; //異常碼2 case?3:?return?MRTU_UNUS3_ERROR; //異常碼3 case?4:?return?MRTU_UNUS4_ERROR; //異常碼4 case?5:?return?MRTU_UNUS5_ERROR; //異常碼5 case?6:?return?MRTU_UNUS6_ERROR; //異常碼6 default:?return?MRTU_OTHER_ERROR; } } else { modebus_debug("返回錯誤,返回功能碼為0x%02Xrn",?pReFrame->fun); return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)長度 if(pReFrame->DataLen?!=?2) { modebus_debug("返回數(shù)據(jù)長度錯誤,讀取%d個寄存器,共%dB,只返回了%dBrn",1,?1*2,?pReFrame->DataLen); return?MRTU_LEN_ERROR; //返回數(shù)據(jù)長度錯誤 } //獲取返回的寄存器的值 *pRegData?=?pReFrame->DataBuff[0]; *pRegData?<DataBuff[1]; 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ī)指定多個連續(xù)寄存器 *?參數(shù) : pHandle:modebus句柄;RegType:讀取的寄存器類型;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍 返回的寄存器的值按照循序存放在pRegData中 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU讀取數(shù)據(jù),讀取一個寄存器 輸入輸出的數(shù)據(jù)都為小端模式 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE?*pHandle,?READ_REG_TYPE?RegType,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[]) { MRTU_READ_FRAME?*pFrame; //發(fā)送數(shù)據(jù)幀格式 MRTU_RETURN_FRAME?*pReFrame; //返回數(shù)據(jù)幀格式 MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式 u16?crc16; u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計數(shù)器 u16?TimeOut; u16?TimeDelay?=?0; //用于計算數(shù)據(jù)接收延時 u8?i; if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 TimeOut?=?pHandle->TimeOut/10+1; //超時初值 pFrame?=?(MRTU_READ_FRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)RegType; //功能碼,讀取 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 if((RegNum?>?127)?||?(RegNum?==?0)) return?MRTU_REGN_ERROR; //寄存器數(shù)量錯誤 pFrame->RegNum?=?SWAP16(RegNum); //需要讀取的寄存器數(shù)量 crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計算CRC16 pFrame->CRC16?=?crc16; //crc16 #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn?MODEBUS?RTU?RXD(%dB)(ping:%dmS):rn",cnt1,TimeDelay*10); for(i?=?0;i?<?cnt1;i?++) { modebus_debug("0x%02X?",?pHandle->pRxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG pReFrame?=?(MRTU_RETURN_FRAME?*)pHandle->pRxBuff; //檢查地址 if(pReFrame->addr?!=?SlaveAddr) { modebus_debug("地址錯誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr); return?MRTU_ADDR_ERROR; } //對接受的數(shù)據(jù)進(jìn)行CRC校驗 crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計算CRC16 if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff))) { modebus_debug("CRC校驗錯誤,計算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]); return?MRTU_CRC_ERROR; //返回CRC校驗錯誤 } //返回的功能碼不一致 if(pReFrame->fun?!=?(u8)RegType) { pUnuFrame?=?(MRTU_UNU_FRAME?*)pHandle->pRxBuff; //異常數(shù)據(jù)幀 if(pUnuFrame->ErrorFun?==?((u8)RegType|0x80)) //返回有異常 { modebus_debug("返回異常,異常碼%drn",?pUnuFrame->unu); switch(pUnuFrame->unu) { case?1:?return?MRTU_UNUS1_ERROR; //異常碼1 case?2:?return?MRTU_UNUS2_ERROR; //異常碼2 case?3:?return?MRTU_UNUS3_ERROR; //異常碼3 case?4:?return?MRTU_UNUS4_ERROR; //異常碼4 case?5:?return?MRTU_UNUS5_ERROR; //異常碼5 case?6:?return?MRTU_UNUS6_ERROR; //異常碼6 default:?return?MRTU_OTHER_ERROR; } } else { modebus_debug("返回錯誤,返回功能碼為0x%02Xrn",?pReFrame->fun); return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)長度 if(pReFrame->DataLen?!=?(RegNum*2)) { modebus_debug("返回數(shù)據(jù)長度錯誤,讀取%d個寄存器,共%dB,只返回了%dBrn",RegNum,?RegNum*2,?pReFrame->DataLen); return?MRTU_LEN_ERROR; //返回數(shù)據(jù)長度錯誤 } //獲取返回的寄存器的值 for(i?=?0;i?<?RegNum;i?++) { pRegData[i]?=?pReFrame->DataBuff[i*2]; pRegData[i]?<DataBuff[i*2+1]; } return?MRTU_OK; //返回成功? } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_HOST_WriteReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u16?RegData) *?功能 : 主機(jī)寫從機(jī)一個指定寄存器 *?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;RegAddr:寫寄存器地址;RegData:寄存器的值 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU寫從機(jī)一個保持寄存器 輸入輸出的數(shù)據(jù)都為小端模式 預(yù)置單個寄存器的發(fā)送與接收數(shù)據(jù)包格式完全一致,理論上發(fā)送與接收的數(shù)據(jù)都應(yīng)該一致 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_HOST_WriteReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u16?RegData) { MRTU_WRITE_FRAME?*pFrame,?*pReFrame;//發(fā)送數(shù)據(jù)幀格式 MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式 u16?crc16; u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計數(shù)器 u16?TimeOut; u16?TimeDelay?=?0; //用于計算數(shù)據(jù)接收延時 if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 TimeOut?=?pHandle->TimeOut/10+1; //超時初值 pFrame?=?(MRTU_WRITE_FRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)MRTU_FUN_WRITE; //功能碼,預(yù)置單個寄存器 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 pFrame->RegData?=?SWAP16(RegData); //寫入寄存器內(nèi)容 pFrame->crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計算CRC16 #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn?MODEBUS?RTU?RXD(%dB)(ping:%dmS):rn",cnt1,TimeDelay*10); for(i?=?0;i?<?cnt1;i?++) { modebus_debug("0x%02X?",?pHandle->pRxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG pReFrame?=?(MRTU_WRITE_FRAME?*)pHandle->pRxBuff; //檢查地址 if(pReFrame->addr?!=?SlaveAddr) { modebus_debug("地址錯誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr); return?MRTU_ADDR_ERROR; } //對接受的數(shù)據(jù)進(jìn)行CRC校驗 crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計算CRC16 if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff))) { modebus_debug("CRC校驗錯誤,計算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]); return?MRTU_CRC_ERROR; //返回CRC校驗錯誤 } //返回的功能碼不一致 if(pReFrame->fun?!=?(u8)MRTU_FUN_WRITE) { pUnuFrame?=?(MRTU_UNU_FRAME?*)pHandle->pRxBuff; //異常數(shù)據(jù)幀 if(pUnuFrame->ErrorFun?==?((u8)MRTU_FUN_WRITE|0x80))//返回有異常 { modebus_debug("返回異常,異常碼%drn",?pUnuFrame->unu); switch(pUnuFrame->unu) { case?1:?return?MRTU_UNUS1_ERROR; //異常碼1 case?2:?return?MRTU_UNUS2_ERROR; //異常碼2 case?3:?return?MRTU_UNUS3_ERROR; //異常碼3 case?4:?return?MRTU_UNUS4_ERROR; //異常碼4 case?5:?return?MRTU_UNUS5_ERROR; //異常碼5 case?6:?return?MRTU_UNUS6_ERROR; //異常碼6 default:?return?MRTU_OTHER_ERROR; } } else { modebus_debug("返回錯誤,返回功能碼為0x%02Xrn",?pReFrame->fun); return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)是否寫入 if(SWAP16(pReFrame->StartReg)?!=?RegAddr) //返回的寄存器地址不一致 { modebus_debug("返回寄存器地址錯誤,寫入寄存器%d,返回寄存器%drn",RegAddr,?pReFrame->StartReg); return?MRTU_REG_ERROR; //返回寄存器錯誤 } if(SWAP16(pReFrame->RegData)?!=?RegData) { modebus_debug("數(shù)據(jù)寫入錯誤,寫入值:0x%04X,返回了:0x%04Xrn",RegData,?pReFrame->RegData); return?MRTU_WRITE_ERROR; //寫入數(shù)據(jù)錯誤 } return?MRTU_OK; //返回成功? } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_HOST_WriteMultReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[]) *?功能 : 主機(jī)寫從機(jī)多個指定寄存器 *?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;RegAddr:寫寄存器地址;RegNum:寄存器數(shù)量,?pRegData:需要寫入的寄存器的值 寫入寄存器的值按照循序排列,使用小端格式,大小必須為RegNum*2 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU寫從機(jī)一個保持寄存器 輸入輸出的數(shù)據(jù)都為小端模式 返回數(shù)據(jù)寄存器位置與寄存器數(shù)量 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_HOST_WriteMultReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[]) { MRTU_WRITE_MULT_FRAME?*pFrame; //發(fā)送數(shù)據(jù)幀格式 MRTU_WRIT_EMULT_RFRAME?*pReFrame; //返回數(shù)據(jù)幀格式 MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式 u16?crc16; u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計數(shù)器 u16?TimeOut; u16?TimeDelay?=?0; //用于計算數(shù)據(jù)接收延時 u8?i; if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 TimeOut?=?pHandle->TimeOut/10+1; //超時初值 pFrame?=?(MRTU_WRITE_MULT_FRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?(u8)MRTU_FUN_MWRITE; //功能碼,預(yù)置多個寄存器 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 if((RegNum?>?127)?||?(RegNum?==?0)) return?MRTU_REGN_ERROR; //寄存器數(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(pHandle->pTxBuff,?7+pFrame->DataLen); //計算CRC16,高低位對調(diào)過 pFrame->DataBuff[pFrame->DataLen]?=?crc16&0xff; //高位 pFrame->DataBuff[pFrame->DataLen+1]=crc16>>8; //低位 #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn?MODEBUS?RTU?RXD(%dB)(ping:%dmS):rn",cnt1,TimeDelay*10); for(i?=?0;i?<?cnt1;i?++) { modebus_debug("0x%02X?",?pHandle->pRxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG pReFrame?=?(MRTU_WRIT_EMULT_RFRAME?*)pHandle->pRxBuff; //檢查地址 if(pReFrame->addr?!=?SlaveAddr) { modebus_debug("地址錯誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr); return?MRTU_ADDR_ERROR; } //對接受的數(shù)據(jù)進(jìn)行CRC校驗 crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計算CRC16 if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff))) { modebus_debug("CRC校驗錯誤,計算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]); return?MRTU_CRC_ERROR; //返回CRC校驗錯誤 } //返回的功能碼不一致 if(pReFrame->fun?!=?(u8)MRTU_FUN_MWRITE) { pUnuFrame?=?(MRTU_UNU_FRAME?*)pHandle->pRxBuff; //異常數(shù)據(jù)幀 if(pUnuFrame->ErrorFun?==?((u8)MRTU_FUN_MWRITE|0x80))//返回有異常 { modebus_debug("返回異常,異常碼%drn",?pUnuFrame->unu); switch(pUnuFrame->unu) { case?1:?return?MRTU_UNUS1_ERROR; //異常碼1 case?2:?return?MRTU_UNUS2_ERROR; //異常碼2 case?3:?return?MRTU_UNUS3_ERROR; //異常碼3 case?4:?return?MRTU_UNUS4_ERROR; //異常碼4 case?5:?return?MRTU_UNUS5_ERROR; //異常碼5 case?6:?return?MRTU_UNUS6_ERROR; //異常碼6 default:?return?MRTU_OTHER_ERROR; } } else { modebus_debug("返回錯誤,返回功能碼為0x%02Xrn",?pReFrame->fun); return?MRTU_FUNR_ERROR; } } //判斷數(shù)據(jù)是否寫入 if(SWAP16(pReFrame->StartReg)?!=?RegAddr) //返回的寄存器地址不一致 { modebus_debug("返回寄存器地址錯誤,寫入寄存器%d,返回寄存器%drn",RegAddr,?pReFrame->StartReg); return?MRTU_REG_ERROR; //返回寄存器錯誤 } if(SWAP16(pReFrame->RegNum)?!=?RegNum) { modebus_debug("寫入寄存器數(shù)量錯誤,寫入%d個寄存器,返回%d個寄存器rn",RegNum,?pReFrame->RegNum); return?MRTU_WRITE_ERROR; //寫入數(shù)據(jù)錯誤 } return?MRTU_OK; //返回成功? } #endif?//MODEBUS_RTU_HOST #if(MODEBUS_RTU_SLAVE)?//開啟從機(jī)模式 /************************************************************************************************************************* *?函數(shù) : bool?MODEBUS_SLAVE_RetrunUnu(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u8?Fun,?MRTU_UNUS?Unus) *?功能 : 從機(jī)返回異常編碼 *?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;Fun:來自主機(jī)的功能碼;Unus:異常碼,見MRTU_UNUS *?返回 : TRUE:發(fā)送成功;FALSE:發(fā)送失敗 *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-17 *?說明 :? 從機(jī)返回異常碼給主機(jī),異常碼見:MRTU_UNUS MRTU_UNUS1 異常碼1,無效的操作碼 MRTU_UNUS2 異常碼2,無效的數(shù)據(jù)地址 MRTU_UNUS3 異常碼3,無效的數(shù)據(jù)值 MRTU_UNUS4 異常碼4,無效操作 MRTU_UNUS5 異常碼5 MRTU_UNUS6 異常碼6 *************************************************************************************************************************/ bool?MODEBUS_SLAVE_RetrunUnu(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u8?Fun,?MRTU_UNUS?Unus) { MRTU_UNU_FRAME?*pFrame; //返回異常數(shù)據(jù)包 u16?crc16; if(pHandle?==?NULL)?return?FALSE; //句柄無效 //數(shù)據(jù)結(jié)構(gòu)填充 pFrame?=?(MRTU_UNU_FRAME?*)pHandle->pTxBuff; pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->ErrorFun?=?(u8)Fun|0x80; //功能碼+0x80,出現(xiàn)異常 pFrame->unu?=?(u8)Unus; //異常編碼 crc16?=?usMBCRC16(pHandle->pTxBuff,?3); //計算CRC16,高低位對調(diào)過 pFrame->crc16H?=?crc16?&?0xff; pFrame->crc16L?=?crc16>>8; #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn?MODEBUS?RTU?RXD(%dB)(CRC:0x%04X):rn",DataLen,crc16); for(i?=?0;i?<?DataLen;i?++) { modebus_debug("0x%02X?",pHandle->pRxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG if((pHandle->pRxBuff[DataLen-1]?==?(crc16?>>?8))?&&?(pHandle->pRxBuff[DataLen-2]?==?(crc16?&?0xff))) { //判斷功能碼 switch(pHandle->pRxBuff[1]) { case?MRTU_FUN_READ_HOLD : //0x03讀保持寄存器,可讀寫寄存器為保持寄存器 case?MRTU_FUN_READ_INPUT : //0x04讀輸入寄存器,為只讀寄存器 { pReadFrame?=?(MRTU_READ_FRAME?*)pHandle->pRxBuff; if((SWAP16(pReadFrame->RegNum)?>?127)?||?(SWAP16(pReadFrame->RegNum)?==?0)) { modebus_debug("讀取寄存器數(shù)量錯誤,讀取寄存器數(shù)量為:%drn",?SWAP16(pReadFrame->RegNum)); MODEBUS_SLAVE_RetrunUnu(pHandle,?pHandle->pRxBuff[0],?pHandle->pRxBuff[1],?MRTU_UNUS2); //返回異常2 return?MRTU_REGN_ERROR; //寄存器數(shù)量錯誤 } }break; case?MRTU_FUN_WRITE :break; //0x06寫單個保持寄存器 case?MRTU_FUN_MWRITE : //0x10寫多個保持寄存器 { pWriteMultFrame?=?(MRTU_WRITE_MULT_FRAME?*)pHandle->pRxBuff; if((SWAP16(pWriteMultFrame->RegNum)?>?127)?||?(SWAP16(pWriteMultFrame->RegNum)?==?0)) { modebus_debug("寫寄存器數(shù)量錯誤,讀取寄存器數(shù)量為:%drn",?SWAP16(pWriteMultFrame->RegNum)); MODEBUS_SLAVE_RetrunUnu(pHandle,?pHandle->pRxBuff[0],?pHandle->pRxBuff[1],?MRTU_UNUS2); //返回異常2 return?MRTU_REGN_ERROR; //寄存器數(shù)量錯誤 } else?if(pWriteMultFrame->DataLen?!=?(2*SWAP16(pWriteMultFrame->RegNum))) { modebus_debug("寫寄存器數(shù)據(jù)長度錯誤,需要寫入%d個寄存器,長度為:%dB,收到數(shù)據(jù)長度為:%dBrn",?pWriteMultFrame->RegNum,?2*pWriteMultFrame->RegNum,?pWriteMultFrame->DataLen); MODEBUS_SLAVE_RetrunUnu(pHandle,?pHandle->pRxBuff[0],?pHandle->pRxBuff[1],?MRTU_UNUS3); //返回異常3 return?MRTU_REGN_ERROR; //寄存器數(shù)量錯誤 } }break; default: //不支持的功能碼,返回異常1 { modebus_debug("不支持的操作碼:0x%02Xrn",?pHandle->pRxBuff[1]); MODEBUS_SLAVE_RetrunUnu(pHandle,?pHandle->pRxBuff[0],?pHandle->pRxBuff[1],?MRTU_UNUS1); //返回異常1 return?MRTU_FUNR_ERROR; } } *pFun?=?pHandle->pRxBuff[1]; //返回功能碼 return?MRTU_OK; //返回成功 } else { modebus_debug("CRC校驗錯誤,計算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[DataLen-2]<pRxBuff[DataLen-1]); return?MRTU_CRC_ERROR; //返回CRC校驗錯誤 } } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_SLAVE_ReturnReadReg(MODEBUS_HANDLE?*pHandle,?u8?Fun,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[]) *?功能 : 從機(jī)返回主機(jī)讀取的寄存器 *?參數(shù) : pHandle:modebus句柄;Fun:讀取的功能碼;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍 返回的寄存器的值按照循序存放在pRegData中 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU主機(jī)讀取從機(jī)的指定寄存器,可以為保持寄存器,也可以為輸入寄存器,可以一次讀取多個 輸入輸出的數(shù)據(jù)都為小端模式 注意:如果直接使用數(shù)據(jù)幀的寄存器數(shù)量以及地址,必須高地位交換 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_SLAVE_ReturnReadReg(MODEBUS_HANDLE?*pHandle,?u8?Fun,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[]) { MRTU_RETURN_FRAME?*pFrame; //返回數(shù)據(jù)幀格式 u16?crc16; u8?i; if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 if((Fun?!=?MRTU_FUN_READ_INPUT)?&&?(Fun?!=?MRTU_FUN_READ_HOLD))?return?MRTU_FUNR_ERROR; //功能碼錯誤 if((RegNum?>?127)?||?(RegNum?==?0)) return?MRTU_REGN_ERROR; //寄存器數(shù)量錯誤 pFrame?=?(MRTU_RETURN_FRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?Fun; //功能碼,讀取 pFrame->DataLen?=?2*RegNum; //數(shù)據(jù)長度 //循環(huán)寫入返回的數(shù)據(jù) for(i?=?0;i?<?RegNum;i?++) { pFrame->DataBuff[2*i]?=?pRegData[i]>>8; //數(shù)據(jù)高位 pFrame->DataBuff[2*i+1]?=?pRegData[i]&0xff; //數(shù)據(jù)低位 } crc16?=?usMBCRC16(pHandle->pTxBuff,?3+pFrame->DataLen);//計算CRC16 pFrame->DataBuff[pFrame->DataLen]?=?crc16&0xff; //數(shù)據(jù)發(fā)送交換過 pFrame->DataBuff[pFrame->DataLen+1]?=?crc16>>8; //數(shù)據(jù)發(fā)送交換過 #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn<-?MODEBUS?RTU?TXD(%dB)(CRC:0x%04X):rn",3+pFrame->DataLen+2,crc16); for(i?=?0;i?<?3+pFrame->DataLen+2;i?++) { modebus_debug("0x%02X?",pHandle->pTxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG MODEBUS_SendData(pHandle->UartCh,?pHandle->pTxBuff,?3+pFrame->DataLen+2); //發(fā)送數(shù)據(jù) return?MRTU_OK; //返回成功? } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_SLAVE_ReturnWriteHoldReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u16?RegData) *?功能 : 從機(jī)返回主機(jī)預(yù)置單個保持寄存器 *?參數(shù) : pHandle:modebus句柄;Fun:讀取的功能碼;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegData:返回寄存器的值 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU主機(jī)寫單個寄存器成功后返回 輸入輸出的數(shù)據(jù)都為小端模式 注意:如果直接使用數(shù)據(jù)幀的寄存器數(shù)量以及地址,必須高地位交換 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_SLAVE_ReturnWriteHoldReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u16?RegData) { MRTU_WRITE_FRAME?*pFrame; //返回數(shù)據(jù)幀格式 u16?crc16; if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 pFrame?=?(MRTU_WRITE_FRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?MRTU_FUN_WRITE; //功能碼,預(yù)置單個寄存器 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器地址 pFrame->RegData?=?SWAP16(RegData); //寄存器的值 pFrame->crc16?=?usMBCRC16(pHandle->pTxBuff,?6);//計算CRC16 #if?MODEBUS_RTU_DBUG { u16?i; modebus_debug("rn<-?MODEBUS?RTU?TXD(%dB)(CRC:0x%04X):rn",8,crc16); for(i?=?0;i?<?8;i?++) { modebus_debug("0x%02X?",pHandle->pTxBuff[i]); } modebus_debug("rn"); } #endif //MODEBUS_RTU_DBUG MODEBUS_SendData(pHandle->UartCh,?pHandle->pTxBuff,?8); //發(fā)送數(shù)據(jù) return?MRTU_OK; //返回成功? } /************************************************************************************************************************* *?函數(shù) : MRTU_ERROR?MODEBUS_SLAVE_ReturnWriteMultHoldReg(MODEBUS_HANDLE?*pHandle,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum) *?功能 : 從機(jī)返回主機(jī)預(yù)置多個保持寄存器 *?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:需要讀取的寄存器數(shù)量 *?返回 : MRTU_ERROR:通信狀態(tài) *?依賴 : 底層通信驅(qū)動 *?作者 : cp1300@139.com *?時間 : 2014-03-24 *?最后修改時間?:?2014-11-16 *?說明 :? MOUEBUS?RTU主機(jī)寫單個寄存器成功后返回 輸入輸出的數(shù)據(jù)都為小端模式 注意:如果直接使用數(shù)據(jù)幀的寄存器數(shù)量以及地址,必須高地位交換 *************************************************************************************************************************/ MRTU_ERROR?MODEBUS_SLAVE_ReturnWriteMultHoldReg(MODEBUS_HANDLE?*pHandle,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum) { MRTU_WRIT_EMULT_RFRAME?*pFrame; //返回數(shù)據(jù)幀格式 if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效 if((RegNum?>?127)?||?(RegNum?==?0)) return?MRTU_REGN_ERROR; //寄存器數(shù)量錯誤 pFrame?=?(MRTU_WRIT_EMULT_RFRAME?*)pHandle->pTxBuff; //數(shù)據(jù)結(jié)構(gòu)填充 pFrame->addr?=?SlaveAddr; //從機(jī)地址 pFrame->fun?=?MRTU_FUN_MWRITE; //功能碼,預(yù)置多個寄存器 pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址 pFrame->RegNum?=?SWAP16(RegNum); //寄存器數(shù)量 pFrame->crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計算CRC16