Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

497 Zeilen
13 KiB

  1. #include "stm32f4xx.h"
  2. #include "ucos_ii.h"
  3. #include "os.h"
  4. #include "string.h"
  5. #include "modbus_parse.h"
  6. #include "modbus_rec_send.h"
  7. extern OS_EVENT* ModbusWriteFlash; /*接收到modbus写入coil请求报文*/
  8. extern OS_EVENT* ModbusConnect; /*已接收到modbus正确报文*/
  9. uint8_t ModbusErr;
  10. /*0x270F + 1 = K10000 */
  11. uint8_t ModbusCoil[1250]; /*10000/8=1250*/
  12. uint16_t ModbusReg[10000];
  13. /*附加功能:页寄存器*/
  14. uint16_t ModbusExtPage[1] = {0}; /*设置地址为0xFFFE*/
  15. uint16_t ModbusExtReg[1]; /*地址映射为0x10000*/
  16. /*附加功能:读取所有单数个寄存器*/
  17. uint16_t ModbusExtOdd[1] = {0}; /*设置地址为0xFFFF*/
  18. uint8_t ModbusRxBuf[MODBUS_RX_BUF_SIZE]; /*接收数组*/
  19. uint16_t ModbusRxLen = 0; /*接收数据长度*/
  20. uint8_t ModbusTxBuf[MODBUS_TX_BUF_SIZE]; /*发送数组*/
  21. uint16_t ModbusTxLen = 0; /*发送数据长度*/
  22. /*modbus协议帧解析任务*/
  23. void AppTaskModbusParse (void *p_arg)
  24. {
  25. OS_ERR err;
  26. MODBUS_FRAME frame;
  27. uint16_t rxLen;
  28. uint8_t rxBuf[256];
  29. while(1)
  30. {
  31. /*无限期等待接收到数据帧信号量*/
  32. OSSemPend(ModbusReceived, 0, &err);
  33. /*数据接收,防止下一帧覆盖*/
  34. rxLen = ModbusRxLen;
  35. if(rxLen > MODBUS_RX_BUF_SIZE)
  36. {
  37. rxLen = 0;
  38. }
  39. memcpy(rxBuf, ModbusRxBuf, rxLen);
  40. /*帧分解*/
  41. frame.slaveAddres = rxBuf[0];
  42. frame.func = rxBuf[1];
  43. frame.crc = ((uint16_t)(rxBuf[rxLen - 2])) | ((uint16_t)rxBuf[rxLen - 1] << 8);
  44. frame.opeAddres = ((uint16_t)rxBuf[2] << 8) | ((uint16_t)rxBuf[3]);
  45. frame.opeNum = ((uint16_t)rxBuf[4] << 8) | ((uint16_t)rxBuf[5]);
  46. /*crc校验判断*/
  47. if(ChcekCrc16(frame.crc, rxBuf, rxLen) != 0)
  48. {
  49. /*crc校验错误,直接丢弃*/
  50. ModbusErr = ERR_CRC;
  51. continue;
  52. }
  53. /*从机地址判断*/
  54. if(frame.slaveAddres != SLAVE_ADDRES)
  55. {
  56. /*从机地址错误,直接丢弃*/
  57. ModbusErr = ERR_SLAVE_ADDRES;
  58. continue;
  59. }
  60. /*释放正确接收信号量*/
  61. OSSemPost(ModbusConnect);
  62. /*功能码分类*/
  63. switch(frame.func)
  64. {
  65. case 0x01:/*读线圈*/
  66. ModbusErr = ModbusReadCoils(frame.opeAddres, frame.opeNum);
  67. break;
  68. case 0x03:/*读寄存器*/
  69. ModbusErr = ModbusReadRegs(frame.opeAddres, frame.opeNum);
  70. break;
  71. case 0x0F:/*写多个线圈*/
  72. frame.wNum = rxBuf[6];
  73. memcpy(frame.wData, &rxBuf[7], frame.wNum);
  74. ModbusErr = ModbusWriteCoils(frame.opeAddres, frame.opeNum, frame.wData);
  75. break;
  76. case 0x10:/*写多个寄存器*/
  77. frame.wNum = rxBuf[6];
  78. memcpy(frame.wData, &rxBuf[7], frame.wNum);
  79. ModbusErr = ModbusWriteRegs(frame.opeAddres, frame.opeNum, frame.wData);
  80. break;
  81. case 0x05:/*写单个线圈*/
  82. memcpy(frame.wData, &rxBuf[4], 2);
  83. ModbusErr = ModbusWriteCoil(frame.opeAddres, frame.wData);
  84. break;
  85. case 0x06:/*写单个寄存器*/
  86. memcpy(frame.wData, &rxBuf[4], 2);
  87. ModbusErr = ModbusWriteReg(frame.opeAddres, frame.wData);
  88. break;
  89. default:/*功能码错误*/
  90. ModbusErr = ERR_FUNC;
  91. ModbusErr = ModbusErrReply(frame.func, ERR_FUNC);
  92. break;
  93. }
  94. /*发送响应帧*/
  95. ModbusSend(ModbusTxBuf, ModbusTxLen);
  96. if(ModbusErr == 0 && (frame.func == 0x0F || frame.func == 0x10
  97. || frame.func == 0x05 || frame.func == 0x06))
  98. {
  99. /*释放写FLASH信号量*/
  100. OSSemPost(ModbusWriteFlash);
  101. }
  102. }
  103. }
  104. uint8_t ModbusReadCoils(uint16_t addres, uint16_t num)
  105. {
  106. uint16_t byteIndI; /*字节索引*/
  107. uint8_t bitIndI; /*位索引*/
  108. uint16_t byteIndO;
  109. uint8_t bitIndO;
  110. uint8_t dataLen; /*响应帧返回字节数*/
  111. uint8_t index; /*发送数组索引*/
  112. uint8_t readVal; /*读取到的形式值*/
  113. uint8_t writeVal; /*写入的形式值*/
  114. if(ModbusRxLen < 8)
  115. {
  116. return ModbusErrReply(0x01, ERR_DATA);
  117. }
  118. /*操作地址超限*/
  119. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  120. {
  121. return ModbusErrReply(0x01, ERR_OPE_ADDRES);
  122. }
  123. /*操作数量超限*/
  124. if(num == 0 || num > 2000)
  125. {
  126. return ModbusErrReply(0x01, ERR_DATA);
  127. }
  128. /*不能num/8+1,当为8的整数时会多一个*/
  129. dataLen = (num + 7) / 8;
  130. /*清零发送数组*/
  131. memset(&ModbusTxBuf[3], 0, 253);
  132. for(uint16_t i = 0; i < num; i++)
  133. {
  134. byteIndO = i / 8;
  135. bitIndO = i % 8;
  136. byteIndI = (addres + i) / 8;
  137. bitIndI = (addres + i) % 8;
  138. /*位掩码读取线圈值*/
  139. readVal = ModbusCoil[byteIndI] & ((uint8_t)1 << bitIndI);
  140. /*读取到的值为0则不进行操作*/
  141. if(readVal != 0)
  142. {
  143. index = 3 + byteIndO;
  144. /*将读取到的值移位到要写入的位*/
  145. writeVal = (uint8_t)1u << bitIndO;
  146. ModbusTxBuf[index] |= writeVal;
  147. }
  148. }
  149. ModbusTxBuf[0] = SLAVE_ADDRES; /*从机地址*/
  150. ModbusTxBuf[1] = 0x01; /*功能码*/
  151. ModbusTxBuf[2] = dataLen; /*响应帧返回数据字节数*/
  152. AddCrc16(ModbusTxBuf, 3 + dataLen);
  153. ModbusTxLen = 5 + dataLen;
  154. return 0;
  155. }
  156. uint8_t ModbusWriteCoils(uint16_t addres, uint16_t num, uint8_t *data)
  157. {
  158. uint16_t byteIndI;
  159. uint8_t bitIndI;
  160. uint16_t byteIndO;
  161. uint8_t bitIndO;
  162. uint8_t readVal;
  163. uint8_t writeVal;
  164. if(ModbusRxLen < 10)
  165. {
  166. return ModbusErrReply(0x0F, ERR_DATA);
  167. }
  168. /*操作地址超限*/
  169. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  170. {
  171. return ModbusErrReply(0x0F, ERR_OPE_ADDRES);
  172. }
  173. /*操作数量超限*/
  174. if(num == 0 || num > 1968)
  175. {
  176. return ModbusErrReply(0x0F, ERR_DATA);
  177. }
  178. for(uint16_t i = 0; i < num; i++)
  179. {
  180. byteIndI = (addres + i) / 8;
  181. bitIndI = (addres + i) % 8;
  182. byteIndO = i / 8;
  183. bitIndO = i % 8;
  184. /*位掩码读取要写入的值*/
  185. readVal = data[byteIndO] & ((uint8_t)1 << bitIndO);
  186. /*将写入值移位到要写入的位*/
  187. writeVal = (uint8_t)1 << bitIndI;
  188. /*对应位写入1*/
  189. if(readVal != 0)
  190. {
  191. ModbusCoil[byteIndI] |= writeVal;
  192. }
  193. /*对应位写入0*/
  194. else
  195. {
  196. ModbusCoil[byteIndI] &= (~writeVal);
  197. }
  198. }
  199. ModbusTxBuf[0] = SLAVE_ADDRES;
  200. ModbusTxBuf[1] = 0x0F;
  201. /*操作地址*/
  202. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  203. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  204. /*成功写入的数量*/
  205. ModbusTxBuf[4] = (uint8_t)(num >> 8);
  206. ModbusTxBuf[5] = (uint8_t)(num & 0x00FF);
  207. AddCrc16(ModbusTxBuf, 6);
  208. ModbusTxLen = 8;
  209. return 0;
  210. }
  211. uint8_t ModbusReadRegs(uint16_t addres, uint16_t num)
  212. {
  213. uint8_t index;
  214. uint8_t readValH;
  215. uint8_t readValL;
  216. uint8_t dataLen;
  217. if(ModbusRxLen < 8)
  218. {
  219. return ModbusErrReply(0x03, ERR_DATA);
  220. }
  221. /*操作地址超限*/
  222. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  223. {
  224. if(addres == 0xFFFF && num == 1)
  225. {
  226. ;
  227. }
  228. else
  229. {
  230. return ModbusErrReply(0x03, ERR_OPE_ADDRES);
  231. }
  232. }
  233. /*操作数量超限*/
  234. if(num == 0 || num > 125)
  235. {
  236. return ModbusErrReply(0x03, ERR_DATA);
  237. }
  238. dataLen = num * 2;
  239. /*附加功能:读取0x10000寄存器*/
  240. if(ModbusExtPage[0] == 1 && addres == 0x0000)
  241. {
  242. /*将16位寄存器值拆分为两个8位*/
  243. readValH = (uint8_t)(ModbusExtReg[0] >> 8);
  244. readValL = (uint8_t)(ModbusExtReg[0] & 0x00FF);
  245. ModbusTxBuf[3] = readValH;
  246. ModbusTxBuf[4] = readValL;
  247. }
  248. else
  249. {
  250. for(uint16_t i = 0; i < num; i++)
  251. {
  252. index = 3 + (i * 2);
  253. /*将16位寄存器值拆分为两个8位*/
  254. readValH = (uint8_t)(ModbusReg[addres + i] >> 8);
  255. readValL = (uint8_t)(ModbusReg[addres + i] & 0x00FF);
  256. ModbusTxBuf[index] = readValH;
  257. ModbusTxBuf[index + 1] = readValL;
  258. }
  259. }
  260. ModbusTxBuf[0] = SLAVE_ADDRES;
  261. ModbusTxBuf[1] = 0x03;
  262. ModbusTxBuf[2] = dataLen;
  263. AddCrc16(ModbusTxBuf, 3 + dataLen);
  264. ModbusTxLen = 5 + dataLen;
  265. return 0;
  266. }
  267. uint8_t ModbusWriteRegs(uint16_t addres, uint16_t num, uint8_t *data)
  268. {
  269. uint8_t index;
  270. uint8_t writeValH;
  271. uint8_t writeValL;
  272. uint16_t writeVal;
  273. if(ModbusRxLen < 11)
  274. {
  275. return ModbusErrReply(0x10, ERR_DATA);
  276. }
  277. /*操作地址超限*/
  278. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  279. {
  280. if((addres == 0xFFFE || addres == 0xFFFF) && num == 1)
  281. {
  282. ;
  283. }
  284. else
  285. {
  286. return ModbusErrReply(0x10, ERR_OPE_ADDRES);
  287. }
  288. }
  289. /*操作数量超限*/
  290. if(num == 0 || num > 123)
  291. {
  292. return ModbusErrReply(0x10, ERR_DATA);
  293. }
  294. /*附加功能:读取0x10000寄存器*/
  295. if(addres == 0xFFFE && num == 1)
  296. {
  297. writeValH = data[0];
  298. writeValL = data[1];
  299. /*将要写入两个8位值拼接为16位*/
  300. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  301. ModbusExtPage[0] = writeVal;
  302. }
  303. /*附加功能:读取大量奇数寄存器*/
  304. else if(addres == 0xFFFF && num == 1)
  305. {
  306. writeValH = data[0];
  307. writeValL = data[1];
  308. /*将要写入两个8位值拼接为16位*/
  309. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  310. ModbusExtOdd[0] = writeVal;
  311. }
  312. /*正常功能*/
  313. else
  314. {
  315. for(uint16_t i = 0; i < num; i++)
  316. {
  317. index = i * 2;
  318. writeValH = data[index];
  319. writeValL = data[index + 1];
  320. /*将要写入两个8位值拼接为16位*/
  321. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  322. ModbusReg[addres + i] = writeVal;
  323. }
  324. }
  325. ModbusTxBuf[0] = SLAVE_ADDRES;
  326. ModbusTxBuf[1] = 0x10;
  327. /*操作地址*/
  328. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  329. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  330. /*成功写入数量*/
  331. ModbusTxBuf[4] = (uint8_t)(num >> 8);
  332. ModbusTxBuf[5] = (uint8_t)(num & 0x00FF);
  333. AddCrc16(ModbusTxBuf, 6);
  334. ModbusTxLen = 8;
  335. return 0;
  336. }
  337. uint8_t ModbusWriteCoil(uint16_t addres, uint8_t *data)
  338. {
  339. uint16_t byteIndI;
  340. uint8_t bitIndI;
  341. uint16_t readVal;
  342. uint8_t writeVal;
  343. if(ModbusRxLen < 8)
  344. {
  345. return ModbusErrReply(0x05, ERR_DATA);
  346. }
  347. /*操作地址超限*/
  348. if(addres > 0x270F)
  349. {
  350. return ModbusErrReply(0x05, ERR_OPE_ADDRES);
  351. }
  352. byteIndI = addres / 8;
  353. bitIndI = addres % 8;
  354. /*位掩码读取要写入的值*/
  355. readVal = ((uint16_t)data[0] << 8) | ((uint16_t)data[1] & 0x00FF);
  356. /*将写入值移位到要写入的位*/
  357. writeVal = (uint8_t)1 << bitIndI;
  358. /*置on*/
  359. if(readVal == 0xFF00)
  360. {
  361. ModbusCoil[byteIndI] |= writeVal;
  362. }
  363. /*置off*/
  364. else if(readVal == 0x0000)
  365. {
  366. ModbusCoil[byteIndI] &= (~writeVal);
  367. }
  368. else
  369. {
  370. return ModbusErrReply(0x05, ERR_DATA);
  371. }
  372. ModbusTxBuf[0] = SLAVE_ADDRES;
  373. ModbusTxBuf[1] = 0x05;
  374. /*操作地址*/
  375. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  376. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  377. /*成功写入*/
  378. ModbusTxBuf[4] = data[0];
  379. ModbusTxBuf[5] = data[1];
  380. AddCrc16(ModbusTxBuf, 6);
  381. ModbusTxLen = 8;
  382. return 0;
  383. }
  384. uint8_t ModbusWriteReg(uint16_t addres, uint8_t *data)
  385. {
  386. uint8_t writeValH;
  387. uint8_t writeValL;
  388. uint16_t writeVal;
  389. if(ModbusRxLen < 8)
  390. {
  391. return ModbusErrReply(0x06, ERR_DATA);
  392. }
  393. /*操作地址超限*/
  394. if(addres > 0x270F)
  395. {
  396. return ModbusErrReply(0x06, ERR_OPE_ADDRES);
  397. }
  398. writeValH = data[0];
  399. writeValL = data[1];
  400. /*将要写入两个8位值拼接为16位*/
  401. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  402. ModbusReg[addres] = writeVal;
  403. ModbusTxBuf[0] = SLAVE_ADDRES;
  404. ModbusTxBuf[1] = 0x06;
  405. /*操作地址*/
  406. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  407. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  408. /*成功写入*/
  409. ModbusTxBuf[4] = writeValH;
  410. ModbusTxBuf[5] = writeValL;
  411. AddCrc16(ModbusTxBuf, 6);
  412. ModbusTxLen = 8;
  413. return 0;
  414. }
  415. uint8_t ModbusErrReply(uint8_t func, uint8_t err)
  416. {
  417. ModbusTxBuf[0] = SLAVE_ADDRES;
  418. ModbusTxBuf[1] = func | 0x80;
  419. ModbusTxBuf[2] = err;
  420. AddCrc16(ModbusTxBuf, 3);
  421. ModbusTxLen = 5;
  422. return err;
  423. }