Modbus adu 关键代码(支持 RTU及ASCII方式 )

```

/**

封装ADU数据

@param const MbFrameType    frameType  帧类型

@param const unsigned char  devAddr  设备地址

@param const unsigned char  funCode  功能码

@param const unsigned char* pData    数据

@param const nsigned  char  dataLen  数据长度

@param unsigned char*      pOutAduData 封装ADU数据

@return pOutAduData据的长度

**/

unsigned char packMbAduData(const MbFrameType frameType, const unsigned char devAddr, const unsigned char* pData,const unsigned char dataLen, unsigned char* pOutAduData)

{

if (frameType == FrameRtu){

return packMbRtuAduData(devAddr, pData, dataLen, pOutAduData);

}else if (frameType == FrameAscii) {

return packMbAsciiAduData(devAddr, pData, dataLen, pOutAduData);

}else

return 0;

}

/**

封装基于RTU的PDU数据

@param const unsigned char  devAddr  设备地址

@param const unsigned char  funCode  功能码

@param const unsigned char* pData    数据

@param const nsigned  char  dataLen  数据长度

@param unsigned char*      pOutRtuData 封装的RTU PDU数据

@return pOutRtuData据的长度

**/

unsigned char packMbRtuAduData(const unsigned char devAddr, const unsigned char* pData,const unsigned char dataLen, unsigned char* pOutRtuData)

{

unsigned short crc    = 0;

unsigned char  req_pdu_len = packMbRtuPduData(devAddr, pData, dataLen, pOutRtuData);

if (req_pdu_len > 0){

crc = calcMbRtuPduCrc(pOutRtuData, req_pdu_len);

pOutRtuData[req_pdu_len++] = (crc & 0x00FF);

pOutRtuData[req_pdu_len++] = (crc & 0xFF00) >> 8;

}

return req_pdu_len;

}

/**

封装基于ASCII的PDU数据

@param const unsigned char  devAddr  设备地址

@param const unsigned char* pData    数据

@param const nsigned  char  dataLen  数据长度

@param unsigned char*      pOutAsciiCmd 封装报的ASCII PDU数据

@return pOutAsciiCmd据的长度

**/

unsigned char packMbAsciiAduData(const unsigned char devAddr, const unsigned char* pData, const unsigned char dataLen, unsigned char* pOutAsciiCmd)

{

unsigned short i = 0, j = 0, lrc = 0;

unsigned char fl;

char sz[3];

unsigned char req_pdu_len = 0;

unsigned char req_pdu_bin[PDU_MAX_LEN];

req_pdu_len = packMbRtuPduData(devAddr, pData, dataLen, req_pdu_bin);

if (req_pdu_len > 0){

pOutAsciiCmd[j++] = ':';

for (i = 0; i < req_pdu_len; i++){

fl = req_pdu_bin[i];

sprintf(sz, "%02X", fl);

pOutAsciiCmd[j++] = sz[0];

pOutAsciiCmd[j++] = sz[1];

}

lrc = calcMbAsciiPduLrc(req_pdu_bin, req_pdu_len);

sprintf(sz, "%02X", lrc);

pOutAsciiCmd[j++] = sz[0];

pOutAsciiCmd[j++] = sz[1];

pOutAsciiCmd[j++] = '\r';

pOutAsciiCmd[j++] = '\n';

}

return j;

}

/**

基于ASCII的PDU数据转为RTU Pdu数据

@param const unsigned char*  pAsciiPdu ASCII的PDU数据

@param const unsigned char  asciiPduLen ASCII的PDU数据的长度

@param unsigned char*      pRtuPduData  转换后的RTU Pdu数据

@return RTU Pdu数据长度

**/

unsigned char MbAsciiPdu2RtuPdu(const unsigned char* pAsciiPdu, unsigned char asciiPduLen, unsigned char* pRtuPduData)

{

unsigned char j = 0;

unsigned char i = 0;

char  sz[2];

int dv;

unsigned fc = 0;

// 取出地址和功能码

if (asciiPduLen >= 4){

sscanf((char*)pAsciiPdu + 0, "%2s", sz);

sscanf(sz, "%x", &dv);

pRtuPduData[j++] = dv;

sscanf((char*)pAsciiPdu + 2, "%2s", sz);

sscanf(sz, "%x", &dv);

fc = dv;

pRtuPduData[j++] = dv;

}

// asciiPduLen - 5: 去掉‘:’和LRC及\r\n的长度;i += 2:ASCII协议中每两字节对应RTU中的一个字节

for (i = 4; i < asciiPduLen - 5; i += 2){

sscanf((char*)pAsciiPdu + i, "%2s", sz);

sscanf(sz, "%x", &dv);

if (fc == ReadHoldingRegister){

dv /= 2;

}

pRtuPduData[j++] = dv;

}

return j;

}

/**

以下三个方法用来校验响应数据

@param const MbFrameType frameType  帧类型

@param const unsigned char* pRspData  ASCII的PDU数据

@param const unsigned char  rspDataLen ASCII的PDU数据的长度

@return 成功返回0,否则返回>1

**/

unsigned char checkMbResponseData(const MbFrameType frameType, const unsigned char* pRspData, const unsigned char rspDataLen)

{

if (frameType == FrameAscii){

return checkMbResponseAsciiData(pRspData, rspDataLen);

}else if (frameType == FrameRtu){

return checkMbResponseRtuData(pRspData, rspDataLen);

}else{

return UnknowFrameType;

}

}

unsigned char checkMbResponseAsciiData(const unsigned char* pRspData, const unsigned char rspDataLen)

{

char sz[2];

char i, fc, len;

int dv;

unsigned char lrc = 0, rsp_lcr = 0;

if (!pRspData || rspDataLen < 3) return ParamError;

sscanf((char*)pRspData + 3, "%2s", sz);

sscanf(sz, "%x", &dv);

fc  = dv;

sscanf((char*)pRspData + 5, "%2s", sz);

sscanf(sz, "%x", &dv);

len  = dv;

// 响应数据中的LRC

if (fc >= ReadCoilStatus && fc <= ReadInputRegister){  // 功能码0x01 ---- 0x04

sscanf((char*)pRspData + 7 + len, "%2s", sz);

sscanf(sz, "%x", &dv);

rsp_lcr = dv;

}else if (fc >= WriteSingleCoil && fc <= WriteSingleRegister){  // 功能码0x05---0x06

sscanf((char*)pRspData + 14, "%2s", sz);

sscanf(sz, "%x", &dv);

rsp_lcr = dv;

}else if (fc >= MaskWriteRegister){ // 功能码0x16

sscanf((char*)pRspData + 18, "%2s", sz);

sscanf(sz, "%x", &dv);

rsp_lcr = dv;

}else{

return InvalidFunctionCode;

}

// 重新计算LRC

for (i = 1; i < rspDataLen - 5; i += 2){

sscanf((char*)pRspData + i, "%2s", sz);

sscanf(sz, "%x", &dv);

lrc += dv;

}

lrc = (~lrc) + 1;

//printf("---fc:%d,len:%dlrc:%02X %0X----", fc, len, lrc, rsp_lcr);

if (lrc == rsp_lcr) return MB_OK;

return MemoryParityError;

}

unsigned char checkMbResponseRtuData(const unsigned char* pRspData, const unsigned char rspDataLen)

{

char fc, len;

unsigned short int crc, rsp_rcr;

if (!pRspData || rspDataLen < 3) return ParamError;

fc  = pRspData[1];

len  = pRspData[2];

// 响应数据中的CRC

if (fc >= ReadCoilStatus && fc <= ReadInputRegister){  // 功能码0x01 ---- 0x04

rsp_rcr = (pRspData[3 + len] << 8) + pRspData[4 + len];

}else if (fc >= WriteSingleCoil && fc <= WriteSingleRegister){  // 功能码0x05---0x06

rsp_rcr = (pRspData[6] << 8) + pRspData[7];

}else if (fc >= MaskWriteRegister){ // 功能码0x16

rsp_rcr = (pRspData[8] << 8) + pRspData[9];

}else{

return InvalidFunctionCode;

}

// 重新计算的CRC

crc = calcMbRtuPduCrc(pRspData, rspDataLen - 2);

crc = u16ToBigEndian(crc);

if (rsp_rcr == crc) return MB_OK;

return MemoryParityError;

}

/**

  指低地址存放最高有效字节

**/

unsigned short u16ToBigEndian(unsigned short v)

{

return ((v & 0xFF00) >> 8) + ((v & 0x00FF) << 8);

}

/**

  指高地址存放最低有效字节

**/

unsigned short u16ToLittleEndian(unsigned short v)

{

return ((v & 0xFF00) >> 8) + ((v & 0x00FF) << 8);

}

/**

以5个方法RS485通信数据转STM32数据

**/

short int toHostInt16(unsigned char *pv)

{

unsigned short int v = (pv[1] << 8) + pv[0];

return (short int)*((short int*)&v);

}

int  toHostInt32(unsigned char *pv)

{

unsigned int v = ((pv[2] << 24) + (pv[3] << 16) + (pv[0] << 8) + pv[1]);

return (int)*((int*)&v);

}

__int64  toHostInt64(unsigned char *pv)

{

unsigned __int64 v = (((__int64)pv[4] << 56) + ((__int64)pv[5] << 48) + ((__int64)pv[6] << 40) + ((__int64)pv[7] << 32)  +  //hight bits

      (pv[0] << 24)        + (pv[1] << 16)          + (pv[2] << 8)          + pv[3]); //low bits

return (__int64)*((__int64*)&v);

}

float toHostFloat32(unsigned char *pv)

{

unsigned int v = ((pv[2] << 24) + (pv[3] << 16) + (pv[0] << 8) + pv[1]);

return (float)*((float*)&v);

}

double toHostFloat64(unsigned char *pv)

{

unsigned __int64 v = (((__int64)pv[4] << 56) + ((__int64)pv[5] << 48) + ((__int64)pv[6] << 40) + ((__int64)pv[7] << 32)  +  //hight bits

      (pv[0] << 24)        + (pv[1] << 16)          + (pv[2] << 8)          + pv[3]); //low bits

return (double)*((double*)&v);

}

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容