28335有MODBUS RTU例程吗
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
#include <stdlib.h>
#include <string.h>
#include "GlobalHeadFile.h"
#ifndef Modbus_C
#define Modbus_C
Modbus_Callback pWriteCoil_Callback = NULL; //写Coil回调函数
Modbus_Callback pWriteHolding_Callback = NULL; //写Holding回调函数
/**
* @brief 绑定写Coil的回调函数
*
* @param pCallback : 回调函数地址
*/
void Set_WriteCoil_Callback(Modbus_Callback pCallback)
{
if(pCallback != NULL)
{
pWriteCoil_Callback = pCallback;
}
}
/**
* @brief 绑定写Holding的回调函数
*
* @param pCallback : 回调函数地址
*/
void Set_WriteHolding_Callback(Modbus_Callback pCallback)
{
if(pCallback != NULL)
{
pWriteHolding_Callback = pCallback;
}
}
/**
* @brief 整理Modbus错误应答帧
*
* @param id 站号
* @param funcCode 功能码
* @param errCode 错误码
* @param txData 发送缓冲
* @param txDataLen 发送数据长度
*/
void PackErrorResponse(Uint16 id,Uint16 funcCode,Uint16 errCode, Uint16* txData, Uint16* txDataLen)
{
*(txData) = id;
*(txData + 1) = 0x80 | funcCode;
*(txData + 2) = errCode;
CRC16_Append(txData,3);
*txDataLen = 5;
}
/**
* @brief 读取Coil
*
* @param id 站号
* @param startAddr 寄存器起始地址
* @param number 寄存器个数
* @param txData 发送缓冲区
* @param txDataLen 发送数据长度
*/
void PackResponse_ReadCoil(Uint16 id,Uint16 startAddr,Uint16 number, Uint16* txData, Uint16* txDataLen)
{
Uint16 idx;
Uint16 coilValue;
Uint16 byteNumber;
*(txData) = id;
*(txData + 1) = MFC_ReadCoil;
byteNumber = (number - 1) / 8 + 1; //字节数
*(txData + 2) = byteNumber;
for(idx = 0; idx < byteNumber; idx++)
{
coilValue = SysCoil_Get_Byte(startAddr + idx * 8);
*(txData + 3 + idx) = coilValue;
}
CRC16_Append(txData,byteNumber + 3);
*txDataLen = byteNumber + 5;
}
/**
* @brief 写单个Coil
* 应答帧与请求帧一模一样
* @param id : 站号
* @param rxData : 接收的数据帧
* @param rxDataLen : 接收的数据长度
* @param txData : 发送的数据缓冲
* @param txDataLen : 发送的数据长度
*/
void PackResponse_WriteSingleCoil(Uint16 id,Uint16* rxData, Uint16 rxDataLen, Uint16* txData, Uint16* txDataLen)
{
//写单个寄存器时,regNumber既是写入的值: 0xFF00/0x0000
Uint16 coilValue = ((Uint16)*(rxData + 4) << 8 ) | *(rxData + 5);
Uint16 coilValue_Bool = (coilValue == 0xFF00) ? 1 : 0;
//写入的值必须是0xFF00或0x0000,否则是非法值
if((coilValue != 0xFF00) && (coilValue != 0))
{
PackErrorResponse(id,MFC_WriteSingleCoil,MEC_InvalidValue,txData,txDataLen);
return;
}
//没有处理函数,则返回不支持功能错误
if(pWriteCoil_Callback == NULL)
{
PackErrorResponse(id,MFC_WriteSingleCoil,MEC_InvalidFunction,txData,txDataLen);
return;
}
Uint16 coilAddr = ((Uint16)*(rxData + 2) << 8 ) | *(rxData + 3);
(*pWriteCoil_Callback)(coilAddr,1,&coilValue_Bool);
Uint16 i = 0;
while (i < rxDataLen)
{
*(txData + i) = *(rxData + i);
i++;
}
*txDataLen = rxDataLen;
}
/**
* @brief 写多个Coil
* @param id : 站号
* @param rxData : 接收的数据帧
* @param rxDataLen : 接收的数据长度
* @param txData : 发送的数据缓冲
* @param txDataLen : 发送的数据长度
*/
void PackResponse_WriteMultiCoil(Uint16 id,Uint16* rxData, Uint16 rxDataLen, Uint16* txData, Uint16* txDataLen)
{
//注意,写入的值CoilValue,是按字节排布的,每个bit代表一个Coil的值
Uint16 coilAddr = ((Uint16)*(rxData + 2) << 8 ) | *(rxData + 3);
Uint16 coilNumber = ((Uint16)*(rxData + 4) << 8 ) | *(rxData + 5);
Uint16 byteNumber = (Uint16)*(rxData + 6);
//判断帧数据长度是否正确,返回错误值错误
if(((coilNumber-1)/8 + 1 != byteNumber) || (rxDataLen != byteNumber + 9))
{
PackErrorResponse(id,MFC_WriteMultipleCoils,MEC_InvalidValue,txData,txDataLen);
return;
}
//没有处理函数,则返回不支持功能错误
if(pWriteCoil_Callback == NULL)
{
PackErrorResponse(id,MFC_WriteSingleCoil,MEC_InvalidFunction,txData,txDataLen);
return;
}
//调用命令执行函数
(*pWriteCoil_Callback)(coilAddr,coilNumber,(rxData+7));
Uint16 i = 0;
while (i < 6)
{
*(txData + i) = *(rxData + i);
i++;
}
CRC16_Append(txData,6);
*txDataLen = 8;
}
/**
* @brief 处理读取Holding应答消息
*
* @param id 站号
* @param startAddr 寄存器起始地址
* @param number 寄存器个数
* @param txData 发送缓冲区
* @param txDataLen 发送数据长度
*/
void PackResponse_ReadHolding(Uint16 id,Uint16 startAddr,Uint16 number, Uint16* txData, Uint16* txDataLen)
{
Uint16 idx;
Uint16 holdValue;
*(txData) = id;
*(txData + 1) = MFC_ReadHolding;
*(txData + 2) = number * 2;
for(idx = 0; idx < number; idx ++)
{
holdValue = SysHolding_Get(startAddr+idx);
*(txData + idx * 2 + 3) = holdValue >> 8;
*(txData + idx * 2 + 4) = holdValue & 0xFF;
}
CRC16_Append(txData,number*2 + 3);
*txDataLen = number*2 + 5;
}
/**
* @brief 写单个Holding
* @param id : 站号
* @param rxData : 接收的数据帧
* @param rxDataLen : 接收的数据长度
* @param txData : 发送的数据缓冲
* @param txDataLen : 发送的数据长度
*/
void PackResponse_WriteSingleHolding(Uint16 id,Uint16* rxData, Uint16 rxDataLen, Uint16* txData, Uint16* txDataLen)
{
Uint16 regAddr = ((Uint16)*(rxData + 2) << 8 ) | *(rxData + 3);
// Uint16 regValue = ((Uint16)*(rxData + 4) << 8 ) | *(rxData + 5);
//没有处理函数,则返回不支持功能错误
if(pWriteHolding_Callback == NULL)
{
PackErrorResponse(id,MFC_WriteSingleHolding,MEC_InvalidFunction,txData,txDataLen);
return;
}
//(*pWriteHolding_Callback)(regAddr,1,®Value);
(*pWriteHolding_Callback)(regAddr,1,(rxData + 4));
Uint16 i = 0;
while (i < rxDataLen)
{
*(txData + i) = *(rxData + i);
i++;
}
*txDataLen = rxDataLen;
}
/**
* @brief 写多个Holding
* @param id : 站号
* @param rxData : 接收的数据帧
* @param rxDataLen : 接收的数据长度
* @param txData : 发送的数据缓冲
* @param txDataLen : 发送的数据长度
*/
void PackResponse_WriteMultiHolding(Uint16 id,Uint16* rxData, Uint16 rxDataLen, Uint16* txData, Uint16* txDataLen)
{
Uint16 regAddr = ((Uint16)*(rxData + 2) << 8 ) | *(rxData + 3);
Uint16 regNumber = ((Uint16)*(rxData + 4) << 8 ) | *(rxData + 5);
Uint16 byteNumber = (Uint16)*(rxData + 6);
//没有处理函数,则返回不支持功能错误
if(pWriteHolding_Callback == NULL)
{
PackErrorResponse(id,MFC_WriteMultipleHoldings,MEC_InvalidFunction,txData,txDataLen);
return;
}
//判断帧数据长度是否正确,返回错误值错误
if((regNumber * 2 != byteNumber) || (rxDataLen != byteNumber + 9))
{
PackErrorResponse(id,MFC_WriteMultipleHoldings,MEC_InvalidValue,txData,txDataLen);
return;
}
(*pWriteHolding_Callback)(regAddr,regNumber,(rxData + 7));
Uint16 i = 0;
while (i < 6)
{
*(txData + i) = *(rxData + i);
i++;
}
CRC16_Append(txData,6);
*txDataLen = 8;
}
/**
* @brief 解析收到的帧
*
* @param rxData 接收到的数据
* @param rxDataLen 接收到的数据长度
* @param slaveId 站号
* @param txData 发送数据缓冲
* @param txDataLen 发送数据长度
*/
void Modbus_ProcessFrame(Uint16* rxData, Uint16 rxDataLen, Uint16 slaveId, Uint16* txData, Uint16* txDataLen)
{
Uint16 crcGet; /** 收到的数据中CRC码 */
Uint16 crcCalc; /** 计算出来 CRC码 */
Uint16 startAddr; /** 起始地址*/
Uint16 regNumber; /** 寄存器个数*/
/** 接收数据长度或Id不匹配,这里匹配广播地址*/
if((rxData == NULL) || (rxDataLen < 7) || ((*(rxData) != slaveId) && (*(rxData) != ID_BROADCAST)) )
{
*txDataLen = 0;
return;
}
/** CRC校验 */
crcGet = (Uint16)(*(rxData + rxDataLen - 2) << 8) | *(rxData + rxDataLen - 1);
crcCalc = CRC16_Calc(rxData,rxDataLen-2);
/** CRC校验失败,非广播消息时应答*/
if(crcGet != crcCalc)
{
if(*(rxData) != ID_BROADCAST)
{
PackErrorResponse(slaveId,*(rxData + 1),MEC_CRCError, txData, txDataLen);
}
else
{
*txDataLen = 0;
}
return;
}
startAddr = ((Uint16)*(rxData + 2) << 8 ) | *(rxData + 3);
regNumber = ((Uint16)*(rxData + 4) << 8 ) | *(rxData + 5);
/** 根据功能码进行相应处理 */
switch (*(rxData + 1))
{
case MFC_ReadCoil: //读取Coil
PackResponse_ReadCoil(slaveId,startAddr,regNumber,txData,txDataLen);
break ;
case MFC_ReadHolding: //读取Holding
PackResponse_ReadHolding(slaveId,startAddr,regNumber,txData,txDataLen);
break;
case MFC_WriteSingleCoil: //写单个Coil寄存器,FuncCode(1Byte) + Addr(2Bytes) + Value(2Bytes)
PackResponse_WriteSingleCoil(slaveId,rxData,rxDataLen,txData,txDataLen);
break;
case MFC_WriteMultipleCoils: //写多个Coil,FuncCode(1Byte) + Addr(2Bytes) + CoilNum(2Bytes) + ByteNum(1Byte)+CoilValue((CoilNum-1)/8+1)
PackResponse_WriteMultiCoil(slaveId,rxData,rxDataLen,txData,txDataLen);
break;
case MFC_WriteSingleHolding: //写单个Holding
PackResponse_WriteSingleHolding(slaveId,rxData,rxDataLen,txData,txDataLen);
break;
case MFC_WriteMultipleHoldings: //写多个Holding
PackResponse_WriteMultiHolding(slaveId,rxData,rxDataLen,txData,txDataLen);
break;
case MFC_Upgrade: //更新程序
//调用UPProtocol处理函数,去掉帧头(id)和帧尾(CRC)
UPProtocol_ProcessFrame(&rxData[1],rxDataLen - 3,&txData[1],txDataLen);
if(txData > 0)
{
txData[0] = slaveId;
CRC16_Append(txData,*txDataLen + 1);
*txDataLen += 3;
}
break;
default:
PackErrorResponse(slaveId, *(rxData + 1),MEC_InvalidAddress, txData, txDataLen);
break ;
}
/** 广播消息,不应答,将发送长度设置为0 */
if(*(rxData) == ID_BROADCAST)
{
*txDataLen = 0;
}
}
#endif //#ifndef Modbus_C
您好,
很遗憾,关于MODBUS没有官方发布资源,请看下面帖子内的资源是否有帮助。