找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

帖子
查看: 1576|回復: 6
打印 上一主題 下一主題
收起左側

關于MCU USART-DMA數(shù)據(jù)傳輸?shù)囊粋€bug請教

[復制鏈接]
跳轉到指定樓層
樓主
ID:644357 發(fā)表于 2023-4-28 15:59 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
問題描述:奇怪的MCU bug
16進制給板子發(fā)送數(shù)據(jù)
比如:
串口助手:發(fā)-04 03 01 02 03 0A C5 98
板子          收-04 03 01 02 03 0A C5 98
就能完成的完成數(shù)據(jù)傳輸
但是發(fā)
發(fā)-04 03 00 00 00 0A C5 98時


收到的就是
收-04 03 00 00 00 00 00 00

數(shù)據(jù)流收發(fā)沒問題,但是只要是00,就會把后面的數(shù)據(jù)給抹掉
串口中斷:
  1. void USART1_IRQHandler(void)
  2. {
  3.     OSIntEnter();

  4.     HAL_UART_IRQHandler(&huart1);

  5.         user_uart1IT_ReceiveCallback();
  6.    
  7.     OSIntExit();
  8. }

  9. void user_uart1IT_ReceiveCallback(void)
  10. {
  11.         uint8_t temp;
  12.         if((__HAL_UART_GET_FLAG(UART_DEBUG, UART_FLAG_IDLE) != RESET))  //獲取IDLE標志位,idle標志被置位
  13.         {
  14.                 __HAL_UART_CLEAR_IDLEFLAG(&huart1);                                                                                                                //清除空閑中斷標志位
  15.                 HAL_UART_DMAStop(UART_DEBUG);                                                                                                                                        //停止串口DMA功能
  16.                
  17.                 temp = huart1.hdmarx->Instance->CNDTR;                                                                                                //得到當前還剩余多少個數(shù)據(jù)
  18.                 uartDMA_data.bits.recive_count = BUFFER_SIZE - temp;                                        //接收數(shù)據(jù)計數(shù)
  19.                
  20.                 uartDMA_data.bits.interrupt_idle = ON;                                                                                                // 接受完成標志位置1        
  21.                
  22.         }
  23. }
復制代碼
數(shù)據(jù)接收服務,放在一個5ms定時一次的定時器中斷里
  1. void USART1DMA_rx_service(void)
  2. {
  3.    
  4.     /*在72MHZ系統(tǒng)時鐘工況下,此函數(shù)運行時間為無空閑中斷0.78ms-0.81ms;
  5.                                              有空閑中斷,需要處理 運行時間為72.114ms*/

  6.     /*將此接收服務判定函數(shù)置于中斷中,有較小概率產(chǎn)生數(shù)據(jù)丟包BUG*/
  7.     /*此任務函數(shù)置于定時中斷中,進行循環(huán)檢測*/
  8.     if(uartDMA_data.bits.interrupt_idle == ON)                //有空閑中斷
  9.     {
  10.         uartDMA_data.bits.interrupt_idle = OFF;

  11.         /*加入臨界段保護-----------------------------------------------------------------------------------------------------------------*/
  12.         CPU_SR_ALLOC();
  13.         CPU_CRITICAL_ENTER();  
  14.         
  15.         memset(uartDMA_data.bits.uart_buffer, 0, sizeof(uartDMA_data.bits.uart_buffer));                                    //清除緩存數(shù)據(jù)數(shù)組
  16.         memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((char *)uartDMA_data.bits.rx_buffer));    //取出數(shù)據(jù)
  17.         memset(uartDMA_data.bits.rx_buffer, 0, sizeof(uartDMA_data.bits.rx_buffer));                                        //清空數(shù)組
  18.         HAL_UART_Receive_DMA(UART_DEBUG, uartDMA_data.bits.rx_buffer, sizeof(uartDMA_data.bits.rx_buffer));                 //重新啟動串口DMA功能
  19.         
  20.         CPU_CRITICAL_EXIT();
  21.          /*加入臨界段保護-----------------------------------------------------------------------------------------------------------------*/
  22.         
  23.         if((DEBUG_USART_ENABLE==1)&&(Modbus_ENABLE==0)){
  24.             /*測試模式,向PC發(fā)送接收到的數(shù)據(jù)*/
  25.             
  26.         }
  27.         if((Modbus_ENABLE==1)&&(DEBUG_USART_ENABLE==0)){     /*進入MODBUS通訊模式*/
  28.             
  29.             uint8_t icnt;
  30.             /*空閑中斷發(fā)生,將DMA接收緩存數(shù)據(jù)轉存至MODBUS數(shù)據(jù)緩存中*/
  31.             Modbus_data_len =  uartDMA_data.bits.recive_count;
  32.             //HAL_UART_Transmit_DMA(UART_DEBUG, (uint8_t *)uartDMA_data.bits.uart_buffer, strlen((char *)uartDMA_data.bits.uart_buffer));        //打印接收到的數(shù)據(jù)
  33.             ModbusbuffAllow = 0;    //modbus緩存寫保護
  34.             for(icnt=0;icnt<Modbus_data_len;icnt++)
  35.             {
  36.                 modbus_Rx_buff[icnt] = uartDMA_data.bits.uart_buffer[icnt];
  37.             }
  38.             
  39.             ModbusbuffAllow = 1;    //modbus緩存解除寫保護
  40.             /*數(shù)據(jù)已經(jīng)寫入modbus緩存*/
  41.             //HAL_UART_Transmit_DMA(UART_DEBUG,modbus_Rx_buff,Modbus_data_len);
  42.         }
  43.         
  44.         
  45. //                Debug_Printf(UART_DEBUG, "\r\n*******************************串口 DMA方式接收打印如下 *****************************\r\n ");         HAL_Delay(100);
  46. //                        
  47. //                        Debug_Printf(UART_DEBUG, "\r\n HAL_UART_Transmit_DMA 庫函數(shù)打印\t:");         HAL_Delay(100);
  48. //                        HAL_UART_Transmit_DMA(UART_DEBUG, (uint8_t *)uartDMA_data.bits.uart_buffer, strlen((char *)uartDMA_data.bits.uart_buffer));        //打印接收到的數(shù)據(jù)
  49. //                        HAL_Delay(100);
  50. //                        Debug_Printf(UART_DEBUG, "\r\nDebug_Printf函數(shù)打印數(shù)組\t\t:");                                         HAL_Delay(100);
  51. //                        Debug_Printf(UART_DEBUG, (char *)uartDMA_data.bits.uart_buffer);        
  52. //                        HAL_Delay(100);
  53. //                        Debug_Printf(UART_DEBUG, "\r\nDebug_Printf函數(shù)打印字符\t\t:");                                         HAL_Delay(100);
  54. //                        Debug_Printf(UART_DEBUG, "uart MDA Debug printf function");
  55. //                        HAL_Delay(100);
  56. //                        Debug_Printf(UART_DEBUG, "\r\nDebug_Printf函數(shù)打印串口接收計數(shù)值\t:");                                         HAL_Delay(100);
  57. //                        Debug_Printf(UART_DEBUG, "recive_count: %d\r\n", uartDMA_data.bits.recive_count);
  58.     }
  59. }
復制代碼

源碼奉上: test.7z (818.38 KB, 下載次數(shù): 4)

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

來自 6#
ID:77589 發(fā)表于 2023-5-4 11:38 | 只看該作者
估計問題出在這里了:
memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((char *)uartDMA_data.bits.rx_buffer));    //取出數(shù)據(jù)
你是不熟悉strlen這個函數(shù)的用法,它是用于獲取字符串長度的,再想想,字符串是以什么結尾的?是不是'\0',這個東西轉成熟悉的十六進制是為是0x00?,所以遇到0x00就已經(jīng)表示字符串結束了,后面的字節(jié)理所當然的就被拋棄了啊!
你不是在總線空閑中斷處獲取了接收數(shù)據(jù)長度么,直接用那個長度就好了。
回復

使用道具 舉報

沙發(fā)
ID:644357 發(fā)表于 2023-4-28 17:30 | 只看該作者
初步查到問題是在HAL_UART_IRQHandler里,0x00會導致數(shù)據(jù)停止接收。
回復

使用道具 舉報

板凳
ID:94031 發(fā)表于 2023-4-28 19:27 | 只看該作者
看來你是MODBUS協(xié)議沒搞明白。
回復

使用道具 舉報

地板
ID:644357 發(fā)表于 2023-5-4 09:23 | 只看該作者
xuyaqi 發(fā)表于 2023-4-28 19:27
看來你是MODBUS協(xié)議沒搞明白。

并不是,里面雖然有MODBUS的前置處理函數(shù),問題并不在modbus里面,協(xié)議硬件部分是純手擼的,HAL庫的回調(diào)函數(shù)會把0x00判定為命令。停止接收。
回復

使用道具 舉報

5#
ID:644357 發(fā)表于 2023-5-4 11:27 | 只看該作者
  1.         memset(uartDMA_data.bits.uart_buffer, 0, sizeof(uartDMA_data.bits.uart_buffer));                                    //清除緩存數(shù)據(jù)數(shù)組
  2.         memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((char *)uartDMA_data.bits.rx_buffer));    //取出數(shù)據(jù)
  3.         memset(uartDMA_data.bits.rx_buffer, 0, sizeof(uartDMA_data.bits.rx_buffer));                                        //清空數(shù)組
  4.         HAL_UART_Receive_DMA(UART_DEBUG, uartDMA_data.bits.rx_buffer, sizeof(uartDMA_data.bits.rx_buffer));                 //重新啟動串口DMA功能
  5.         
復制代碼


問題已找到,strlen會把0x00識別為\0結束符,導致提前結束取出數(shù)據(jù)
回復

使用道具 舉報

7#
ID:644357 發(fā)表于 2023-5-5 09:15 | 只看該作者
Longan.Wang 發(fā)表于 2023-5-4 11:38
估計問題出在這里了:
memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((cha ...

大哥正解,通過這個BUG,感覺自己的C基礎還有待提高
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表