国产精品久久久久影院,成人午夜福利视频,国产精品久久久久高潮,国产精品 欧美 亚洲 制服,国产精品白浆无码流出

STM32 HAL庫利用DMA實現(xiàn)串口不定長度接收方法

發(fā)布者:GoldenEclipse最新更新時間:2025-02-19 來源: cnblogs關(guān)鍵字:STM32  HAL庫  DMA  串口 手機(jī)看文章 掃描二維碼
隨時隨地手機(jī)看文章

我這里使用的芯片是 F1 系列的,主要是利用 DMA 數(shù)據(jù)傳輸方式實現(xiàn)的,在配置工程的時候要注意配置好 DMA,并開啟中斷。

如果出現(xiàn)數(shù)據(jù)長度對,可是數(shù)據(jù)接收不完整,把Memory勾選即可:

1、利用STM32 cubemx 建立一個工程,工程建立請參考我以前的文章:https://www.cnblogs.com/xingboy/p/9597464.html


2、利用STM32 cubemx 生成代碼后,我們先定義一些變量來使用


/*    自己添加代碼部分    */

volatile uint8_t rx_len=0;                            //接收數(shù)據(jù)長度

volatile uint8_t recv_end_flag=0;                     //接收完成標(biāo)記位

uint8_t  rx_buffer[100];                              //接收緩存

char          BUFFER_SIZE=100;                        //不定長數(shù)據(jù)的最大長度,設(shè)置為100則最大長度為100

這里為什么要定義volatile 關(guān)鍵字呢?


主要是因為volatile 關(guān)鍵字提醒編譯器定義的變量是易變的,編譯后的程序每次需要存儲或讀取該變量時,會直接從變量地址讀取數(shù)據(jù)。在中斷或多線程中使用volatile關(guān)鍵字可以避免不同優(yōu)化等級時程序出錯,提高程序的魯棒性。


接著對串口初始化添加一些代碼,程序如下:


/* USART2 init function */

static void MX_USART2_UART_Init(void)

{


  huart2.Instance = USART2;

  huart2.Init.BaudRate = 115200;

  huart2.Init.WordLength = UART_WORDLENGTH_8B;

  huart2.Init.StopBits = UART_STOPBITS_1;

  huart2.Init.Parity = UART_PARITY_NONE;

  huart2.Init.Mode = UART_MODE_TX_RX;

  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;

  huart2.Init.OverSampling = UART_OVERSAMPLING_16;

  if (HAL_UART_Init(&huart2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

    

    /*    自己添加代碼部分    */

   __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);        //使能idle中斷

   HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE);  //打開DMA接收,數(shù)據(jù)存入rx_buffer數(shù)組中。


}


3、接收函數(shù)我寫在了另一個文件上,其他文件要用到上面 main文件里面定義的變量就要聲明一個外部變量


extern volatile uint8_t rx_len;

extern volatile uint8_t recv_end_flag;

extern uint8_t  rx_buffer[100];

extern char      BUFFER_SIZE;


4、接著修改串口中斷服務(wù)函數(shù),在串口中斷服務(wù)函數(shù)里添加接收代碼,代碼如下:

void USART2_IRQHandler(void)

{

  /* USER CODE BEGIN USART2_IRQn 0 */

    

    /*    自己添加代碼部分    */

    uint32_t tmp_flag = 0;

    uint32_t temp;

    tmp_flag =__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE);   //獲取IDLE標(biāo)志位

    if((tmp_flag != RESET))  //idle標(biāo)志被置位

    { 

        __HAL_UART_CLEAR_IDLEFLAG(&huart2);  //清除標(biāo)志位

        temp = huart2.Instance->SR;    //清除狀態(tài)寄存器SR(F0的HAL庫USART_TypeDef結(jié)構(gòu)體中名字為ISR:USART Interrupt and status register),讀取SR可以清楚該寄存器

        temp = huart2.Instance->DR;    //讀取數(shù)據(jù)寄存器中的數(shù)據(jù),讀取DR(F0中為RDR:USART Receive Data register)

        HAL_UART_DMAStop(&huart2); 

     temp  = hdma_usart2_rx.Instance->CNDTR;   //獲取DMA中未傳輸?shù)臄?shù)據(jù)個數(shù),NDTR寄存器分析見下面

        rx_len =  BUFFER_SIZE - temp;         //總計數(shù)減去未傳輸?shù)臄?shù)據(jù)個數(shù),得到已經(jīng)接收的數(shù)據(jù)個數(shù)

        recv_end_flag = 1;                //接受完成標(biāo)志位置1    

     }

 

  /* USER CODE END USART2_IRQn 0 */ 

  HAL_UART_IRQHandler(&huart2);

  /* USER CODE BEGIN USART2_IRQn 1 */


  /* USER CODE END USART2_IRQn 1 */

}


上面的 CNDTR 寄存器在 DMA 通道結(jié)構(gòu)體中定義了 CNDTR 寄存器,這個不同的芯片HAL庫里面定義的命名有點不同,有興趣的可以自己去查看一下,那為什么是未傳輸?shù)臄?shù)據(jù)數(shù)呢,STM32的中文手冊給出了該寄存器的具體說明。(注意:建立工程的時候要添加串口TX RX 的DMA通道,以及打開DMA中斷)


/** 

  * @brief DMA Controller

  */

typedef struct

{

  __IO uint32_t CCR;

  __IO uint32_t CNDTR;

  __IO uint32_t CPAR;

  __IO uint32_t CMAR;

} DMA_Channel_TypeDef;


寄存器說明如下:

5、接著編寫接收處理函數(shù),代碼如下:

/***************************************************************

    *函數(shù)名:Data_Turn

    *輸  入:無

    *說  明:串口接收完成,返回串口查看接收情況

    *返回值:無

  **/

void Data_Turn(void)

{


  if(recv_end_flag ==1)        

  {

      printf('rx_len=%drn',rx_len);                           //打印接收長度

      HAL_UART_Transmit(&huart2,rx_buffer, rx_len,200);        //接收數(shù)據(jù)打印出來

      for(uint8_t i=0;i      {

         rx_buffer[i]=0;   //清接收緩存

      }

      rx_len=0;        //清除計數(shù)

      recv_end_flag=0;    //清除接收結(jié)束標(biāo)志位

   }

}


6.再主函數(shù)里的的while循環(huán)里再次打開DMA中斷接收


HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE);            //重新打開DMA接收 


運行效果如下圖,我的代碼是接收到Do-0:1字符串,判斷字符串,返回我需要的字符串,效果正確。

 

補充一點最近新發(fā)現(xiàn)的關(guān)于串口中斷接收的問題:

串口中斷接收如果使用HAL庫的中斷接收函數(shù),接收到的數(shù)據(jù)量遠(yuǎn)小于設(shè)定要接收的數(shù)據(jù)量,串口一直處于Busy狀態(tài),會出現(xiàn)接收死循環(huán)的情況,接收的數(shù)據(jù)跟設(shè)定不符會出錯


注意:

測試過程中發(fā)現(xiàn),用接收串口助手的所有數(shù)據(jù)都沒問題,不過接收模塊的不定長數(shù)據(jù)時,如果這個數(shù)據(jù)之間包含回車換行符會接收不全,例如:ATrnOKrn,這個就只能接收到ATr,具體什么原因造成的還沒找出原因,有知道的可以告訴我一下。


不過如果是串口助手發(fā)這串?dāng)?shù)據(jù)下來,卻又可以全部接收完成,想不通。為了解決這個問題,我又找出了一個中斷接收的方法,可以實現(xiàn)了不管中間有沒有回車,都可以接收完成。


關(guān)鍵字:STM32  HAL庫  DMA  串口 引用地址:STM32 HAL庫利用DMA實現(xiàn)串口不定長度接收方法

上一篇:STM32 軟件復(fù)位并模擬USB拔插
下一篇:STM32 IIC雙機(jī)通信—— HAL庫硬件IIC版

小廣播
設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦

最新單片機(jī)文章

 
EEWorld訂閱號

 
EEWorld服務(wù)號

 
汽車開發(fā)圈

 
機(jī)器人開發(fā)圈

電子工程世界版權(quán)所有 京ICP證060456號 京ICP備10001474號-1 電信業(yè)務(wù)審批[2006]字第258號函 京公網(wǎng)安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved