串口设置一般包括以下步骤:
- 串口时钟使能,GPIO 时钟使能。
- GPIO 初始化设置:要设置模式为复用功能。
- 串口参数初始化:设置波特率,字长,奇偶校验等参数。
- 开启中断并且初始化 NVIC,使能中断(如果需要开启中断才需要这个步骤)。
- 使能串口。
- 编写中断处理函数:函数名格式为 USARTxIRQHandler(x 对应串口号)。
1、串口时钟使能和GPIO时钟使能
串口初始化函数:
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
/*入口参数huart:串口句柄,为HAL_StatusTypeDef结构体指针类型,如下:*/
typedef struct __UART_HandleTypeDef
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
__IO HAL_UART_RxTypeTypeDef ReceptionType; /*!< Type of ongoing reception */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
and also related to Tx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */
void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */
void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */
void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */
void (* RxEventCallback)(struct __UART_HandleTypeDef *huart, uint16_t Pos); /*!< UART Reception Event Callback */
void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
以上结构体成员变量非常多,一般在使用HAL_UART_Init对串口进行初始化时,只需先对Instance 和 Init 两个成员变量赋值:
Instance 是 USART_TypeDef 结构体指针类型变量,它是执行寄存器基地址,实际上这个基 地址 HAL 库已经定义好了,如果是串口 1,取值为 USART1 即可。 Init 是 UART_InitTypeDef 结构体类型变量,用来设置串口的各个参数,包括波特率, 停止位等,它的使用方法非常简单。UART_InitTypeDef 结构体定义如下:
typedef struct
{
uint32_t BaudRate; /*!< This member configures the UART communication baud rate.
The baud rate is computed using the following formula:
- IntegerDivider = ((PCLKx) / (8 * (OVR8+1) * (huart->Init.BaudRate)))
- FractionalDivider = ((IntegerDivider - ((uint32_t) IntegerDivider)) * 8 * (OVR8+1)) + 0.5
Where OVR8 is the "oversampling by 8 mode" configuration bit in the CR1 register. */
uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.
This parameter can be a value of @ref UART_Word_Length */
uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.
This parameter can be a value of @ref UART_Stop_Bits */
uint32_t Parity; /*!< Specifies the parity mode.
This parameter can be a value of @ref UART_Parity
@note When parity is enabled, the computed parity is inserted
at the MSB position of the transmitted data (9th bit when
the word length is set to 9 data bits; 8th bit when the
word length is set to 8 data bits). */
uint32_t Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled.
This parameter can be a value of @ref UART_Mode */
uint32_t HwFlowCtl; /*!< Specifies whether the hardware flow control mode is enabled or disabled.
This parameter can be a value of @ref UART_Hardware_Flow_Control */
uint32_t OverSampling; /*!< Specifies whether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8).
This parameter can be a value of @ref UART_Over_Sampling */
} UART_InitTypeDef;
在初始化函数HAL_UART_Init中会调用相应的串口使能函数__HAL_UART_ENABLE(huart);同时,在调用的初始化函数 HAL_UART_Init 内 部,会先调用 MSP 初始化回调函数进行 MCU 相关的初始化,函数为:
HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
重写该函数,使能时钟、配置IO以及中断配置
2、GPIO 初始化设置:要设置模式为复用功能
在HAL_UART_MspInit中配置:
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
3、 开启中断
使能串口中断的函数:(已接收完成中断为例)
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
输入的第一个参数是串口句柄,第二个参数是串口中断类型。
关闭中断:
/* Disable the UART Data Register not empty Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
4、编写中断服务函数
当发生中断时,在串口中断服务函数中编写相应的逻辑代码即可
void USART1_IRQHandler(void)
串口接收中断的一般逻辑为:(此图由《STM32F4开发指南》截得)
HAL库一共提供了5个中断处理回调函数:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);//发送完成回调函数
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);//发送完成过半回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//接收完成回调函数
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//接收完成过半回调函数
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);//错误处理回调函数
当然,以上是基于我们使用HAL_UART_Receive_IT 函数,开启接收中断,并且初始化串口句柄的缓存相关参数。
从而使用中断处理回调函数:当接收到一个字符之后,UART_Receive_IT中会把数据保存在串口句柄的成员变量pRxBuffPtr缓存中,同时RxXferCount 计数器减 1。如果我们设置 RxXferSize=10,那么当接收到 10 个字符之后,RxXferCount 会由 10 减到 0(RxXferCount 初始值等于 RxXferSize),这个时候再调用接收完成回调函数 HAL_UART_RxCpltCallback 进行处理。
如果不使用中断处理回调函数,就不需要用初始化串口句柄的中断接收缓存,而是直接在要开启中断的 地方通过调用__HAL_UART_ENABLE_IT 单独开启中断即可,只不过这里还需要通过 HAL 库串口接收函数 HAL_UART_Receive 来获取接收到的字符进行相应的处理。
更多串口详细内容,请见:【STM32学习笔记】串口总结:轮询模式、中断模式、DMA模式以及串口接收不定长数据