選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

442 行
12 KiB

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