串口数据收发(轮询)初始化步骤:
第一步:调用HAL_UART_Init函数初始化串口参数,函数如下:
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);
函数传入结构参数如下:
typedef struct
{
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传输时,传入发送引脚TX的DMA初始化配置参数
DMA_HandleTypeDef *hdmarx; // 当串口使用DMA传输时,传入接收引脚RX的DMA初始化配置参数
HAL_LockTypeDef Lock; // 锁定对象
__IO HAL_UART_StateTypeDef gState; // 当前串口Tx引脚状态信息
__IO HAL_UART_StateTypeDef RxState; // 当前串口Rx引脚状态信息
__IO uint32_t ErrorCode; // 串口错误代码
}UART_HandleTypeDef;
第二步、重定义HAL_UART_MspInit函数初始化,初始化串口硬件参数。当调用HAL_UART_Init串口初始化函数时,该函数内部会调用HAL_UART_MspInit函数,用来初始化串口使用到的引脚。这实际是HAL库的一个优点,它通过开放一个回调函数HAL_UART_MspInit,让用户自己去编写与串口有关的硬件初始化,而与串口相关的参数配置则放在HAL_UART_Init函数中,这样当我们移植程序到别的STM32平台时,使用串口只需要修改HAL_UART_MspInit函数中配置即可。
第三步、调用串口接收数据库函数HAL_UART_Receive(),实现功能如下:
①.函数传入4个参数,分别为串口初始化结构体参数UART_HandleTypeDef、接收数据缓冲区地址pData、接收数据缓冲区宽度Size、和接收数据最大等待时间。
②. 函数中首先初始化结构体UART_HandleTypeDef里面错误代码变量“ErrorCode”,接收数据缓冲区大小“RxXferSize”等变量。
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint16_t* tmp;
uint32_t tickstart = 0U;
/* Check that a Rx process is not already ongoing */
if(huart->RxState == HAL_UART_STATE_READY)
{
if((pData == NULL ) || (Size == 0))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Init tickstart for timeout managment */
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
③.接下来根据初始化的接收数据个数变量进行while循环,循环中接收个数递减。
④.接下来根据串口初始化的接收数据个数、有无奇偶校验等参数来初始化临时存储数据变量pData。
⑤.在while循环中,调用UART_WaitOnFlagUntilTimeout函数,根据接收数据寄存器非空标志位(UART_FLAG_RXNE:当RDR移位寄存器的内容转移到USART_DR寄存器时,硬件将设置此位)状态位依次接收每个字节数据,并判断等待每个字节是否超出溢出时间,如果未超过定义的等待时间,则将数据存储到pData变量中,否则返回错误状态HAL_TIMEOUT。
/* Check the remain data to be received */
while(huart->RxXferCount > 0U)
{
huart->RxXferCount--;
if(huart->Init.WordLength == UART_WORDLENGTH_9B)
{
if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
tmp = (uint16_t*) pData;
if(huart->Init.Parity == UART_PARITY_NONE)
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
pData +=2U;
}
else
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
pData +=1U;
}
}
else
{
if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if(huart->Init.Parity == UART_PARITY_NONE)
{
*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
}
}
3、调用串口发送数据库函数HAL_UART_Transmit(),函数实现与HAL_UART_Receive类似,请参考上面函数。
串口数据收发bsp_uart.c完整程序如下:
#include "bsp_uart.h"
UART_HandleTypeDef UART1_Handler; //UART 句柄
// 初始化串口函数
void UART_Init(void)
{
UART1_Handler.Instance = USART1; // 串口1
UART1_Handler.Init.BaudRate = 115200; // 波特率
UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无硬件流控
UART1_Handler.Init.Mode = UART_MODE_TX_RX; // 收发模式
UART1_Handler.Init.Parity = UART_PARITY_NONE; // 无奇偶校验
UART1_Handler.Init.StopBits = UART_STOPBITS_1; // 一个停止位
UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B; // 字长为8位格式
HAL_UART_Init(&UART1_Handler); // 初始化串口
}
// 初始化低级硬件
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIO引脚
__HAL_RCC_USART1_CLK_ENABLE(); // 使能串口
GPIO_Initure.Mode = GPIO_MODE_AF_PP; // 复用推挽模式
GPIO_Initure.Pin = GPIO_PIN_9|GPIO_PIN_10; // PA9、PA10
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、PA10
}
}
void UART_Transmit(uint8_t *pData, uint16_t Size)
{
HAL_UART_Transmit(&UART1_Handler, pData, Size, HAL_MAX_DELAY);
}
void UART_Receive(uint8_t *pData, uint16_t Size)
{
HAL_UART_Receive(&UART1_Handler, pData, Size, HAL_MAX_DELAY);
}
主函数程序如下:
uint8_t buffer[10];
int main(void)
{
CLOCLK_Init(); // 配置系统时钟为168M
UART_Init();
while(1)
{
UART_Receive(buffer, 5);
UART_Transmit(buffer, 5);
}
}