25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 

179 satır
7.4 KiB

  1. /***********************************************************************
  2. * Copyright (C) 2025-, XINJE Co., Ltd.
  3. *
  4. * File Name: modbus_master.h
  5. * Description: Modbus主站的ModbusRTUMaster头文件,主要负责四种请求帧的生成:(01)(03)(0F)(10)、响应帧的解析。
  6. * Others:
  7. * Version: v1.0
  8. * Author: weikai XINJE
  9. * Date: 2025-7-30
  10. ***********************************************************************/
  11. #ifndef MODBUS_RTU_MASTER_H
  12. #define MODBUS_RTU_MASTER_H
  13. #include <QObject>
  14. #include <QByteArray>
  15. #include <QVector>
  16. #include <QHash>
  17. const int TYPE_REGISTERS = 1;
  18. const int TYPE_COILS = 2;
  19. /**********************************************************************
  20. * Iterates over the contents of a ModbusRTUMaster.
  21. *ModbusRTUMaster:
  22. *提供Modbus RTU协议的主站功能,支持生成各种Modbus RTU请求帧,
  23. *以及解析从站返回的响应帧。所有协议相关参数均作为类成员变量,可通过setter方法进行设置。
  24. ***********************************************************************/
  25. class ModbusRTUMaster : public QObject
  26. {
  27. Q_OBJECT
  28. public:
  29. //构造函数
  30. explicit ModbusRTUMaster(QObject *parent = nullptr);
  31. //功能码枚举 - 定义Modbus协议支持的功能码
  32. enum FunctionCode
  33. {
  34. READ_COILS = 0x01, // 读线圈状态
  35. READ_HOLDING_REGISTERS = 0x03, // 读保持寄存器
  36. WRITE_MULTIPLE_COILS = 0x0F, // 写多个线圈
  37. WRITE_MULTIPLE_REGISTERS = 0x10 // 写多个保持寄存器
  38. };
  39. //错误码枚举 - 定义Modbus协议可能返回的错误码
  40. enum ErrorCode
  41. {
  42. NO_ERROR = 0x00, // 无错误
  43. ILLEGAL_FUNCTION = 0x01, // 非法功能 - 从站不支持该功能码
  44. ILLEGAL_DATA_ADDRESS = 0x02, // 非法数据地址 - 从站不支持该地址
  45. ILLEGAL_DATA_VALUE = 0x03, // 非法数据值 - 数据值超出范围
  46. SERVER_DEVICE_FAILURE = 0x04,// 从站设备故障
  47. ACKNOWLEDGE = 0x05, // 确认 - 请求已接收但未处理
  48. SERVER_DEVICE_BUSY = 0x06, // 从站设备忙 - 无法处理请求
  49. MEMORY_PARITY_ERROR = 0x08 // 内存奇偶性错误
  50. };
  51. //设置从站地址
  52. void setSlaveAddr(quint8 slaveAddr) { slaveAddr_ = slaveAddr; }
  53. //设置功能码
  54. void setFuncCode(FunctionCode funcCode) { funcCode_ = funcCode; }
  55. //设置起始地址
  56. void setStartAddr(quint16 startAddr) { startAddr_ = startAddr; }
  57. //设置读取数量
  58. void setReadCount(quint16 readCount) { readCount_ = readCount; }
  59. //设置线圈数据
  60. void setCoils(const QVector<bool>& coils) { coils_ = coils; }
  61. //设置寄存器数据
  62. void setRegisters(const QVector<quint16>& registers) { registers_ = registers; }
  63. //提取错误码对应描述
  64. QString getErrorDescription(int errorCode);
  65. //获取起始地址
  66. quint16 getStartAddr() const;
  67. //生成读线圈请求帧 (功能码01)
  68. QByteArray createReadCoilsFrame();
  69. //生成读保持寄存器请求帧 (功能码03)
  70. QByteArray createReadHoldingRegistersFrame();
  71. //生成写多个线圈请求帧 (功能码0F)
  72. QByteArray createWriteMultipleCoilsFrame();
  73. //生成写多个保持寄存器请求帧 (功能码10)
  74. QByteArray createWriteMultipleRegistersFrame();
  75. /***********************************************************************
  76. *@brief: 处理接收到的数据流并解析完整帧
  77. *@param: data 接收到的原始数据
  78. *@param: slaveAddr 输出参数,从响应中解析出的从站地址
  79. *@param: funcCode 输出参数,从响应中解析出的功能码
  80. *@param: parsedData 输出参数,解析后的数据
  81. *@param: errorCode 输出参数,错误码(NoError表示成功)
  82. *@param: extractedFrame 输出参数,提取到的完整帧
  83. *@return:是否成功解析
  84. *@note: 提取到帧后会进行解析
  85. ***********************************************************************/
  86. bool processReceivedData(const QByteArray& data, quint8& slaveAddr, quint8& funcCode,
  87. QVector<quint16>& parsedData, quint8& errorCode,QByteArray& extractedFrame,bool& isComFrame);
  88. public:
  89. /***********************************************************************
  90. *@brief: 创建读请求帧
  91. *@param: frame 输出参数 请求帧
  92. *@param: type 请求类型
  93. ***********************************************************************/
  94. void buildReadFrame(QByteArray& frame,FunctionCode funcCode);
  95. /***********************************************************************
  96. *@brief: 创建部分写请求帧
  97. *@param: frame 输出参数 请求帧
  98. *@param: type 请求类型
  99. ***********************************************************************/
  100. void buildWriteFrame(QByteArray& frame,FunctionCode funcCode);
  101. /***********************************************************************
  102. *@brief: 解析读线圈响应数据
  103. *@param: responseData 响应中的数据部分
  104. *@param: coils 输出参数(bool类型的数组),解析出的线圈状态
  105. *@return:是否成功解析
  106. ***********************************************************************/
  107. bool parseReadCoilsResponse(const QByteArray& responseData, QVector<bool>& coils);
  108. /***********************************************************************
  109. *@brief: 解析读保持寄存器响应数据
  110. *@param: responseData 响应中的数据部分
  111. *@param: registers 输出参数(quint16类型的数组),解析出的寄存器值
  112. *@return:是否成功解析
  113. ***********************************************************************/
  114. bool parseReadHoldingRegistersResponse(const QByteArray& responseData, QVector<quint16>& registers);
  115. /***********************************************************************
  116. *@brief: 解析单帧响应
  117. *@param: response 从站返回的响应数据
  118. *@param: slaveAddr 输出参数,从响应中解析出的从站地址
  119. *@param: funcCode 输出参数,从响应中解析出的功能码
  120. *@param: data 输出参数,解析后的数据
  121. *@param: errorCode 输出参数,错误码(NoError表示成功)
  122. *@return:是否成功解析
  123. ***********************************************************************/
  124. bool parseResponse(const QByteArray& response, quint8& slaveAddr, quint8& funcCode,
  125. QVector<quint16>& data, quint8& errorCode);
  126. /***********************************************************************
  127. *@brief: 从缓冲区提取完整帧
  128. *@param: frame 输出参数,提取的完整帧
  129. *@return:是否成功提取到一帧
  130. ***********************************************************************/
  131. bool extractFrame(QByteArray& frame,bool& isComFrame);
  132. //计算CRC16校验值
  133. quint16 calculateCRC(const QByteArray& data);
  134. //验证帧的CRC16校验
  135. bool verifyCRC(const QByteArray& frame);
  136. //Modbus RTU协议参数
  137. quint8 slaveAddr_; // 从站地址
  138. FunctionCode funcCode_; // 功能码
  139. quint16 startAddr_; // 起始地址
  140. quint16 readCount_; // 读取数量
  141. QVector<bool> coils_; // 线圈数据(写入)
  142. QVector<quint16> registers_; // 寄存器数据(写入)
  143. //其他
  144. QHash<int,QString> errMessage; //错误码描述映射表
  145. QByteArray buffer_; // 数据缓冲区
  146. };
  147. #endif // MODBUS_RTU_MASTER_H