stm32 UART (hal库+空闲中断实现)
使用HAL库,uart的配置与使用只需要考虑初始化和中断的编写,以及一些函数的封装就好了。
1. UART的初始化
初始化结构体UART_HandleTypeDef(如下),用来存放一些HAL库与uart相关的变量,重点是对.Init的初始化
UART_HandleTypeDef uart_handle[] =
{
//index:0 USART1
{
.Instance = USART1,
.Init =
{
.BaudRate = 115200,
.WordLength = UART_WORDLENGTH_8B,
.StopBits = UART_STOPBITS_1,
.Parity = UART_PARITY_NONE,
.Mode = UART_MODE_TX_RX,
.HwFlowCtl = UART_HWCONTROL_NONE,
.OverSampling = UART_OVERSAMPLING_8,
},
.pTxBuffPtr = NULL,
.TxXferSize = 0,
.TxXferCount = 0,
.pRxBuffPtr = NULL,
.RxXferSize = 0,
.RxXferCount = 0,
.hdmatx = NULL,
.hdmarx = NULL,
.Lock = HAL_UNLOCKED,
.gState = HAL_UART_STATE_RESET,
.RxState = HAL_UART_STATE_RESET,
.ErrorCode = 0,
}
};
BaudRate设置波特率,如果是经典值,HAL库会帮忙自动设置寄存器配置达到相应的波特率
WordLength设置字长,一般使用奇偶校验位的话就使用9bit,不使用的话就使用8bit
StopBits设置停止位,有 0.5 个、 1 个、 1.5 个和 2 个停止位,一般使用1个停止位
Parity设置是否使用奇偶校验位
Mode设置双工还是只接收或者发送
HwFlowCtl是否使用硬件流控制(还没用到过,用到了再补充)
OverSampling设置uart的采样率,使用8倍采样率,uart的发送速率最高可达fPCLK/8,而使用16倍采样率,uart的发送速率会减半,但是会更精确
2.使用中断来发送

使用HAL库的中断发送HAL_UART_Transmit_IT,只需要将下面函数放入对应的中断服务函数里就成
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(uart_config.config_head[UART1_INDEX].handle);
}
在这里说明一下两个中断标志位的区别(之前混在一起了)
TXE标志位表示移位寄存器器为空,TC表示发送完成,之前混淆了这两个概念,移位寄存器为空并不等于发送完成了,看手册里的这张图我们就能明了两者之间的关系

3.使用空闲中断来接收数据

定义一个fifo来存放收到的数据(这里的发送fifo先定义着,还没用到)
/*uart fifo 结构体*/
typedef struct
{
uint8_t *rxBuf;/*接收缓冲指针*/
uint8_t *txBuf;/*发送缓冲指针*/
uint16_t unTxBufSize; /* 发送缓冲区大小 */
uint16_t unRxBufSize; /* 接收缓冲区大小 */
uint8_t unTxWrite; /* 发送 FIFO 写索引 */
uint8_t unTxRead; /* 发送 FIFO 读索引 */
uint8_t unRxWrite; /* 接收 FIFO 写索引 */
uint8_t unRxRead; /* 接收 FIFO 读索引 */
uint16_t unRxCount;/* 接收 FIFO 使用计数 */
}uart_fifo_type;
封装一个接收开始的函数:该函数中使用HAL库帮我们使能了接收中断,以及一些错误中断。我们在后面补上使能一个空闲中断
void Usart_Receive_start(uint8_t index)
{
HAL_UART_Receive_IT(uart_config.config_head[index-1].handle, un_rxbuf_temp, 1);
__HAL_UART_ENABLE_IT(uart_config.config_head[0].handle,UART_IT_IDLE);
}
定义回调函数,每接收完成一个字节,就将该字节推入fifo
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/*进入这个回调函数表示1个字节接收完成了*/
uart_fifo_type *lcFifo_handle = uart_config.config_head[UART1_INDEX].FifoBuf;//fifo使用的句柄
UART_HandleTypeDef *lcHal_uart_handle = uart_config.config_head[UART1_INDEX].handle;//HAL库uart句柄
/*将该字节推入fifo*/
lcHal_uart_handle->pRxBuffPtr--;
lcFifo_handle->rxBuf[lcFifo_handle->unRxWrite] = *(lcHal_uart_handle->pRxBuffPtr);
/* 接收 FIFO 的写指针+1 */
if ((lcFifo_handle->unRxWrite+1) >= lcFifo_handle->unRxBufSize)
{
lcFifo_handle->unRxWrite = 0;
}
else
{
lcFifo_handle->unRxWrite++;
}
/* 统计未处理的字节个数 */
if (lcFifo_handle->unRxCount < lcFifo_handle->unRxBufSize)
{
lcFifo_handle->unRxCount++;
}
/*开启下一个字节的接收*/
HAL_UART_Receive_IT(huart, un_rxbuf_temp, 1);
}
在中断服务函数中加上如下代码:空闲中断产生的时候,设置标志位,让应用程序来取
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(uart_config.config_head[UART1_INDEX].handle);
//空闲中断标志位
if(__HAL_UART_GET_FLAG(uart_config.config_head[UART1_INDEX].handle, UART_FLAG_IDLE) != RESET)
{
/*清除中断标志位*/
__HAL_UART_CLEAR_IDLEFLAG(uart_config.config_head[UART1_INDEX].handle);
/*设置接收结束标志位*/
uart_config.config_head[UART1_INDEX].RecFinish = 1;
}
}
提供给应用程序从fifo中取数据的接口
uint8_t Usart_get_data(uint8_t index,uint8_t *pData,uint16_t *length)
{
uart_fifo_type *lcFifo_handle = uart_config.config_head[index-1].FifoBuf;//fifo使用的句柄
uart_config_ex_type *lcUart_handle = &uart_config.config_head[index-1];
if(1u == lcUart_handle->RecFinish)
{
HAL_NVIC_DisableIRQ(lcUart_handle->IRQ_num);
lcUart_handle->RecFinish = 0u;
*length = lcFifo_handle->unRxWrite - lcFifo_handle->unRxRead;
while(lcFifo_handle->unRxRead < lcFifo_handle->unRxWrite)
{
*pData = lcFifo_handle->rxBuf[lcFifo_handle->unRxRead];
lcFifo_handle->unRxRead++;
pData++;
}
lcFifo_handle->unRxRead = 0;
lcFifo_handle->unRxWrite = 0;
HAL_NVIC_EnableIRQ(lcUart_handle->IRQ_num);
return 0;
}
else
{
return 2;
}
}

浙公网安备 33010602011771号