串口简介
USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收发送器
即串口。是一个高度灵活的收发模块,它可以做到与上位机,或者其他MCU进行通信,实现上位机,其他MCU间的相互控制
STM32单片机芯片内部集成了多个串口。
一般而言,我们使用串口都使用异步收发模式。同步收发模式在外设和代码上的处理较为复杂,而且对时钟的要求严格,MCU的频率较PC频率低得多,所以没很大的必要使用同步模式。而同步通信的目的就是为了加快通信速率,但在使用上有些不尽如人意。以我用过的串口模块(外设)来说,基本上都是异步收发的串口模块(外设)。如ESP8266,其他一些蓝牙模块。
以STM32F4为例,该芯片集成了4个同步异步串口(USART1,USART2,USART3,USART6),2个异步串口(UART4,UART5),同步异步串口可以初始化为同步模式,也可以初始化为异步模式,而异步串口仅能初始化为异步模式。
若要将同步异步串口初始化为同步模式,则调用同步模式的串口初始化函数,否则调用异步模式串口初始化函数来初始化串口。
串口初始化具体步骤
这里我们先介绍初始化串口要用到的函数
相关HAL库函数 | 具体功能 |
---|---|
HAL_UART_Init | 顾名思义,异步串口初始化函数,初始化串口时我们调用的函数。所在源文件:stm32f4xx_hal_uart.c |
HAL_UART_DeInit | 取消对某异步串口的初始化 |
HAL_UART_MspInit | 串口MSP初始化 |
HAL_UART_MspDeInit | 取消MSP初始化 |
这是MSP初始化函数的声明,可以发现,在void关键字之前有一个weak关键字
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
这个关键字告诉编译器,这个定义是弱定义,若在编译时,有一处函数定义不含此关键字,则所有该函数的调用都指向那一个非weak型的函数定义。这个操作叫函数重定向。因为在系统头文件里,MSP层是没有声明的,MSP层是具体对应每一个MCU的物理状态,系统文件不会声明也不能声明,但在单片机做上电初始化时,有一些函数又必须调用,所以系统文件采取了这种用户可以重定向的写法。我们在初始化串口时,需要自己写一个MSPInit,而且不含weak。函数声明如下:
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
我们要初始化串口,就要定义一个属于自己的MSP函数,并且系统会自动的把所有的MSP调用都指向我们定义的这个MSP函数
以下为系统定义的MSP函数,可见,内部几乎没什么内容,唯一一个函数调用是使该串口变为UNUSED(不使用)
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_MspInit could be implemented in the user file
*/
}
取消MSP使能函数的声明如下,可见在内部代码中的该函数也为弱定义,内部代码也十分简单,此处不做赘述
__weak void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
具体初始化过程(以CUBEMX生成的空项目为例):
使用串口第一步。添加串口同步异步源文件到项目中。(stm32f4xx_hal_usart.c,stm32f4xx_hal_uart.c)若只使用异步模式,应该不需要添加同步异步模式的头文件进入项目,但一方面是为了方便,一方面是为了少出一点事情,还是将它加进项目吧)
点击Add Files
返回项目文件夹层级,可见有如上几个文件夹。点击Drivers
点击HAL_Driver,下一栏点src,从中找到stm32f4xx_hal_usart.c和stm32f4xx_hal_uart.c,点击Add加入项目。文件即加入了我们的项目
文件加入我们的项目后,我们仅仅引用了源文件,而头文件的引用,进入main.h中,打开stm32f4xx_hal.h,找到stm32f4xx_hal_conf.h
可以发现头文件的模块使能宏定义被注释掉了,把注释去掉即可。
这样一来所有的准备工作都做好了,我们开始着手初始化串口吧
串口初始化函数
void Usart1Init(int baudRate)
{
UART1_Handle.Instance = USART1; //串口句柄1与串口1对应
UART1_Handle.Init.BaudRate = baudRate; //初始化波特率为输入波特率
UART1_Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件控制流
UART1_Handle.Init.Mode = UART_MODE_TX_RX; //串口异步收发模式
UART1_Handle.Init.OverSampling = UART_OVERSAMPLING_16; //默认过采样16倍
UART1_Handle.Init.Parity = UART_PARITY_NONE; //默认无校验位
UART1_Handle.Init.StopBits = UART_STOPBITS_1; //默认1位停止位
UART1_Handle.Init.WordLength = UART_WORDLENGTH_8B; //8bit数据位
if (HAL_UART_Init(&UART1_Handle) != HAL_OK)
{
Error_Handler();
}
}
其中UART1_Handle为UART_HandleTypeDef类型的结构体
结构体内容如下:
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 */
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)<