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

511 行
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. if(frame.wNum != ((frame.opeNum + 7) / 8))
  74. {
  75. ModbusErr = ModbusErrReply(0x0F, ERR_DATA);
  76. }
  77. else
  78. {
  79. memcpy(frame.wData, &rxBuf[7], frame.wNum);
  80. ModbusErr = ModbusWriteCoils(frame.opeAddres, frame.opeNum, frame.wData);
  81. }
  82. break;
  83. case 0x10:/*写多个寄存器*/
  84. frame.wNum = rxBuf[6];
  85. if(frame.wNum != (frame.opeNum * 2))
  86. {
  87. ModbusErr = ModbusErrReply(0x10, ERR_DATA);
  88. }
  89. else
  90. {
  91. memcpy(frame.wData, &rxBuf[7], frame.wNum);
  92. ModbusErr = ModbusWriteRegs(frame.opeAddres, frame.opeNum, frame.wData);
  93. }
  94. break;
  95. case 0x05:/*写单个线圈*/
  96. memcpy(frame.wData, &rxBuf[4], 2);
  97. ModbusErr = ModbusWriteCoil(frame.opeAddres, frame.wData);
  98. break;
  99. case 0x06:/*写单个寄存器*/
  100. memcpy(frame.wData, &rxBuf[4], 2);
  101. ModbusErr = ModbusWriteReg(frame.opeAddres, frame.wData);
  102. break;
  103. default:/*功能码错误*/
  104. ModbusErr = ERR_FUNC;
  105. ModbusErr = ModbusErrReply(frame.func, ERR_FUNC);
  106. break;
  107. }
  108. /*发送响应帧*/
  109. ModbusSend(ModbusTxBuf, ModbusTxLen);
  110. if(ModbusErr == 0 && (frame.func == 0x0F || frame.func == 0x10
  111. || frame.func == 0x05 || frame.func == 0x06))
  112. {
  113. /*释放写FLASH信号量*/
  114. OSSemPost(ModbusWriteFlash);
  115. }
  116. }
  117. }
  118. uint8_t ModbusReadCoils(uint16_t addres, uint16_t num)
  119. {
  120. uint16_t byteIndI; /*字节索引*/
  121. uint8_t bitIndI; /*位索引*/
  122. uint16_t byteIndO;
  123. uint8_t bitIndO;
  124. uint8_t dataLen; /*响应帧返回字节数*/
  125. uint8_t index; /*发送数组索引*/
  126. uint8_t readVal; /*读取到的形式值*/
  127. uint8_t writeVal; /*写入的形式值*/
  128. if(ModbusRxLen < 8)
  129. {
  130. return ModbusErrReply(0x01, ERR_DATA);
  131. }
  132. /*操作地址超限*/
  133. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  134. {
  135. return ModbusErrReply(0x01, ERR_OPE_ADDRES);
  136. }
  137. /*操作数量超限*/
  138. if(num == 0 || num > 2000)
  139. {
  140. return ModbusErrReply(0x01, ERR_DATA);
  141. }
  142. /*不能num/8+1,当为8的整数时会多一个*/
  143. dataLen = (num + 7) / 8;
  144. /*清零发送数组*/
  145. memset(&ModbusTxBuf[3], 0, 253);
  146. for(uint16_t i = 0; i < num; i++)
  147. {
  148. byteIndO = i / 8;
  149. bitIndO = i % 8;
  150. byteIndI = (addres + i) / 8;
  151. bitIndI = (addres + i) % 8;
  152. /*位掩码读取线圈值*/
  153. readVal = ModbusCoil[byteIndI] & ((uint8_t)1 << bitIndI);
  154. /*读取到的值为0则不进行操作*/
  155. if(readVal != 0)
  156. {
  157. index = 3 + byteIndO;
  158. /*将读取到的值移位到要写入的位*/
  159. writeVal = (uint8_t)1u << bitIndO;
  160. ModbusTxBuf[index] |= writeVal;
  161. }
  162. }
  163. ModbusTxBuf[0] = SLAVE_ADDRES; /*从机地址*/
  164. ModbusTxBuf[1] = 0x01; /*功能码*/
  165. ModbusTxBuf[2] = dataLen; /*响应帧返回数据字节数*/
  166. AddCrc16(ModbusTxBuf, 3 + dataLen);
  167. ModbusTxLen = 5 + dataLen;
  168. return 0;
  169. }
  170. uint8_t ModbusWriteCoils(uint16_t addres, uint16_t num, uint8_t *data)
  171. {
  172. uint16_t byteIndI;
  173. uint8_t bitIndI;
  174. uint16_t byteIndO;
  175. uint8_t bitIndO;
  176. uint8_t readVal;
  177. uint8_t writeVal;
  178. if(ModbusRxLen < 10)
  179. {
  180. return ModbusErrReply(0x0F, ERR_DATA);
  181. }
  182. /*操作地址超限*/
  183. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  184. {
  185. return ModbusErrReply(0x0F, ERR_OPE_ADDRES);
  186. }
  187. /*操作数量超限*/
  188. if(num == 0 || num > 1968)
  189. {
  190. return ModbusErrReply(0x0F, ERR_DATA);
  191. }
  192. for(uint16_t i = 0; i < num; i++)
  193. {
  194. byteIndI = (addres + i) / 8;
  195. bitIndI = (addres + i) % 8;
  196. byteIndO = i / 8;
  197. bitIndO = i % 8;
  198. /*位掩码读取要写入的值*/
  199. readVal = data[byteIndO] & ((uint8_t)1 << bitIndO);
  200. /*将写入值移位到要写入的位*/
  201. writeVal = (uint8_t)1 << bitIndI;
  202. /*对应位写入1*/
  203. if(readVal != 0)
  204. {
  205. ModbusCoil[byteIndI] |= writeVal;
  206. }
  207. /*对应位写入0*/
  208. else
  209. {
  210. ModbusCoil[byteIndI] &= (~writeVal);
  211. }
  212. }
  213. ModbusTxBuf[0] = SLAVE_ADDRES;
  214. ModbusTxBuf[1] = 0x0F;
  215. /*操作地址*/
  216. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  217. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  218. /*成功写入的数量*/
  219. ModbusTxBuf[4] = (uint8_t)(num >> 8);
  220. ModbusTxBuf[5] = (uint8_t)(num & 0x00FF);
  221. AddCrc16(ModbusTxBuf, 6);
  222. ModbusTxLen = 8;
  223. return 0;
  224. }
  225. uint8_t ModbusReadRegs(uint16_t addres, uint16_t num)
  226. {
  227. uint8_t index;
  228. uint8_t readValH;
  229. uint8_t readValL;
  230. uint8_t dataLen;
  231. if(ModbusRxLen < 8)
  232. {
  233. return ModbusErrReply(0x03, ERR_DATA);
  234. }
  235. /*操作地址超限*/
  236. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  237. {
  238. if(addres == 0xFFFF && num == 1)
  239. {
  240. ;
  241. }
  242. else
  243. {
  244. return ModbusErrReply(0x03, ERR_OPE_ADDRES);
  245. }
  246. }
  247. /*操作数量超限*/
  248. if(num == 0 || num > 125)
  249. {
  250. return ModbusErrReply(0x03, ERR_DATA);
  251. }
  252. dataLen = num * 2;
  253. /*附加功能:读取0x10000寄存器*/
  254. if(ModbusExtPage[0] == 1 && addres == 0x0000)
  255. {
  256. /*将16位寄存器值拆分为两个8位*/
  257. readValH = (uint8_t)(ModbusExtReg[0] >> 8);
  258. readValL = (uint8_t)(ModbusExtReg[0] & 0x00FF);
  259. ModbusTxBuf[3] = readValH;
  260. ModbusTxBuf[4] = readValL;
  261. }
  262. else
  263. {
  264. for(uint16_t i = 0; i < num; i++)
  265. {
  266. index = 3 + (i * 2);
  267. /*将16位寄存器值拆分为两个8位*/
  268. readValH = (uint8_t)(ModbusReg[addres + i] >> 8);
  269. readValL = (uint8_t)(ModbusReg[addres + i] & 0x00FF);
  270. ModbusTxBuf[index] = readValH;
  271. ModbusTxBuf[index + 1] = readValL;
  272. }
  273. }
  274. ModbusTxBuf[0] = SLAVE_ADDRES;
  275. ModbusTxBuf[1] = 0x03;
  276. ModbusTxBuf[2] = dataLen;
  277. AddCrc16(ModbusTxBuf, 3 + dataLen);
  278. ModbusTxLen = 5 + dataLen;
  279. return 0;
  280. }
  281. uint8_t ModbusWriteRegs(uint16_t addres, uint16_t num, uint8_t *data)
  282. {
  283. uint8_t index;
  284. uint8_t writeValH;
  285. uint8_t writeValL;
  286. uint16_t writeVal;
  287. if(ModbusRxLen < 11)
  288. {
  289. return ModbusErrReply(0x10, ERR_DATA);
  290. }
  291. /*操作地址超限*/
  292. if(addres > 0x270F || (addres + (num - 1)) > 0x270F)
  293. {
  294. if((addres == 0xFFFE || addres == 0xFFFF) && num == 1)
  295. {
  296. ;
  297. }
  298. else
  299. {
  300. return ModbusErrReply(0x10, ERR_OPE_ADDRES);
  301. }
  302. }
  303. /*操作数量超限*/
  304. if(num == 0 || num > 123)
  305. {
  306. return ModbusErrReply(0x10, ERR_DATA);
  307. }
  308. /*附加功能:读取0x10000寄存器*/
  309. if(addres == 0xFFFE && num == 1)
  310. {
  311. writeValH = data[0];
  312. writeValL = data[1];
  313. /*将要写入两个8位值拼接为16位*/
  314. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  315. ModbusExtPage[0] = writeVal;
  316. }
  317. /*附加功能:读取大量奇数寄存器*/
  318. else if(addres == 0xFFFF && num == 1)
  319. {
  320. writeValH = data[0];
  321. writeValL = data[1];
  322. /*将要写入两个8位值拼接为16位*/
  323. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  324. ModbusExtOdd[0] = writeVal;
  325. }
  326. /*正常功能*/
  327. else
  328. {
  329. for(uint16_t i = 0; i < num; i++)
  330. {
  331. index = i * 2;
  332. writeValH = data[index];
  333. writeValL = data[index + 1];
  334. /*将要写入两个8位值拼接为16位*/
  335. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  336. ModbusReg[addres + i] = writeVal;
  337. }
  338. }
  339. ModbusTxBuf[0] = SLAVE_ADDRES;
  340. ModbusTxBuf[1] = 0x10;
  341. /*操作地址*/
  342. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  343. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  344. /*成功写入数量*/
  345. ModbusTxBuf[4] = (uint8_t)(num >> 8);
  346. ModbusTxBuf[5] = (uint8_t)(num & 0x00FF);
  347. AddCrc16(ModbusTxBuf, 6);
  348. ModbusTxLen = 8;
  349. return 0;
  350. }
  351. uint8_t ModbusWriteCoil(uint16_t addres, uint8_t *data)
  352. {
  353. uint16_t byteIndI;
  354. uint8_t bitIndI;
  355. uint16_t readVal;
  356. uint8_t writeVal;
  357. if(ModbusRxLen < 8)
  358. {
  359. return ModbusErrReply(0x05, ERR_DATA);
  360. }
  361. /*操作地址超限*/
  362. if(addres > 0x270F)
  363. {
  364. return ModbusErrReply(0x05, ERR_OPE_ADDRES);
  365. }
  366. byteIndI = addres / 8;
  367. bitIndI = addres % 8;
  368. /*位掩码读取要写入的值*/
  369. readVal = ((uint16_t)data[0] << 8) | ((uint16_t)data[1] & 0x00FF);
  370. /*将写入值移位到要写入的位*/
  371. writeVal = (uint8_t)1 << bitIndI;
  372. /*置on*/
  373. if(readVal == 0xFF00)
  374. {
  375. ModbusCoil[byteIndI] |= writeVal;
  376. }
  377. /*置off*/
  378. else if(readVal == 0x0000)
  379. {
  380. ModbusCoil[byteIndI] &= (~writeVal);
  381. }
  382. else
  383. {
  384. return ModbusErrReply(0x05, ERR_DATA);
  385. }
  386. ModbusTxBuf[0] = SLAVE_ADDRES;
  387. ModbusTxBuf[1] = 0x05;
  388. /*操作地址*/
  389. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  390. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  391. /*成功写入*/
  392. ModbusTxBuf[4] = data[0];
  393. ModbusTxBuf[5] = data[1];
  394. AddCrc16(ModbusTxBuf, 6);
  395. ModbusTxLen = 8;
  396. return 0;
  397. }
  398. uint8_t ModbusWriteReg(uint16_t addres, uint8_t *data)
  399. {
  400. uint8_t writeValH;
  401. uint8_t writeValL;
  402. uint16_t writeVal;
  403. if(ModbusRxLen < 8)
  404. {
  405. return ModbusErrReply(0x06, ERR_DATA);
  406. }
  407. /*操作地址超限*/
  408. if(addres > 0x270F)
  409. {
  410. return ModbusErrReply(0x06, ERR_OPE_ADDRES);
  411. }
  412. writeValH = data[0];
  413. writeValL = data[1];
  414. /*将要写入两个8位值拼接为16位*/
  415. writeVal = ((uint16_t)writeValH << 8) | ((uint16_t)writeValL & 0x00FF);
  416. ModbusReg[addres] = writeVal;
  417. ModbusTxBuf[0] = SLAVE_ADDRES;
  418. ModbusTxBuf[1] = 0x06;
  419. /*操作地址*/
  420. ModbusTxBuf[2] = (uint8_t)(addres >> 8);
  421. ModbusTxBuf[3] = (uint8_t)(addres & 0x00FF);
  422. /*成功写入*/
  423. ModbusTxBuf[4] = writeValH;
  424. ModbusTxBuf[5] = writeValL;
  425. AddCrc16(ModbusTxBuf, 6);
  426. ModbusTxLen = 8;
  427. return 0;
  428. }
  429. uint8_t ModbusErrReply(uint8_t func, uint8_t err)
  430. {
  431. ModbusTxBuf[0] = SLAVE_ADDRES;
  432. ModbusTxBuf[1] = func | 0x80;
  433. ModbusTxBuf[2] = err;
  434. AddCrc16(ModbusTxBuf, 3);
  435. ModbusTxLen = 5;
  436. return err;
  437. }