You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

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