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ů.
 
 
 
 

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