久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: HAL庫串口中斷RX中的Overrun Error解決方案 [打印本頁]

作者: 我是你的小號    時間: 2021-6-1 23:59
標題: HAL庫串口中斷RX中的Overrun Error解決方案
[首先簡單研究一下什么時候會出現overrun的問題,配置正常的HAL串口中斷接收如下
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   /* judge interrupt source */
   if(huart ->Instance == USART2)
  {
       //send data to huart1 from huart2
       HAL_UART_Transmit(&huart1, (uint8_t*)recv_buf, 3,0xFFFF);
       //enable RX IT
       HAL_UART_Receive_IT(huart, (uint8_t*)recv_buf, 3);
  }
}
[
可以看出,分三種情況:
[其中,觸發兩次接收緩存溢出的時候,就會進入Overrun Error。
[比如說BUF長度為3,連續發兩次長度為4的數據,就會進入ORE。或者說第一次發送長度為2的數據,然后接著發送兩次長度為3的數據,也是會觸發ORE的,后續的兩次長度為3的數據因為有之前一條長度為2的鋪墊,都是視作BUF溢出的數據。但是如果發送一次長度為4的數據之后,后續發長度一條長度為2的數據,就會進入正常狀態,是有彈性的。彈性限度為BUF長度的兩倍,也就是說發送一次長度為6的數據,會立即進入ORE。
[ORE狀態下,串口進入ORE溢出中斷,無法繼續接收數據,但是可以發送數據,相當于接收數據不會觸發中斷了。
[對于ORE溢出常用解決方案有下:
[無論哪一種方法都要理解HAL_UART_RxCpltCallback的實現原理:
[從上到下,層層封裝和調用。
  1. void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
  2. {
  3. uint32_t isrflags = READ_REG(huart->Instance->SR);
  4. uint32_t cr1its = READ_REG(huart->Instance->CR1);
  5. uint32_t cr3its = READ_REG(huart->Instance->CR3);
  6. uint32_t errorflags = 0x00U;
  7. uint32_t dmarequest = 0x00U;
  8. /* If no error occurs */
  9. errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  10. //close ORE check
  11. //errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_NE));
  12. if (errorflags == RESET)
  13. {
  14. /* UART in mode Receiver -------------------------------------------------*/
  15. if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
  16. {
  17. UART_Receive_IT(huart);
  18. return;
  19. }
  20. }

復制代碼
[        想要關閉ORE中斷,將errorflags中的USART_SR_ORE 這一位去掉即可,相當于對ORE錯誤不予檢查,經過實際的測試是可行的,實際的表現就是出現ORE溢出之后,串口只接受固定BUF長度的數據,對于溢出的數據直接丟棄,但是還需要考慮ORE溢出之后,那個時刻中BUF肯定是有數據,但是由于沒有清除BUF,后續的數據直接進來會導致錯位,因此想要真正實現完美的溢出數據丟棄處理且不影響后續的數據,是要在程序中加入清除BUF的指令的。但是這些方法都會影響HAL庫的底層代碼,包括去掉USART_SR_ORE 這一位,這也是STM32IDE的一點的不好的地方,底層文件是沒有用戶代碼入口的,修改IOC文件之后,一切都會回到最初的起點。
[          其次就是雙重緩存,具體的就是將BUF長度設置為1,這樣子每一次收到一個字節的話都會調用回調函數,為什么長度長度大于1的時候會發生ORE,而1的時候可以接受很長的數據而不ORE呢,我猜是因為1的時候將某些位置位了,間接關閉了ORE,然后用戶自己定義BUF區,一個一個去讀取寫入,這個方法還可以實現不定長的接收,設置數據結束幀位就可以了。缺點也很明顯,當數據很長的時候,中斷要進入很多次,有點占資源了。
[用戶回調函數HAL_UART_RxCpltCallback只有接收到設定的BUF的長度才會調用一次,而不是有字節就調用,實現的方法在UART_Receive_IT函數中:
  1.   if (--huart->RxXferCount == 0U)
  2.   {
  3.      /* Disable the UART Data Register not empty Interrupt */
  4.      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

  5.      /* Disable the UART Parity Error Interrupt */
  6.      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

  7.      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
  8.      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

  9.      /* Rx process is completed, restore huart->RxState to Ready */
  10.      huart->RxState = HAL_UART_STATE_READY;

  11. #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  12.      /*Call registered Rx complete callback*/
  13.      huart->RxCpltCallback(huart);
  14. #else
  15.      /*Call legacy weak Rx complete callback*/
  16.      HAL_UART_RxCpltCallback(huart);
  17. #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
復制代碼

[if (--huart->RxXferCount == 0U)這一句,每次字節來都會調用UART_Receive_IT,然后RxXferCount減1,這個變量就是一開始設置的BUF接收長度,只有等這個到零了,才會調用HAL_UART_RxCpltCallback(huart)
[最終,因為在項目中串口是需要來高頻率接收固定長度的測量數據的,但是在之前要用串口發送上電指令,這個指令會返回一個和測量數據長度不同的ASK信號,處理方法就是在上電之后,再開啟串口接收,這樣子就可以設置BUF長度為固定長度,同時稍微降低測量的頻率,讓串口接收有足夠的時間,避免ORE的產生。






歡迎光臨 (http://www.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 日韩中文字幕第一页 | 高清av一区 | 日韩三片 | 91麻豆久久久 | 爱高潮www亚洲精品 中文字幕免费视频 | 国产亚洲精品久久久久动 | 国产精品夜夜春夜夜爽久久电影 | 亚洲一区二区精品视频在线观看 | 国产网站在线播放 | 色综合区 | 精品欧美二区 | 91视频免费在观看 | 欧美一区二区三区视频在线 | av在线电影网站 | 亚洲日韩中文字幕一区 | 一a一片一级一片啪啪 | 精品久久久一区 | 蜜桃视频在线观看免费视频网站www | 亚洲精品日韩一区二区电影 | 麻豆av一区二区三区久久 | 国产激情视频 | 国产精品日韩欧美 | 一区二区免费在线观看 | 成人av电影在线 | 亚洲乱码一区二区三区在线观看 | 99亚洲精品| 日韩精品在线观看视频 | 91久久国产综合久久91精品网站 | 亚洲精品日本 | 久久大 | 国产成人综合在线 | 在线婷婷| 午夜久久久久久久久久一区二区 | 婷婷不卡 | 中文字幕免费观看 | 草草影院ccyy | 2023亚洲天堂 | 亚洲精品国产一区 | 精品视频一区在线 | 久久精品日产第一区二区三区 | 欧美一级免费看 |