Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

446 wiersze
16 KiB

  1. #include "RTU_Salve.h"
  2. #include <bitset>
  3. char read_buf[MAX_NUMBER];
  4. bitset<MAX_Address> Coil_date; //0-9999
  5. UINT16 Register[MAX_Address]; // 0-9999
  6. unsigned int Response_Message_Len;
  7. unsigned int RTU_Enable = 1;
  8. /*********************************************************************************************
  9. * 功能     :  初始化线圈和寄存器
  10. * 描述    : 对线圈和寄存器数组赋值为全1
  11. * 输入 : 无
  12. * 返回值 : 无
  13. **********************************************************************************************/
  14. void Init_Coil_Register(void)
  15. {
  16. for (int i = 0; i < MAX_Address; i++)
  17. {
  18. Coil_date[i] = 1;
  19. Register[i] = 0xFFFF;
  20. }
  21. }
  22. /*********************************************************************************************
  23. * 功能     :  Bitset转UINT8类型
  24. * 描述    : Bitset ==》UINT8
  25. * 输入 : Bitset_Address Bitset的起始地址 Read_Number 要读取的位数
  26. * 返回值 : Date 转换后的UNIT8数据
  27. **********************************************************************************************/
  28. UINT8 Bitset_to_Uint8(unsigned int Bitset_Address, unsigned int Read_Number)
  29. {
  30. UINT8 Date = 0x00;
  31. if (Read_Number >= 8)
  32. {
  33. unsigned int len = Bitset_Address + 7;
  34. for (unsigned int i = 0; i < 8; i++)
  35. {
  36. Date = Date << 1;
  37. Date = Date | (int)Coil_date[len--];
  38. }
  39. }
  40. else
  41. {
  42. unsigned int len = Bitset_Address + Read_Number-1;
  43. for (unsigned int i = 0; i < Read_Number; i++)
  44. {
  45. Date = Date << 1;
  46. Date = Date | (int)Coil_date[len--];
  47. }
  48. }
  49. return Date;
  50. }
  51. /*********************************************************************************************
  52. * 功能     :  生成异常码响应报文
  53. * 描述    : 对不支持的功能码生成对应的异常响应报文
  54. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  55. * 返回值 : 无
  56. **********************************************************************************************/
  57. void Create_Abnormal_Code_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message, UINT8 Abnormal_Code)
  58. {
  59. Response_Message[0] = Device_ID;
  60. Response_Message[1] = Requst_Message[1] + 0x80;
  61. Response_Message[2] = Abnormal_Code;
  62. Response_Message_Len = 3;
  63. UINT16 CRC_date = CRC_16(Response_Message, 3);
  64. Response_Message[3] = CRC_date >> 8;//CRC_H
  65. Response_Message[4] = (UINT8)CRC_date; //CRC_L
  66. Response_Message_Len = 5;
  67. }
  68. /*********************************************************************************************
  69. * 功能     :  生成0x01功能码响应报文
  70. * 描述    : 通过判断地址范围生成0x01对应的响应报文
  71. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  72. * 返回值 : 无
  73. **********************************************************************************************/
  74. void Create_0x01_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  75. {
  76. unsigned int Start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  77. unsigned int Address_range = Start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  78. if (Address_range < MAX_Address)//判断地址是否超限
  79. {
  80. unsigned int Read_Number = Requst_Message[4] << 8 | Requst_Message[5];//要读取的位数
  81. unsigned int Read_Len = Count_Read_date_number(Requst_Message[1], Read_Number); //要读取的字节数
  82. for (unsigned int i = 3; i < Read_Len + 3; i++)
  83. {
  84. Response_Message[i] = Bitset_to_Uint8(Start_Address, Read_Number);
  85. Start_Address += 8;
  86. Read_Number -= 8;
  87. }
  88. Response_Message[0] = Device_ID;
  89. Response_Message[1] = Requst_Message[1];
  90. Response_Message[2] = Read_Len; //响应报文中的后续字节数
  91. UINT16 CRC_date = CRC_16(Response_Message, Read_Len+3);
  92. Response_Message_Len = Read_Len + 2 + 3;
  93. Response_Message[Response_Message_Len - 2] = CRC_date>>8;//CRC_H
  94. Response_Message[Response_Message_Len - 1] = (UINT8)CRC_date; //CRC_L
  95. }
  96. else
  97. {
  98. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message,0x02);
  99. }
  100. }
  101. /*********************************************************************************************
  102. * 功能     :  生成0x03功能码响应报文
  103. * 描述    : 通过判断地址范围生成0x03对应的响应报文
  104. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  105. * 返回值 : 无
  106. **********************************************************************************************/
  107. void Create_0x03_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  108. {
  109. unsigned int Start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  110. unsigned int Address_range = Start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  111. if (Address_range < MAX_Address) //判断地址是否超限
  112. {
  113. unsigned int Read_Number = Requst_Message[4] << 8 | Requst_Message[5];//要读取的寄存器数量
  114. unsigned int Read_Len = Count_Read_date_number(Requst_Message[1
  115. ], Read_Number); //要读取的字节数
  116. for (unsigned int i = 3; i < Read_Len + 3; i= i + 2)
  117. {
  118. Response_Message[i] = Register[Start_Address] >> 8;
  119. Response_Message[i + 1] = (UINT8)Register[Start_Address];
  120. Start_Address += 1;
  121. }
  122. Response_Message[0] = Device_ID;
  123. Response_Message[1] = Requst_Message[1];
  124. Response_Message[2] = Read_Len; //响应报文中的后续字节数
  125. UINT16 CRC_date = CRC_16(Response_Message, Read_Len + 3);
  126. Response_Message_Len = Read_Len + 2 + 3;
  127. Response_Message[Response_Message_Len - 2] = CRC_date >> 8;//CRC_H
  128. Response_Message[Response_Message_Len - 1] = (UINT8)CRC_date; //CRC_L
  129. }
  130. else //地址超限
  131. {
  132. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  133. }
  134. }
  135. /*********************************************************************************************
  136. * 功能     :  写入线圈
  137. * 描述    : 将数据写入线圈中
  138. * 输入 : Write_date_Message 要写入的数据 Write_Number要写入的位数 Start_Address起始地址
  139. * 返回值 : 无
  140. **********************************************************************************************/
  141. void Write_Coil_date(UINT8 Write_date_Message, unsigned int Write_Number, unsigned int Start_Address)
  142. {
  143. if (Write_Number >= 8)
  144. {
  145. for (unsigned int i = Start_Address; i < Start_Address+8; i++)
  146. {
  147. Coil_date[i] = Write_date_Message & 1;
  148. Write_date_Message = Write_date_Message >> 1;
  149. }
  150. }
  151. else
  152. {
  153. for (unsigned int i = Start_Address; i < Start_Address + Write_Number; i++)
  154. {
  155. Coil_date[i] = Write_date_Message & 1;
  156. Write_date_Message = Write_date_Message >> 1;
  157. }
  158. }
  159. }
  160. /*********************************************************************************************
  161. * 功能     :  生成0x0F功能码响应报文
  162. * 描述    : 通过判断地址范围生成0x0F对应的响应报文
  163. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  164. * 返回值 : 无
  165. **********************************************************************************************/
  166. void Create_0x0F_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  167. {
  168. unsigned int Start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  169. unsigned int Address_range = Start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  170. if (Address_range < MAX_Address)//判断地址是否超限
  171. {
  172. unsigned int Write_Number = Requst_Message[4] << 8 | Requst_Message[5];//要写入的位数
  173. for (int i = 7; i < Requst_Message[6]+7; i++)//执行写入线圈操作
  174. {
  175. Write_Coil_date(Requst_Message[i], Write_Number, Start_Address);
  176. Write_Number -= 8;
  177. Start_Address += 8;
  178. }
  179. Response_Message[0] = Device_ID;
  180. Response_Message[1] = Requst_Message[1];
  181. Response_Message[2] = Requst_Message[2];
  182. Response_Message[3] = Requst_Message[3];
  183. Response_Message[4] = Requst_Message[4];
  184. Response_Message[5] = Requst_Message[5];
  185. UINT16 CRC_date = CRC_16(Response_Message, 6);
  186. Response_Message[6] = CRC_date >> 8;//CRC_H
  187. Response_Message[7] = (UINT8)CRC_date; //CRC_L
  188. Response_Message_Len = 8;
  189. }
  190. else //地址超限
  191. {
  192. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  193. }
  194. }
  195. /*********************************************************************************************
  196. * 功能     :  生成0x10功能码响应报文
  197. * 描述    : 通过判断地址范围生成0x10对应的响应报文
  198. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  199. * 返回值 : 无
  200. **********************************************************************************************/
  201. void Create_0x10_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  202. {
  203. unsigned int Start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  204. unsigned int Address_range = Start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  205. if (Address_range < MAX_Address)//判断地址是否超限
  206. {
  207. unsigned int Write_Number = Requst_Message[4] << 8 | Requst_Message[5];//要写入的寄存器个数
  208. for (int i = 7; i < Requst_Message[6] + 7; i = i + 2)//执行写入寄存器操作
  209. {
  210. Register[Start_Address] = Requst_Message[i] << 8 | Requst_Message[i+1];
  211. Start_Address++;
  212. }
  213. Response_Message[0] = Device_ID;
  214. Response_Message[1] = Requst_Message[1];
  215. Response_Message[2] = Requst_Message[2];
  216. Response_Message[3] = Requst_Message[3];
  217. Response_Message[4] = Requst_Message[4];
  218. Response_Message[5] = Requst_Message[5];
  219. UINT16 CRC_date = CRC_16(Response_Message, 6);
  220. Response_Message[6] = CRC_date >> 8;//CRC_H
  221. Response_Message[7] = (UINT8)CRC_date; //CRC_L
  222. Response_Message_Len = 8;
  223. }
  224. else //地址超限
  225. {
  226. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  227. }
  228. }
  229. /*********************************************************************************************
  230. * 功能     :  CRC校验
  231. * 描述    : 对请求报文中的数据进行CRC校验
  232. * 输入 : *Requst_Message 请求报文 Read_len 接收到到的字节数
  233. * 返回值 : true CRC校验通过
  234. * false CRC校验不通过
  235. **********************************************************************************************/
  236. bool Check_Requst_Message_CRC(UINT8 *Requst_Message, DWORD Read_len)
  237. {
  238. UINT16 CRC_data = CRC_16(Requst_Message, Read_len-2);
  239. UINT16 Message_CRC = Requst_Message[Read_len - 2] << 8 | Requst_Message[Read_len - 1];
  240. if (CRC_data != Message_CRC)
  241. return false;
  242. return true;
  243. }
  244. /*********************************************************************************************
  245. * 功能     :  异常码03判定--请求报文长度校验
  246. * 描述    : 对请求报文的字节长度进行计算校验
  247. * 输入 : *Requst_Message 请求报文 Read_len 接收到到的字节数
  248. * 返回值 : true 长度校验通过
  249. * false 长度校验不通过
  250. **********************************************************************************************/
  251. bool Check_Requst_Message_Len(UINT8 *Requst_Message, DWORD Read_len)
  252. {
  253. if (Requst_Message[1] == 0x01 || Requst_Message[1] == 0x03)
  254. {
  255. if (Read_len != 8)
  256. return false;
  257. }
  258. if (Requst_Message[1] == 0x0F || Requst_Message[1] == 0x10)
  259. {
  260. unsigned int Number = Requst_Message[4] << 8 | Requst_Message[5];
  261. unsigned int Count_len = Count_Read_date_number(Requst_Message[1], Number);
  262. if (Requst_Message[6] != Count_len || Read_len != Count_len + 9)
  263. return false;
  264. }
  265. return true;
  266. }
  267. /*********************************************************************************************
  268. * 功能     :  异常码03判定--请求报文中的操作数量判定
  269. * 描述    : 对请求报文中的操作数量进行判定
  270. * 输入 : *Requst_Message 请求报文 Read_len 接收到到的字节数
  271. * 返回值 : true 校验通过
  272. * false 校验不通过
  273. **********************************************************************************************/
  274. bool Check_Operation_Number_Requst_Message(UINT8 *Requst_Message)
  275. {
  276. unsigned int Operation_Number = Requst_Message[4] << 8 | Requst_Message[5];
  277. if (Requst_Message[1] == 0x01)
  278. {
  279. if (Operation_Number == 0 || Operation_Number > 2000)
  280. return false;
  281. }
  282. if (Requst_Message[1] == 0x03)
  283. {
  284. if (Operation_Number == 0 || Operation_Number > 125)
  285. return false;
  286. }
  287. if (Requst_Message[1] == 0x0F)
  288. {
  289. if (Operation_Number < 1 || Operation_Number > 1968)
  290. return false;
  291. }
  292. if (Requst_Message[1] == 0x10)
  293. {
  294. if (Operation_Number < 1 || Operation_Number > 123)
  295. return false;
  296. }
  297. return true;
  298. }
  299. /*********************************************************************************************
  300. * 功能     :  生成响应报文
  301. * 描述    : 检查设备请求报文来生成对应功能的响应报文
  302. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  303. * 返回值 : true 生成响应报文
  304. * false 不生成响应报文
  305. **********************************************************************************************/
  306. bool Create_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message, DWORD Read_len)
  307. {
  308. if (Requst_Message[0] != Device_ID) //检查设备ID一致
  309. return false;
  310. if (Read_len < 8 || Read_len > 256)
  311. return false;
  312. if (!Check_Requst_Message_CRC(Requst_Message, Read_len))//CRC校验报文是否正确
  313. return false;
  314. if (RTU_Enable == 0)
  315. {
  316. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x04);
  317. return true;
  318. }
  319. if (!Check_Requst_Message_Len(Requst_Message, Read_len) || !Check_Operation_Number_Requst_Message(Requst_Message))//检查请求报文长度是否正确
  320. {
  321. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x03);
  322. return true;
  323. }
  324. switch (Requst_Message[1])
  325. {
  326. case 0x01:Create_0x01_Response_Message(Requst_Message, Response_Message); break;
  327. case 0x03:Create_0x03_Response_Message(Requst_Message, Response_Message); break;
  328. case 0x0F:Create_0x0F_Response_Message(Requst_Message, Response_Message); break;
  329. case 0x10:Create_0x10_Response_Message(Requst_Message, Response_Message); break;
  330. default: Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message,0x01);
  331. }
  332. return true;
  333. }
  334. HANDLE Input_Parameter()
  335. {
  336. HANDLE Handle_Com;
  337. while (true)
  338. {
  339. GetComm_Name();
  340. string COMM = Input_COMM();
  341. unsigned int Baud_Rate = Input_Baud_Rate();
  342. BYTE Date_Bits = Input_Date_Bits();
  343. BYTE Stop_Bits = Input_Stop_Bits(Date_Bits);
  344. BYTE Parity = Input_Parity();
  345. Handle_Com = Init_COM((LPCTSTR)COMM.c_str(), Baud_Rate, Date_Bits, Stop_Bits, Parity);
  346. if (Handle_Com == INVALID_HANDLE_VALUE)
  347. {
  348. cout << "初始化串口失败,请重新输入设备信息\n" << endl;
  349. }
  350. else
  351. {
  352. printf("初始化串口成功\n");
  353. break;
  354. }
  355. }
  356. return Handle_Com;
  357. }
  358. int Modbus_RTU_Salve(void)
  359. {
  360. UINT8 Requst_Message[MAX_NUMBER];
  361. UINT8 Response_Message[MAX_NUMBER];
  362. HANDLE Handle_Com = Input_Parameter();
  363. Init_Coil_Register();
  364. DWORD Read_len;
  365. int Count = 0;
  366. while (true)
  367. {
  368. PurgeComm(Handle_Com, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT);//清除缓存
  369. BOOL Read_flage = ReadFile(Handle_Com, Requst_Message, 300, &Read_len, NULL); //阻塞等待接收请求报文
  370. if (Read_flage && (Read_len > 0))
  371. {
  372. if (Create_Response_Message(Requst_Message, Response_Message, Read_len))
  373. {
  374. while (!SendData(Handle_Com, (char*)Response_Message, Response_Message_Len))
  375. {
  376. Count++;
  377. printf("发送失败,重新发送第%d次\n",Count);
  378. if (Count > 4)
  379. {
  380. break;
  381. }
  382. }
  383. printf("主站请求 :");
  384. for (unsigned int i = 0; i < Read_len; i++)
  385. {
  386. printf("%02x ", Requst_Message[i]);
  387. }
  388. printf("\n");
  389. printf("从站响应 :");
  390. for (unsigned int i = 0; i < Response_Message_Len; i++)
  391. {
  392. printf("%02x ", Response_Message[i]);
  393. }
  394. printf("\n\n");
  395. //Log_Note(Requst_Message, 0, Read_len);
  396. //Log_Note(Response_Message, 1, Response_Message_Len);
  397. }
  398. else
  399. continue;
  400. }
  401. else
  402. {
  403. printf("设备端口异常,请检查设备连接状态\n");
  404. printf("**************************** Press Enter To Contioun ****************************\n");
  405. getchar();
  406. system("cls");
  407. printf("是否重新连接端口: 1 重新连接 0 关闭本软件\n");
  408. int a = 0 ;
  409. do
  410. {
  411. cin >> a;
  412. cin.clear();
  413. cin.sync();
  414. } while (!(a == 0 || a == 1));
  415. if (a == 1)
  416. {
  417. CloseHandle(Handle_Com);
  418. }
  419. else
  420. break;
  421. Handle_Com = Input_Parameter();
  422. }
  423. }
  424. CloseHandle(Handle_Com);
  425. getchar();
  426. return 0;
  427. }