[STM32F4]

stm32F4XX之UART&DMA HAL库

[复制链接]
359|5
手机看帖
扫描二维码
随时随地手机跟帖
heimaojingzhang|  楼主 | 2021-8-4 11:58 | 显示全部楼层 |阅读模式
1:串口相关的初始化操作
我们都知道stm32相关外设的初始化都需要打开相应的时钟,配置相应的IO,除此之外我们还需要对串口库中的相关成员变量赋值,这里我们就直接看一下这些结构体成员有哪些。

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);这个函数就是对串口的初始化操作,形参是一个结构体指针,该结构体主要包含哪些部分,下面会做相应的介绍

typedef struct
{
USART_TypeDef *Instance;
UART_InitTypeDef Init;
uint8_t *pTxBuffPtr;
uint16_t TxXferSize;
uint16_t TxXferCount;
uint8_t *pRxBuffPtr;
uint16_t RxXferSize;
uint16_t RxXferCount;
DMA_HandleTypeDef *hdmatx;
DMA_HandleTypeDef *hdmarx;
HAL_LockTypeDef Lock;
__IO HAL_UART_StateTypeDef State;
__IO uint32_t ErrorCode;
}UART_HandleTypeDef;


使用特权

评论回复
heimaojingzhang|  楼主 | 2021-8-4 11:59 | 显示全部楼层
在该成员中我们只需要对 USART_TypeDef *Instance;  UART_InitTypeDef Init; 这两个成员赋值就行了,首先我先来介绍一下 USART_TypeDef *Instance,这个成员表示的是具体串口号,它是执行寄存器基地址,实际上这个基地址 HAL 库已经定义好了,如果是串口 1,取值为 USART1 即可。

UART_InitTypeDef Init这个变量主要包含如下的成员,它是用来设置串口的各个参数,包括波特率,停止位等

typedef struct
{
uint32_t BaudRate; //波特率
uint32_t WordLength; //字长
uint32_t StopBits; //停止位
uint32_t Parity; //奇偶校验
uint32_t Mode; //收/发模式设置
uint32_t HwFlowCtl; //硬件流设置
uint32_t OverSampling; //过采样设置
}UART_InitTypeDef
pTxBuffPtr,TxXferSize 和 TxXferCount 三个变量分别用来设置串口发送的数据缓存指针,发送的数据量和还剩余的要发送的数据量。而接下来的三个变量 pRxBuffPtr,RxXferSize 和RxXferCount 则是用来设置接收的数据缓存指针,接收的最大数据量以及还剩余的要接收的数据量。这六个变量是 HAL 库处理中间变量。hdmatx 和 hdmarx 是串口 DMA 相关的变量,指向 DMA 句柄
函数 HAL_UART_Init 使用的一般格式为:


UART_HandleTypeDef UART1_Handler; //UART 句柄
UART1_Handler.Instance=USART1; //USART1
UART1_Handler.Init.BaudRate=115200; //波特率
UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; //字长为 8 位格式
UART1_Handler.Init.StopBits=UART_STOPBITS_1; //一个停止位
UART1_Handler.Init.Parity=UART_PARITY_NONE; //无奇偶校验位
UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; //无硬件流控
UART1_Handler.Init.Mode=UART_MODE_TX_RX; //收发模式
HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()会使能 UART1

这里我们需要说明的是,函数 HAL_UART_Init 内部会调用串口使能函数使能相应串口,所以调用了该函数之后我们就不需要重复使能串口了。当然,HAL 库也提供了具体的串口使能和关闭方法,具体使用方法如下:
__HAL_UART_ENABLE(handler); //使能句柄 handler 指定的串口
__HAL_UART_DISABLE(handler); //关闭句柄 handler 指定的串口


使用特权

评论回复
heimaojingzhang|  楼主 | 2021-8-4 12:00 | 显示全部楼层
这里还需要提醒大家,串口作为一个重要外设,在调用的初始化函数 HAL_UART_Init 内部,会先调用 MSP 初始化回调函数进行 MCU 相关的初始化,函数为:void HAL_UART_MspInit(UART_HandleTypeDef *huart);我们在程序中,只需要重写该函数即可。一般情况下,该函数内部用来编写 IO 口初始化,时钟使能以及 NVIC 配置

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    //GPIO端口设置
        GPIO_InitTypeDef GPIO_Initure;
       
        if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化
        {
                __HAL_RCC_GPIOA_CLK_ENABLE();                        //使能GPIOA时钟
                __HAL_RCC_USART1_CLK_ENABLE();                        //使能USART1时钟
       
                GPIO_Initure.Pin=GPIO_PIN_9;                        //PA9
                GPIO_Initure.Mode=GPIO_MODE_AF_PP;                //复用推挽输出
                GPIO_Initure.Pull=GPIO_PULLUP;                        //上拉
                GPIO_Initure.Speed=GPIO_SPEED_FAST;                //高速
                GPIO_Initure.Alternate=GPIO_AF7_USART1;        //复用为USART1
                HAL_GPIO_Init(GPIOA,&GPIO_Initure);                   //初始化PA9

                GPIO_Initure.Pin=GPIO_PIN_10;                        //PA10
                HAL_GPIO_Init(GPIOA,&GPIO_Initure);                   //初始化PA10
               
#if EN_USART1_RX
                HAL_NVIC_EnableIRQ(USART1_IRQn);                //使能USART1中断通道
                HAL_NVIC_SetPriority(USART1_IRQn,3,3);        //抢占优先级3,子优先级3
#endif       
        }

}


使用特权

评论回复
heimaojingzhang|  楼主 | 2021-8-4 12:03 | 显示全部楼层
2:中断相关配置
开启串口相关中断,配置串口中断优先级HAL 库中定义了一个使能串口中断的标识符__HAL_UART_ENABLE_IT,大家可以把它当一个函数来使用,具体定义请参考 HAL 库文件 stm32f4xx_hal_uart.h 中该标识符定义。例如我们要使能接收完成中断,方法如下:
__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE); //开启接收完成中断第一个参数为串口句柄,类型为UART_HandleTypeDef 结构体类型。第二个参数为我们要开启的中断类型值,可选值在头文件 stm32f4xx_hal_uart.h 中有宏定义。

关闭串口中断,操作方法为:
__HAL_UART_DISABLE_IT(huart,UART_IT_RXNE); //关闭接收完成中断对于中断优先级配置,方法就非常简单

对于中断优先级配置,方法就非常简单
HAL_NVIC_EnableIRQ(USART1_IRQn); //使能 USART1 中断通道
HAL_NVIC_SetPriority(USART1_IRQn,3,3); //抢占优先级 3,子优先级 3


使用特权

评论回复
heimaojingzhang|  楼主 | 2021-8-4 12:06 | 显示全部楼层
3:编写中断服务函数
我们在初始化串口之后,开启相应中断,在中断产生的时候我们要有相应的中断处理函数来相应此次的中断

//串口1中断服务程序
void USART1_IRQHandler(void)                       
{
        u32 timeout=0;
        u32 maxDelay=0x1FFFF;
       
        HAL_UART_IRQHandler(&UART1_Handler);        //调用HAL库中断处理公用函数
       
        timeout=0;
    while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)//等待就绪
        {
         timeout++;超时处理
     if(timeout>maxDelay) break;               
        }

        timeout=0;
        while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
        {
         timeout++; //超时处理
         if(timeout>maxDelay) break;       
        }

}


HAL_UART_IRQHandler(&UART1_Handler);    该函数会清楚相应的中断标志位,然后调用HAL_UART_GetState等待uart恢复初始状态,处理完之后重新打开接受中断



使用特权

评论回复
heimaojingzhang|  楼主 | 2021-8-4 12:10 | 显示全部楼层
4:串口的发送和接收

         STM32F4 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到数据的时候,也是存在该寄存器内。HAL 库操作 USART_DR 寄存器发送数据的函数是:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
通过该函数向串口寄存器 USART_DR 写入一个数据。
HAL 库操作 USART_DR 寄存器读取串口接收到的数据的函数是:
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
通过该函数可以读取串口接受到的数据。


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

74

主题

3832

帖子

4

粉丝