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];

 

posted @ 2020-10-02 07:18  流水江湖  阅读(3252)  评论(0编辑  收藏  举报