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