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)建時(shí)間: 2014-03-24
?*?最后修改時(shí)間: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:接收超時(shí),單位ms
*?返回 : FALSE:初始化失敗;TRUE:初始化成功
*?依賴 : 串口
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-09-25
*?最后修改時(shí)間?:?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ù)包計(jì)數(shù)
pHandle->RxPacketNum?=?0; //接收數(shù)據(jù)包計(jì)數(shù)
pHandle->ErrorNum?=?0; //通信錯(cuò)誤計(jì)數(shù)
pHandle->ReturnTime?=?0; //數(shù)據(jù)返回時(shí)間
//設(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ī)一個(gè)指定寄存器
*?參數(shù) : pHandle:modebus句柄;RegType:讀取的寄存器類型;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;pRegData:寄存器的值
*?返回 : MRTU_ERROR:通信狀態(tài)
*?依賴 : 底層通信驅(qū)動
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU讀取數(shù)據(jù),讀取一個(gè)寄存器
輸入輸出的數(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; //返回?cái)?shù)據(jù)幀格式
MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式
u16?crc16;
u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計(jì)數(shù)器
u16?TimeOut;
u16?TimeDelay?=?0; //用于計(jì)算數(shù)據(jù)接收延時(shí)
if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效
TimeOut?=?pHandle->TimeOut/10+1; //超時(shí)初值
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); //計(jì)算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("地址錯(cuò)誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr);
return?MRTU_ADDR_ERROR;
}
//對接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn)
crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計(jì)算CRC16
if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff)))
{
modebus_debug("CRC校驗(yàn)錯(cuò)誤,計(jì)算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]);
return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤
}
//返回的功能碼不一致
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("返回錯(cuò)誤,返回功能碼為0x%02Xrn",?pReFrame->fun);
return?MRTU_FUNR_ERROR;
}
}
//判斷數(shù)據(jù)長度
if(pReFrame->DataLen?!=?2)
{
modebus_debug("返回?cái)?shù)據(jù)長度錯(cuò)誤,讀取%d個(gè)寄存器,共%dB,只返回了%dBrn",1,?1*2,?pReFrame->DataLen);
return?MRTU_LEN_ERROR; //返回?cái)?shù)據(jù)長度錯(cuò)誤
}
//獲取返回的寄存器的值
*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ī)指定多個(gè)連續(xù)寄存器
*?參數(shù) : pHandle:modebus句柄;RegType:讀取的寄存器類型;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:寄存器數(shù)量;pRegData:返回寄存器的值,至少為RegNum的2倍
返回的寄存器的值按照循序存放在pRegData中
*?返回 : MRTU_ERROR:通信狀態(tài)
*?依賴 : 底層通信驅(qū)動
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU讀取數(shù)據(jù),讀取一個(gè)寄存器
輸入輸出的數(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; //返回?cái)?shù)據(jù)幀格式
MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式
u16?crc16;
u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計(jì)數(shù)器
u16?TimeOut;
u16?TimeDelay?=?0; //用于計(jì)算數(shù)據(jù)接收延時(shí)
u8?i;
if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效
TimeOut?=?pHandle->TimeOut/10+1; //超時(shí)初值
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ù)量錯(cuò)誤
pFrame->RegNum?=?SWAP16(RegNum); //需要讀取的寄存器數(shù)量
crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計(jì)算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("地址錯(cuò)誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr);
return?MRTU_ADDR_ERROR;
}
//對接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn)
crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計(jì)算CRC16
if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff)))
{
modebus_debug("CRC校驗(yàn)錯(cuò)誤,計(jì)算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]);
return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤
}
//返回的功能碼不一致
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("返回錯(cuò)誤,返回功能碼為0x%02Xrn",?pReFrame->fun);
return?MRTU_FUNR_ERROR;
}
}
//判斷數(shù)據(jù)長度
if(pReFrame->DataLen?!=?(RegNum*2))
{
modebus_debug("返回?cái)?shù)據(jù)長度錯(cuò)誤,讀取%d個(gè)寄存器,共%dB,只返回了%dBrn",RegNum,?RegNum*2,?pReFrame->DataLen);
return?MRTU_LEN_ERROR; //返回?cái)?shù)據(jù)長度錯(cuò)誤
}
//獲取返回的寄存器的值
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ī)一個(gè)指定寄存器
*?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;RegAddr:寫寄存器地址;RegData:寄存器的值
*?返回 : MRTU_ERROR:通信狀態(tài)
*?依賴 : 底層通信驅(qū)動
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU寫從機(jī)一個(gè)保持寄存器
輸入輸出的數(shù)據(jù)都為小端模式
預(yù)置單個(gè)寄存器的發(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ù)計(jì)數(shù)器
u16?TimeOut;
u16?TimeDelay?=?0; //用于計(jì)算數(shù)據(jù)接收延時(shí)
if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效
TimeOut?=?pHandle->TimeOut/10+1; //超時(shí)初值
pFrame?=?(MRTU_WRITE_FRAME?*)pHandle->pTxBuff;
//數(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); //寫入寄存器內(nèi)容
pFrame->crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計(jì)算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("地址錯(cuò)誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr);
return?MRTU_ADDR_ERROR;
}
//對接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn)
crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計(jì)算CRC16
if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff)))
{
modebus_debug("CRC校驗(yàn)錯(cuò)誤,計(jì)算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]);
return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤
}
//返回的功能碼不一致
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("返回錯(cuò)誤,返回功能碼為0x%02Xrn",?pReFrame->fun);
return?MRTU_FUNR_ERROR;
}
}
//判斷數(shù)據(jù)是否寫入
if(SWAP16(pReFrame->StartReg)?!=?RegAddr) //返回的寄存器地址不一致
{
modebus_debug("返回寄存器地址錯(cuò)誤,寫入寄存器%d,返回寄存器%drn",RegAddr,?pReFrame->StartReg);
return?MRTU_REG_ERROR; //返回寄存器錯(cuò)誤
}
if(SWAP16(pReFrame->RegData)?!=?RegData)
{
modebus_debug("數(shù)據(jù)寫入錯(cuò)誤,寫入值:0x%04X,返回了:0x%04Xrn",RegData,?pReFrame->RegData);
return?MRTU_WRITE_ERROR; //寫入數(shù)據(jù)錯(cuò)誤
}
return?MRTU_OK; //返回成功?
}
/*************************************************************************************************************************
*?函數(shù) : MRTU_ERROR?MODEBUS_HOST_WriteMultReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u8?RegNum,?u16?pRegData[])
*?功能 : 主機(jī)寫從機(jī)多個(gè)指定寄存器
*?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;RegAddr:寫寄存器地址;RegNum:寄存器數(shù)量,?pRegData:需要寫入的寄存器的值
寫入寄存器的值按照循序排列,使用小端格式,大小必須為RegNum*2
*?返回 : MRTU_ERROR:通信狀態(tài)
*?依賴 : 底層通信驅(qū)動
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU寫從機(jī)一個(gè)保持寄存器
輸入輸出的數(shù)據(jù)都為小端模式
返回?cái)?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; //返回?cái)?shù)據(jù)幀格式
MRTU_UNU_FRAME *pUnuFrame; //返回的異常數(shù)據(jù)幀格式
u16?crc16;
u16?cnt1,?cnt2=0; //接收數(shù)據(jù)計(jì)數(shù)器
u16?TimeOut;
u16?TimeDelay?=?0; //用于計(jì)算數(shù)據(jù)接收延時(shí)
u8?i;
if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效
TimeOut?=?pHandle->TimeOut/10+1; //超時(shí)初值
pFrame?=?(MRTU_WRITE_MULT_FRAME?*)pHandle->pTxBuff;
//數(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)) return?MRTU_REGN_ERROR; //寄存器數(shù)量錯(cuò)誤
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); //計(jì)算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("地址錯(cuò)誤,目標(biāo)地址為:0x%02X,返回地址為:0x%02Xrn",SlaveAddr,?pReFrame->addr);
return?MRTU_ADDR_ERROR;
}
//對接受的數(shù)據(jù)進(jìn)行CRC校驗(yàn)
crc16?=?usMBCRC16(pHandle->pRxBuff,?cnt1-2);//計(jì)算CRC16
if((pHandle->pRxBuff[cnt1-1]?!=?(crc16?>>?8))?||?(pHandle->pRxBuff[cnt1-2]?!=?(crc16?&?0xff)))
{
modebus_debug("CRC校驗(yàn)錯(cuò)誤,計(jì)算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<pRxBuff[cnt1-1]);
return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤
}
//返回的功能碼不一致
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("返回錯(cuò)誤,返回功能碼為0x%02Xrn",?pReFrame->fun);
return?MRTU_FUNR_ERROR;
}
}
//判斷數(shù)據(jù)是否寫入
if(SWAP16(pReFrame->StartReg)?!=?RegAddr) //返回的寄存器地址不一致
{
modebus_debug("返回寄存器地址錯(cuò)誤,寫入寄存器%d,返回寄存器%drn",RegAddr,?pReFrame->StartReg);
return?MRTU_REG_ERROR; //返回寄存器錯(cuò)誤
}
if(SWAP16(pReFrame->RegNum)?!=?RegNum)
{
modebus_debug("寫入寄存器數(shù)量錯(cuò)誤,寫入%d個(gè)寄存器,返回%d個(gè)寄存器rn",RegNum,?pReFrame->RegNum);
return?MRTU_WRITE_ERROR; //寫入數(shù)據(jù)錯(cuò)誤
}
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
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?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); //計(jì)算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ù)量錯(cuò)誤,讀取寄存器數(shù)量為:%drn",?SWAP16(pReadFrame->RegNum));
MODEBUS_SLAVE_RetrunUnu(pHandle,?pHandle->pRxBuff[0],?pHandle->pRxBuff[1],?MRTU_UNUS2); //返回異常2
return?MRTU_REGN_ERROR; //寄存器數(shù)量錯(cuò)誤
}
}break;
case?MRTU_FUN_WRITE :break; //0x06寫單個(gè)保持寄存器
case?MRTU_FUN_MWRITE : //0x10寫多個(gè)保持寄存器
{
pWriteMultFrame?=?(MRTU_WRITE_MULT_FRAME?*)pHandle->pRxBuff;
if((SWAP16(pWriteMultFrame->RegNum)?>?127)?||?(SWAP16(pWriteMultFrame->RegNum)?==?0))
{
modebus_debug("寫寄存器數(shù)量錯(cuò)誤,讀取寄存器數(shù)量為:%drn",?SWAP16(pWriteMultFrame->RegNum));
MODEBUS_SLAVE_RetrunUnu(pHandle,?pHandle->pRxBuff[0],?pHandle->pRxBuff[1],?MRTU_UNUS2); //返回異常2
return?MRTU_REGN_ERROR; //寄存器數(shù)量錯(cuò)誤
}
else?if(pWriteMultFrame->DataLen?!=?(2*SWAP16(pWriteMultFrame->RegNum)))
{
modebus_debug("寫寄存器數(shù)據(jù)長度錯(cuò)誤,需要寫入%d個(gè)寄存器,長度為:%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ù)量錯(cuò)誤
}
}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校驗(yàn)錯(cuò)誤,計(jì)算CRC為:0x%04X,返回CRC為:0x%04Xrn",crc16,(u16)(pHandle->pRxBuff[DataLen-2]<pRxBuff[DataLen-1]);
return?MRTU_CRC_ERROR; //返回CRC校驗(yàn)錯(cuò)誤
}
}
/*************************************************************************************************************************
*?函數(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
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU主機(jī)讀取從機(jī)的指定寄存器,可以為保持寄存器,也可以為輸入寄存器,可以一次讀取多個(gè)
輸入輸出的數(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; //返回?cái)?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; //功能碼錯(cuò)誤
if((RegNum?>?127)?||?(RegNum?==?0)) return?MRTU_REGN_ERROR; //寄存器數(shù)量錯(cuò)誤
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);//計(jì)算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ù)置單個(gè)保持寄存器
*?參數(shù) : pHandle:modebus句柄;Fun:讀取的功能碼;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegData:返回寄存器的值
*?返回 : MRTU_ERROR:通信狀態(tài)
*?依賴 : 底層通信驅(qū)動
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU主機(jī)寫單個(gè)寄存器成功后返回
輸入輸出的數(shù)據(jù)都為小端模式
注意:如果直接使用數(shù)據(jù)幀的寄存器數(shù)量以及地址,必須高地位交換
*************************************************************************************************************************/
MRTU_ERROR?MODEBUS_SLAVE_ReturnWriteHoldReg(MODEBUS_HANDLE?*pHandle,u8?SlaveAddr,?u16?RegAddr,?u16?RegData)
{
MRTU_WRITE_FRAME?*pFrame; //返回?cái)?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ù)置單個(gè)寄存器
pFrame->StartReg?=?SWAP16(RegAddr); //寄存器地址
pFrame->RegData?=?SWAP16(RegData); //寄存器的值
pFrame->crc16?=?usMBCRC16(pHandle->pTxBuff,?6);//計(jì)算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ù)置多個(gè)保持寄存器
*?參數(shù) : pHandle:modebus句柄;SlaveAddr:從機(jī)地址;RegAddr:需讀取的寄存器地址;RegNum:需要讀取的寄存器數(shù)量
*?返回 : MRTU_ERROR:通信狀態(tài)
*?依賴 : 底層通信驅(qū)動
*?作者 : cp1300@139.com
*?時(shí)間 : 2014-03-24
*?最后修改時(shí)間?:?2014-11-16
*?說明 :? MOUEBUS?RTU主機(jī)寫單個(gè)寄存器成功后返回
輸入輸出的數(shù)據(jù)都為小端模式
注意:如果直接使用數(shù)據(jù)幀的寄存器數(shù)量以及地址,必須高地位交換
*************************************************************************************************************************/
MRTU_ERROR?MODEBUS_SLAVE_ReturnWriteMultHoldReg(MODEBUS_HANDLE?*pHandle,?u8?SlaveAddr,?u16?RegAddr,?u8?RegNum)
{
MRTU_WRIT_EMULT_RFRAME?*pFrame; //返回?cái)?shù)據(jù)幀格式
if(pHandle?==?NULL)?return?MRTU_HANDLE_ERROR; //句柄無效
if((RegNum?>?127)?||?(RegNum?==?0)) return?MRTU_REGN_ERROR; //寄存器數(shù)量錯(cuò)誤
pFrame?=?(MRTU_WRIT_EMULT_RFRAME?*)pHandle->pTxBuff;
//數(shù)據(jù)結(jié)構(gòu)填充
pFrame->addr?=?SlaveAddr; //從機(jī)地址
pFrame->fun?=?MRTU_FUN_MWRITE; //功能碼,預(yù)置多個(gè)寄存器
pFrame->StartReg?=?SWAP16(RegAddr); //寄存器起始地址
pFrame->RegNum?=?SWAP16(RegNum); //寄存器數(shù)量
pFrame->crc16?=?usMBCRC16(pHandle->pTxBuff,?6); //計(jì)算CRC16 




