HAL庫配置UART


https://blog.csdn.net/u012523921/article/details/105411008

https://jiejie.blog.csdn.net/article/details/80563422

 

1、查詢(基本不用)

2、中斷

3、中斷+DMA

操作分3個步驟

1、設置STM32cubeMX,初始化代碼在stm32f4xx_hal_msp.c,執行代碼在main.C

 

2、打開中斷和接收相關函數

//開啟空閑中斷
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);  

//UART_IT_IDLE  空閑中斷
//UART_IT_RXNE
//UART_IT_TXE
//UART_IT_PE
//UART_IT_TC
//UART_IT_LBD
//UART_IT_CTS
//UART_IT_ERR
                
//開啟DMA接收,                                     
  HAL_UART_Receive_DMA(&huart1, (uint8_t*)uart1_rx_buf, USART1_RX_BUF_SIZE); 
  
//@file    stm32f4xx_hal_uart.c    
/*
阻塞模式Blocking mode:通信以輪詢模式執行。
        (+) HAL_UART_Transmit()
        (+) HAL_UART_Receive()
非阻塞模式Non-Blocking:使用中斷執行通信,這些API會返回HAL狀態
        (+) HAL_UART_Transmit_IT()
        (+) HAL_UART_Receive_IT()
        (+) HAL_UART_IRQHandler()

非阻塞模式Non-Blocking:使用DMA執行通信或,這些API會返回HAL狀態
        (+) HAL_UART_Transmit_DMA()
        (+) HAL_UART_Receive_DMA()
        (+) HAL_UART_DMAPause()
        (+) HAL_UART_DMAResume()
        (+) HAL_UART_DMAStop()

非阻塞模式Non-Blocking回調函數:
        (+) HAL_UART_TxHalfCpltCallback()
        (+) HAL_UART_TxCpltCallback()
        (+) HAL_UART_RxHalfCpltCallback()
        (+) HAL_UART_RxCpltCallback()
        (+) HAL_UART_ErrorCallback()

非阻塞模式Non-Blocking中止執行函數:
        (+) HAL_UART_Abort()
        (+) HAL_UART_AbortTransmit()
        (+) HAL_UART_AbortReceive()
        (+) HAL_UART_Abort_IT()
        (+) HAL_UART_AbortTransmit_IT()
        (+) HAL_UART_AbortReceive_IT()

        (+) HAL_UART_AbortCpltCallback()
        (+) HAL_UART_AbortTransmitCpltCallback()
        (+) HAL_UART_AbortReceiveCpltCallback()

*/

 

3、處理相關函數

      處理相關函數一般放在中斷函數,或者回調函數內。先判斷中斷串口號,中斷類型,清除中斷類型。 

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */ USER_UART_IRQHandler(&huart1); //加入自己的中斷處理函數
  /* USER CODE END USART1_IRQn 1 */
}

 

//下面是自己的空閑中斷處理函數
void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
{
    if(USART1 == huart->Instance)                                   //判斷是否是串口1
    {
        if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))   //判斷是否是空閑中斷
        {
            __HAL_UART_CLEAR_IDLEFLAG(&huart1);                     //清楚空閑中斷標志(否則會一直不斷進入中斷)
            USAR_UART_IDLECallback(huart);                          //調用中斷處理函數
        }
    }
}

 

//空閑中斷回調函數
void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
{
   if(USART1 == huart->Instance){
        uint8_t data_len1;                                                          //停止本次DMA傳輸
        data_len1  = USART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);   //計算接收到的數據長度
        fifo_uart1_rx.tail =  data_len1; 
 
        if(fifo_uart1_rx.head <= fifo_uart1_rx.tail)
        {
            fifo_uart1_rx.DMAsize = fifo_uart1_rx.tail - fifo_uart1_rx.head;
        }
        else if(fifo_uart1_rx.head > fifo_uart1_rx.tail)
        {
            fifo_uart1_rx.DMAsize = USART1_RX_BUF_SIZE - fifo_uart1_rx.head + fifo_uart1_rx.tail;
        }
            fifo_uart1_rx.flag = 1;//置位標志,表示接收到數據
                
                
                
                
                __HAL_DMA_DISABLE(huart->hdmarx);
                //__HAL_DMA_SET_COUNTER(huart->hdmarx, USART1_RX_BUF_SIZE);        
            __HAL_DMA_ENABLE(huart->hdmarx);
                
        /*用戶實現的回調函數*/
                uart1_get_data(uart1_tx_dma_buf,fifo_uart1_rx.DMAsize);
               HAL_UART_Transmit_DMA(&huart1, uart1_tx_dma_buf,fifo_uart1_rx.DMAsiz); 
// HAL_UART_Transmit_DMA(&huart1, uart1_rx_buf, sizeof(uart1_rx_buf) - 1); // 采用DMA發送 str,按照str實際大小發送,不發送字符串末尾的'0' // if(p_uart1_rx_complete_callback != NULL) // (*p_uart1_rx_complete_callback)(); // //這里是定義的回調函數指針, // //用戶可以自己定義這個回調函數, // //因為我做的這個模塊是要打包給別人使用的, // //這種用戶實現的函數都是通過函數指針定義的, // //這樣用戶可以自己定義回調函數的函數名,如果不需要回調,可以將這里注釋掉; } }

 

//串口接收環形緩沖區取出函數
//參數1:串口接收環形緩沖區對象指針
//參數2:串口接收環形緩沖區最大長度
//參數3:取出的數據緩沖區地址
//參數4:取出的數據長度
//返回數據:取出的數據長度
uint16_t uart1_get_data(uint8_t *data_rsv,uint16_t len)
{
    uint16_t i=0;
    if(fifo_uart1_rx.flag &&(fifo_uart1_rx.DMAsize > 0))//接收到數據
    {
        for(;i<len;i++)//取出環形緩沖區的數據
        {
            data_rsv[i] = fifo_uart1_rx.buf[fifo_uart1_rx.head];
            fifo_uart1_rx.head ++;
            fifo_uart1_rx.head %= USART1_RX_BUF_SIZE;
            if(fifo_uart1_rx.head == fifo_uart1_rx.tail) 
            {
                fifo_uart1_rx.flag = 0;//清空接收數據標志
                i++;
                break;
            }
        }
    }
    return (i);
}

 

//這里是發送和接收緩沖區的定義
__align(2) uint8_t uart1_tx_dma_buf[USART1_TX_BUF_SIZE]={0};
__align(2) uint8_t uart1_rx_buf[USART1_RX_BUF_SIZE]={0};

/*這里雖然是注釋部分,但是這是工程中用到的代碼,這里只是以這種方式進行說明一下:
關於fifo_uart1_rx的說明,在uart.h中定義的環形結構體:*/
typedef struct{
    uint16_t head;//幀頭位置
    uint16_t tail;//幀尾位置
    uint16_t DMAsize;//硬件DMA發送的長度【接收幀長度】
    uint8_t *buf;         //內存起始地址,
    uint8_t flag;         //幀標志
    
}uart_fifo_t;

//串口1的環形緩沖區
static __IO uart_fifo_t fifo_uart1_tx={0,0,0,uart1_tx_dma_buf,0}; 

//串口1的環形緩沖區
static __IO uart_fifo_t fifo_uart1_rx={0,0,USART1_RX_BUF_SIZE,uart1_rx_buf,0}; 

 

#define RX_MAX_COUNT           255  // 串口接收最大字節數

 #define USART1_TX_BUF_SIZE 255
 #define USART1_RX_BUF_SIZE 255

//uint8_t USART1_RX_BUF_SIZE
//uint8_t    uart1_rx_buf[USART1_RX_BUF_SIZE];

__IO uint8_t aRxBuffer[RX_MAX_COUNT]={0}; // 接收緩沖區
__IO uint16_t RxCount=0;                  // 已接收到的字節數
__IO uint8_t Frame_flag=0;                // 幀標志:1:一個新的數據幀  0:無數據幀

extern uint8_t uart1_rx_buf[USART1_TX_BUF_SIZE];

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM