Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

527 рядки
14 KiB

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