您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

199 行
8.6 KiB

  1. #include "Modbus.h"
  2. UINT16 Transmission_Indicator = 0x00; //事务号
  3. /*********************************************************************************************
  4. * 功能    : 计算写入数据的字节数
  5. * 描述   : 通过对应的功能码和操作数量计算对应的数据字节数
  6. * 输入 : function_code 选择的功能码类型 operations_Number对应功能码类型的操作数量
  7. * 输出 : Write_date_number 写入数据的字节数
  8. *********************************************************************************************/
  9. unsigned int Count_Write_date_number(int function_code, unsigned int operations_number)
  10. {
  11. unsigned int write_date_number = 0;
  12. if (function_code == 0x01 || function_code == 0x03)
  13. return write_date_number;
  14. if (function_code == 0x0F) //读线圈
  15. {
  16. write_date_number = operations_number / 8;
  17. if (operations_number % 8)
  18. write_date_number++;
  19. }
  20. if (function_code == 0x10)
  21. write_date_number = operations_number * 2;
  22. return write_date_number;
  23. }
  24. /*********************************************************************************************
  25. * 功能    : 计算请求报文计算预期响应报文字节数
  26. * 描述   : 通过对应的功能码和操作数量计算对应的数据字节数
  27. * 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量
  28. * 输出 : Respone_len 预期响应的数据字节数
  29. *********************************************************************************************/
  30. unsigned int Count_Respone_Len(int function_code, unsigned int operations_number)
  31. {
  32. unsigned int respone_len = 0;
  33. if (function_code == 0x0F || function_code == 0x10)
  34. return respone_len;
  35. if (function_code == 0x01) //读线圈
  36. {
  37. respone_len = operations_number / 8;
  38. if (operations_number % 8)
  39. respone_len++;
  40. }
  41. if (function_code == 0x03)
  42. respone_len = operations_number * 2;
  43. return respone_len;
  44. }
  45. /*********************************************************************************************
  46. * 功能    : 检测响应报文长度
  47. * 描述   : 对响应报文中存放长度字节进行判断和请求报文对比
  48. * 输入 : Response_Message 响应报文 Request_Message 请求报文 Response_Message_len 接收到的数据长度
  49. * 输出 : true 长度正常 false 长度异常
  50. *********************************************************************************************/
  51. bool Check_Response_Message_len(UINT8 *Response_Message, UINT8 *Request_Message, int response_message_len)
  52. {
  53. if ((response_message_len - 6) != Response_Message[5])
  54. return false;
  55. unsigned int operations_Number = Request_Message[10] << 8 | Request_Message[11];
  56. unsigned int respone_Len = Count_Respone_Len(Request_Message[7], operations_Number);
  57. if (Request_Message[7] == 0x0F || Request_Message[7] == 0x10)
  58. if (response_message_len != 12)
  59. return false;
  60. if (Request_Message[7] == 0x01 || Request_Message[7] == 0x03)
  61. {
  62. if (respone_Len + 9 != response_message_len)
  63. return false;
  64. if (respone_Len != Response_Message[8])
  65. return false;
  66. }
  67. return true;
  68. }
  69. /*********************************************************************************************
  70. * 功能    : 判断响应报文是否可以正常解析
  71. * 描述   : 通过长度和异常码等判定该响应报文是否可以解析
  72. * 输入 : Response_Message 响应报文 Request_Message请求报文 Response_Message_len 响应报文长度
  73. * 输出 : 响应数据类型
  74. *********************************************************************************************/
  75. int Analysis_Response_Message(UINT8 *Response_Message, UINT8 *Request_Message, int response_message_len)
  76. {
  77. if (response_message_len < 9 || response_message_len > 260)
  78. return MSG_LEN_ERROR;
  79. for (int i = 0; i < 7; i++)
  80. {
  81. if (i == 4 || i == 5) //后续字节长度
  82. continue;
  83. if (Response_Message[i] != Request_Message[i]) //0 1 传输标识,2 3 协议标识,6设备ID
  84. return MABP_ERROR; //一旦不一致,判定为异常报文数据
  85. }
  86. if (Response_Message[4] != 0x00) //4 固定0x00
  87. return MABP_ERROR;
  88. if (Response_Message[7] == Request_Message[7] + 0x80)//先处理异常响应
  89. {
  90. if (response_message_len == 9)
  91. {
  92. return ABNORMAL_RESPONSE;
  93. }
  94. else
  95. return MSG_LEN_ERROR;
  96. }
  97. if (Response_Message[7] != Request_Message[7]) //功能码判断
  98. return FUNCTION_CODE_ERROR;
  99. if (Request_Message[7] == 0x0F || Request_Message[7] == 0x10) //0F 10 地址和操作数量判定
  100. {
  101. for (int j = 8; j < 10; j++)
  102. {
  103. if (Request_Message[j] != Response_Message[j])
  104. return START_ADDRESS_ERROR;
  105. }
  106. for (int j = 10; j < 12; j++)
  107. {
  108. if (Request_Message[j] != Response_Message[j])
  109. return OPERATION_NUMBER_ERROR;
  110. }
  111. }
  112. if (!Check_Response_Message_len(Response_Message, Request_Message, response_message_len))
  113. return MSG_LEN_ERROR;
  114. return NORMAL_RESPONSE;
  115. }
  116. /*********************************************************************************************
  117. * 功能    : 生成MBAP报头
  118. * 描述 : MBAP报文头的包括的内容:
  119. * +-------------+---------+--------+--------+------------------------------+
  120. * | 域 | 长度 | 客户机 | 服务器 | 描述 |
  121. * +-------------+---------+--------+--------+------------------------------+
  122. * |事务元标识符 | 2个字节 | 启动 | 复制 |请求/响应事务处理的识别码 |
  123. * +-------------+---------+--------+--------+------------------------------+
  124. * |协议标识符 | 2个字节 | 启动 | 复制 |0=MODBUS 协议 |
  125. * +-------------+---------+--------+--------+------------------------------+
  126. * | 长度 | 2个字节 | 启动 | 启动 |以下字节的数量 |
  127. * +-------------+---------+--------+--------+------------------------------+
  128. * |单元标识符 | 1个字节 | 启动 | 复制 |连接的远程从站的识别码 |
  129. * 输入 : 无
  130. * 输出 : MBAP报文头内容
  131. *********************************************************************************************/
  132. void Create_MBAP(UINT8 *Message, int function_code, unsigned int operations_number)
  133. {
  134. Message[0] = Transmission_Indicator >> 8;//事务号
  135. Message[1] = (UINT8)Transmission_Indicator;
  136. Transmission_Indicator++;
  137. Message[2] = 0x00; //Modbus协议标识
  138. Message[3] = 0x00;
  139. Message[4] = 0x00;//后续字节长度
  140. Message[5] = Count_Write_date_number(function_code, operations_number) + 0x06;
  141. if (function_code == 0x0F || function_code == 0x10)//0f/10功能码后续字节数多1
  142. {
  143. Message[5] = Message[5] + 1;
  144. }
  145. Message[6] = DEVICE_ID;
  146. }
  147. /*********************************************************************************************
  148. * 功能    : 字符串转UINT8类型
  149. * 描述   : 根据写入数量和功能码类型输入相应的数据
  150. * 输入 : *Message 消息帧存放的数组 Write_date 要转换的字符串
  151. * Message_len消息帧数组的起始位置
  152. * 输出 : Message_len 消息帧的长度
  153. *********************************************************************************************/
  154. int HexStringtoByte(UINT8 *Message, string write_date, int message_len, int function_code, unsigned int operations_Number)
  155. {
  156. if (write_date.length() == 0)
  157. return message_len;
  158. Message[message_len] = Count_Write_date_number(function_code, operations_Number);
  159. message_len++;
  160. const char *b = write_date.c_str();
  161. int temp = 0;
  162. for (unsigned int i = 0; i + 3 < write_date.length(); i = i + 3)
  163. {
  164. sscanf_s(b + i, "%02X", &temp);
  165. Message[message_len] = (UINT8)temp;
  166. message_len++;
  167. }
  168. sscanf_s(b + write_date.length() - 2, "%02X", &temp);
  169. Message[message_len] = (UINT8)temp;
  170. return ++message_len;
  171. }
  172. /*********************************************************************************************
  173. * 功能    : 生成TCP模式下的消息帧
  174. * 描述   : 根据要写入的数据生成消息帧
  175. * 输入 : *Message 消息帧存放的数组 Write_date 写入数据的字符串
  176. * Function_code 功能码 Operations_Number 操作数量 Starting_address起始地址
  177. * 输出 : 消息帧的总长度
  178. *********************************************************************************************/
  179. int Create_TCP_Message(UINT8 *Message, int function_code, unsigned int operations_Number, unsigned int starting_address, string write_date)
  180. {
  181. Create_MBAP(Message, function_code, operations_Number);
  182. Message[7] = function_code;//功能码
  183. Message[8] = starting_address >> 8;//起始地址H
  184. Message[9] = starting_address;//起始地址L
  185. Message[10] = operations_Number >> 8;//操作数量H
  186. Message[11] = operations_Number;//操作数量L
  187. return HexStringtoByte(Message, write_date, 12, function_code, operations_Number);
  188. }