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

269 行
8.3 KiB

  1. #include "modbus_rec_send.h"
  2. #include "hardware.h"
  3. MODBUS_RX_STATE ModbusRxState = MODBUS_RX_RECEIVING;
  4. /*USART接收空闲中断*/
  5. void USART1_IRQHandler(void)
  6. {
  7. uint32_t temp;
  8. uint16_t rxLenRemain;
  9. OSIntEnter(); /*进入中断*/
  10. if(USART_GetITStatus(USART1, USART_IT_IDLE) == SET)
  11. {
  12. /*清除IDLE中断标志位*/
  13. temp = USART1->SR;
  14. temp = USART1->DR;
  15. (void)temp;
  16. /*判断是否接收到帧,触发TIM计时*/
  17. rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);
  18. ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain;
  19. if(ModbusRxLen != 0)
  20. {
  21. switch (ModbusRxState)
  22. {
  23. /*正常接收数据*/
  24. case MODBUS_RX_RECEIVING:
  25. ModbusRxState = MODBUS_RX_CHECK_T15;
  26. TimRestart(MODBUS_IDLE_TO_T15_US);
  27. break;
  28. /*在t1.5定时还未到达时又接收到了数据*/
  29. case MODBUS_RX_CHECK_T15:
  30. ModbusRxState = MODBUS_RX_CHECK_T15;
  31. TimRestart(MODBUS_IDLE_TO_T15_US);
  32. break;
  33. /*在判断t1.5~t3.5是否出现字符时,t3.5定时中断还未触发,又接收到了数据*/
  34. case MODBUS_RX_CHECK_T35:
  35. ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35; /*判断为错误帧*/
  36. TimRestart(MODBUS_IDLE_TO_T35_US); /*等待3.5字符该帧结束之后丢失该帧*/
  37. break;
  38. /*在t1.5~t3.5中出现字符,随后又接收到数据*/
  39. case MODBUS_RX_DISCARD:
  40. ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35; /*判断为错误帧*/
  41. TimRestart(MODBUS_IDLE_TO_T35_US); /*等待3.5字符该帧结束之后丢失该帧*/
  42. break;
  43. /*在等待3.5字符该帧结束期间又接收到数据*/
  44. case MODBUS_RX_DISCARD_CHECK_T35:
  45. ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35;
  46. TimRestart(MODBUS_IDLE_TO_T35_US); /*再等待3.5字符该帧结束之后丢失该帧*/
  47. break;
  48. }
  49. }
  50. }
  51. OSIntExit(); /*退出中断*/
  52. }
  53. /*TIM定时器中断*/
  54. void TIM5_IRQHandler(void)
  55. {
  56. uint16_t rxLenRemain;
  57. OSIntEnter();
  58. rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);
  59. if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
  60. {
  61. switch (ModbusRxState)
  62. {
  63. /*检查在t1-t1.5期间是否接收到数据*/
  64. case MODBUS_RX_CHECK_T15:
  65. /*在t1-t1.5期间接收到了数据,正常继续接收*/
  66. if (MODBUS_RX_BUF_SIZE - rxLenRemain != ModbusRxLen)
  67. {
  68. ModbusRxState = MODBUS_RX_RECEIVING;
  69. TimOff();
  70. }
  71. /*在t1-t1.5期间没收到,开始检查t1.5-t3.5期间是否接收到数据*/
  72. else
  73. {
  74. ModbusRxState = MODBUS_RX_CHECK_T35;
  75. TimRestart(MODBUS_T15_TO_T35_US);
  76. }
  77. break;
  78. /*检查在t1.5-t3.5期间是否接收到数据*/
  79. case MODBUS_RX_CHECK_T35:
  80. /*在t1.5-t3.5期间接收到了数据,判断为错误帧,等待串口空闲中断开启3.5字符等待定时器计时*/
  81. if (MODBUS_RX_BUF_SIZE - rxLenRemain != ModbusRxLen)
  82. {
  83. ModbusRxState = MODBUS_RX_DISCARD;
  84. TimOff();
  85. }
  86. /*在t1.5-t3.5之间都没接收到数据,该帧结束,开始帧解析*/
  87. else
  88. {
  89. ModbusRxState = MODBUS_RX_RECEIVING;
  90. ModbusParseWakeUp();
  91. }
  92. break;
  93. /*接收到错误帧,等待3.5字符之后丢弃该帧*/
  94. case MODBUS_RX_DISCARD_CHECK_T35:
  95. /*在等待3.5字符期间又接收到了数据,等待串口空闲中断重新开启3.5字符等待定时器计时*/
  96. if (MODBUS_RX_BUF_SIZE - rxLenRemain != ModbusRxLen)
  97. {
  98. ModbusRxState = MODBUS_RX_DISCARD_CHECK_T35;
  99. TimOff();
  100. }
  101. /*在等待3.5字符期间没接收到数据,该错误帧结束,丢弃该帧,准备开始下一帧的接收*/
  102. else
  103. {
  104. ModbusRxState = MODBUS_RX_RECEIVING;
  105. ModbusDmaRestart();
  106. }
  107. break;
  108. }
  109. }
  110. OSIntExit();
  111. }
  112. void TimRestart(uint32_t timArr)
  113. {
  114. /*启动TIM计时*/
  115. TIM_Cmd(TIM5, DISABLE);
  116. TIM_SetCounter(TIM5, 0); /*清除计数值*/
  117. TIM_SetAutoreload(TIM5, timArr);
  118. TIM_ClearITPendingBit(TIM5, TIM_IT_Update); /*清除中断标志位*/
  119. TIM_Cmd(TIM5, ENABLE);
  120. }
  121. void TimOff(void)
  122. {
  123. TIM_Cmd(TIM5, DISABLE);
  124. TIM_SetCounter(TIM5, 0); /*清除计数值*/
  125. TIM_ClearITPendingBit(TIM5, TIM_IT_Update); /*清除中断标志位*/
  126. }
  127. void ModbusParseWakeUp(void)
  128. {
  129. uint16_t rxLenRemain;
  130. TimOff();
  131. /*关闭DMA*/
  132. DMA_Cmd(DMA2_Stream2, DISABLE);
  133. /*清除传输已经完成TCIF2、传输已经完成一半HTIF2标志位*/
  134. DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2);
  135. /*计算数据长度*/
  136. rxLenRemain = DMA_GetCurrDataCounter(DMA2_Stream2);
  137. ModbusRxLen = MODBUS_RX_BUF_SIZE - rxLenRemain;
  138. /*释放接收到数据帧信号量,唤醒帧解析任务*/
  139. if(ModbusRxLen >= 4) /*4字节(1字节地址、1字节功能、2字节CRC)*/
  140. {
  141. OSSemPost(ModbusReceived);
  142. }
  143. /*重新指定接收地址*/
  144. DMA_MemoryTargetConfig(DMA2_Stream2, (uint32_t)ModbusRxBuf, DMA_Memory_0);
  145. /*重启DMA*/
  146. DMA_SetCurrDataCounter(DMA2_Stream2, MODBUS_RX_BUF_SIZE);
  147. DMA_Cmd(DMA2_Stream2, ENABLE);
  148. }
  149. void ModbusDmaRestart(void)
  150. {
  151. TimOff();
  152. /*关闭DMA*/
  153. DMA_Cmd(DMA2_Stream2, DISABLE);
  154. /*清除传输已经完成TCIF2、传输已经完成一半HTIF2标志位*/
  155. DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2);
  156. /*重新指定接收地址*/
  157. DMA_MemoryTargetConfig(DMA2_Stream2, (uint32_t)ModbusRxBuf, DMA_Memory_0);
  158. /*重启DMA*/
  159. DMA_SetCurrDataCounter(DMA2_Stream2, MODBUS_RX_BUF_SIZE);
  160. DMA_Cmd(DMA2_Stream2, ENABLE);
  161. }
  162. /*modbus响应帧发送*/
  163. void ModbusSend(uint8_t *txBuf, uint16_t len)
  164. {
  165. if(DMA_GetCmdStatus(DMA2_Stream7) == ENABLE)
  166. {
  167. /*等待DMA发送完成*/
  168. while(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) == RESET);
  169. }
  170. /*先关闭DMA发送通道*/
  171. DMA_Cmd(DMA2_Stream7, DISABLE);
  172. /*等待DMA关闭*/
  173. while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);
  174. /*清除传输已经完成TCIF7、传输已经完成一半HTIF7、FIFO错误FEIF7标志位*/
  175. DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_FEIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TCIF7);
  176. /*配置发送地址和长度*/
  177. DMA_MemoryTargetConfig(DMA2_Stream7, (uint32_t)txBuf, DMA_Memory_0);
  178. DMA_SetCurrDataCounter(DMA2_Stream7, len);
  179. /*等待串口发送完成*/
  180. while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
  181. /*启动 DMA 发送*/
  182. DMA_Cmd(DMA2_Stream7, ENABLE);
  183. }
  184. /*crc16校验*/
  185. uint16_t Crc16(const uint8_t *data, uint16_t length)
  186. {
  187. uint16_t crc;
  188. uint16_t byteInd;
  189. uint8_t bitInd;
  190. crc = 0xFFFFu;
  191. for (byteInd = 0u; byteInd < length; byteInd++)
  192. {
  193. crc ^= (uint16_t)data[byteInd];
  194. for (bitInd = 0u; bitInd < 8u; bitInd++)
  195. {
  196. if ((crc & 0x0001u) != 0u)
  197. {
  198. crc >>= 1;
  199. crc ^= 0xA001u;
  200. }
  201. else
  202. {
  203. crc >>= 1;
  204. }
  205. }
  206. }
  207. return crc;
  208. }
  209. /*crc16检查*/
  210. int8_t ChcekCrc16(uint16_t recCrc16, uint8_t *data, uint16_t length)
  211. {
  212. uint16_t crc16 = Crc16(data, (length - 2));
  213. if(recCrc16 == crc16)
  214. {
  215. return 0;
  216. }
  217. else
  218. {
  219. return -1;
  220. }
  221. }
  222. void AddCrc16(uint8_t *data, uint16_t length)
  223. {
  224. uint8_t *dataT = data;
  225. uint16_t crc16 = Crc16(data, length);
  226. /*低前高后*/
  227. dataT[length] = (uint8_t)(crc16 & 0x00FF);
  228. dataT[length + 1] = (uint8_t)(crc16 >> 8);
  229. }