文章目录
- 概述
- `UART`初始化
- `UART`参数初始化
- `UART`句柄
- `UART`初始化结构体
- `UART`参数初始化函数
- `UART`时钟初始化
- `UART_GPIO`初始化
- `UART`中断配置
- `Msp`初始化函数
- `UART`无中断收发
- `UART`发送数据
- `UART`发送数据`API`
- `UART`无中断发送示例
- `UART`接收数据
- `UART`接收数据`API`
- `UART`无中断接收数据示例
- `UART`中断收发
- `UART`发送中断
- `UART`发送中断使能
- `UART`发送完成中断回调
- `UART`发送中断示例
- 注意:
- `UART`接收中断
- `UART`接收中断使能
- `UART`接收完成中断回调
- `UART`接收中断示例
- 注意:
概述
本篇将以STM32F407VET6
芯片的USART1
为例,总结STM32CubeIDE
平台关于UART
通信的**主动收发(无中断收发)和被动收发(中断收发)**流程。应当注意,对于USART
的常规应用,应当使用HAL
库中的UART API
.
UART
初始化
UART
的完整初始化流程为:
1.UART参数初始化
(1).UART句柄配置
(2).UART初始化结构体配置
(3).UART使能
2.UART时钟初始化(置于UART_Msp初始化函数)
3.UART_GPIO初始化(置于UART_Msp初始化函数)
(1).GPIO时钟初始化
(2).GPIO参数初始化
4.UART中断配置(置于UART_Msp初始化函数)
(1).NVIC总中断优先级配置
(2).NVIC使能总中断
(3).UART开启分中断(发送中断/接收中断)
UART
参数初始化
UART
句柄
UART
句柄是UART
初始化和具体操作中最重要的参数,应当声明为工程级别的全局变量。HAL
库中采用 发送缓冲区 和 接收缓冲区 一次发送/接受 一个或多个字节 的方式提高数据吞吐效率。
typedef struct __UART_HandleTypeDef {
USART_TypeDef *Instance;
UART_InitTypeDef Init;
uint8_t *pTxBuffPtr;
uint16_t TxXferSize;
__IO uint16_t TxXferCount;
uint8_t *pRxBuffPtr;
uint16_t RxXferSize;
__IO uint16_t RxXferCount;
DMA_HandleTypeDef *hdmatx;
DMA_HandleTypeDef *hdmarx;
HAL_LockTypeDef Lock;
__IO HAL_UART_StateTypeDef gState;
__IO HAL_UART_StateTypeDef RxState;
__IO uint32_t ErrorCode;
} UART_HandleTypeDef;
UART
初始化结构体
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;
UART
参数初始化函数
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);
UART
参数初始化实例:
void MX_USART1_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
UART
时钟初始化
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_USART1_CLK_DISABLE();
__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_UART4_CLK_DISABLE();
UART_GPIO
初始化
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = USART1_TX_Pin|USART1_RX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
UART
中断配置
HAL_NVIC_SetPriority(USART1_IRQn,0,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
Msp
初始化函数
UART
参数初始化函数HAL_UART_Init()
中调用了Msp
初始化函数实现用户自定义初始化配置。UART
的时钟使能、GPIO
初始化、中断配置 都应当在Msp
初始化函数中实现。
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) {
}
UART
无中断收发
UART
发送数据
UART
发送数据API
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout);
UART
无中断发送示例
uint8_t *TxBufferPtr = (uint8_t*)"Successful!\n\r";
#ifndef TIMEOUT
#define TIMEOUT 1000
#endif
while(HAL_UART_Transmit(&huart1,TxBufferPtr,13,TIMEOUT) != HAL_OK);
UART
接收数据
UART
接收数据API
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout);
UART
无中断接收数据示例
uint8_t RxBufferPtr[10] = {0};
#ifndef TIMEOUT
#define TIMEOUT 1000
#endif
while(HAL_UART_Receive(&huart1,RxBufferPtr,10,TIMEOUT) != HAL_OK);
while(HAL_UART_Transmit(&huart1,RxBufferPtr,10,TIMEOUT) != HAL_OK);
UART
中断收发
HAL
库中将UART
中断深度封装,仅提供中断回调函数进行用户中断处理逻辑的实现。中断回调函数均有弱定义(__weak
)声明,用户可在任意源文件(.c
)中重新强定义(无__weak
声明)中断回调函数实现自定义中断处理逻辑。
UART
中断回调流程:
1.中断发生
2.进入中断服务函数 UARTx_IRQHandler()
3.中断服务函数调用 通用入口函数 HAL_UART_IRQHandler(),
通用入口函数中进行中断源的判断、中断标志的清除等操作
4.通用入口函数依据事件判断调用 中断回调函数 HAL_UART_XxxCallback()
UART
发送中断
UART
发送中断使能
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size);
UART
发送完成中断回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
}
UART
发送中断示例
uint8_t *TxBufferPtr = (uint8_t*)"Successful!\n\r";
int main(void) {
while(HAL_UART_Transmit_IT(&huart1,TxBufferPtr,13) != HAL_OK);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART1) {
LED_ON();
}
}
注意:
UART
发送中断回调的机制是:每发送一个字节之后均会进入中断服务函数,通过UART
句柄中的TxXferCount
判断UART
发送数据的进度,如果发送达到指定字节数(Size
),则调用HAL_UART_TxCpltCallback()
.
HAL_UART_Transmit_IT()
只能开启1
次发送中断,调用发送中断回调函数之后便 失能 发送中断。在合适的时机再次调用HAL_UART_Transmit_IT()
可以再次开启发送中断。
HAL_UART_Transmit_IT()
不可在UART
的Msp
初始化函数中调用。Msp
初始化函数并非在UART
参数初始化函数HAL_UART_Init()
的末尾调用,在Msp
初始化函数调用之后还会进行UART
状态的初始化操作。如果在Msp
初始化函数中调用HAL_UART_Transmit_IT()
将导致错误判断UART
发送状态,HAL_UART_Transmit_IT()
将错误返回HAL_BUSY
.
正确的做法是:在UART
参数初始化函数HAL_UART_Init()
调用后调用HAL_UART_Transmit_IT()
.
UART
接收中断
UART
接收中断使能
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size);
UART
接收完成中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
}
UART
接收中断示例
uint8_t RxBufferPtr[10] = {0};
int main(void) {
while(HAL_UART_Receive_IT(&huart1,RxBufferPtr,10) != HAL_OK);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART1) {
#ifndef TIMEOUT
#define TIMEOUT 1000
#endif
while(HAL_UART_Transmit(&huart1,RxBufferPtr,10,TIMEOUT) != HAL_OK);
while(HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,TIMEOUT) != HAL_OK);
while(HAL_UART_Receive_IT(&huart1,RxBufferPtr,10) != HAL_OK);
}
}
注意:
UART
接收中断回调的机制是:每接收一个字节之后均会进入中断服务函数,通过UART
句柄中的RxXferCount
判断UART
接收数据的进度,如果接收达到指定字节数(Size
),则调用HAL_UART_RxCpltCallback()
.
HAL_UART_Receive_IT()
只能开启1
次接收中断,调用接收中断回调函数之后便 失能 接收中断。在合适的时机再次调用HAL_UART_Receive_IT()
可以再次开启接收中断。
HAL_UART_Receive_IT()
不可在UART
的Msp
初始化函数中调用。Msp
初始化函数并非在UART
参数初始化函数HAL_UART_Init()
的末尾调用,在Msp
初始化函数调用之后还会进行UART
状态的初始化操作。如果在Msp
初始化函数中调用HAL_UART_Receive_IT()
将导致错误判断UART
接收状态,HAL_UART_Receive_IT()
将错误返回HAL_BUSY
.
正确的做法是:在UART
参数初始化函数HAL_UART_Init()
调用后调用HAL_UART_Receive_IT()
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)