Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

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