概述
目录
- 前言
- 1、UART_Receive_IT
- 2、HAL_UART_Receive
- 3、 HAL_UART_Receive_IT
前言
看了很长时间串口中断的HAL库,最容易混淆的就是函数的名称,主要集中在
UART_Receive_IT
、HAL_UART_Receive
、HAL_UART_Receive_IT
。有点傻傻分不清楚,接下来分析一下他们各自的含义。
1、UART_Receive_IT
函数代码如下:
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
uint16_t *tmp;
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
if (huart->Init.WordLength == UART_WORDLENGTH_9B)//判断CR寄存器的第12位W是否为1 ,为1则代表设置为一个起始位, 9个数据位, n个停止位
{
tmp = (uint16_t *) huart->pRxBuffPtr;//将pRxBuffPtr这个缓冲区的首地址先转化为16位的整型再赋值给tmp
if (huart->Init.Parity == UART_PARITY_NONE)//奇偶校验位
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
huart->pRxBuffPtr += 2U;
}
else
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
huart->pRxBuffPtr += 1U;
}
}
else
{
if (huart->Init.Parity == UART_PARITY_NONE)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);//将数据寄存器DR的值载入到huart的缓冲区指针所指向的位置
}
else
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
}
if (--huart->RxXferCount == 0U)
{
/* Disable the UART Data Register not empty Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
/* Disable the UART Parity Error Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);//接收数据完成,关闭中断并开始回调函数
/* Rx process is completed, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx complete callback*/
huart->RxCpltCallback(huart);
#else
/*Call legacy weak Rx complete callback*/
HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
return HAL_OK;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
前半部分其实我觉得tmp
这个变量存在与否没有什么关键含义,因为if-else
的两种情况都是将USART
的DR
寄存器的值存放到pRxBuffPtr
这个缓存区,只不过这个pRxBuffPtr
是一个指向缓存区首地址的指针。这个函数是把所有输入的数据一个一个存放到缓存区中,也就是,一个数据对应一次中断
,直到确认所有的数据都存放到缓存区中,huart->RxXferCount
对应的值也会自减为0,此时会执行3个__HAL_UART_DISABLE_IT
函数来关闭中断(我也不知道为什么HAL库要这样设置),之后会进入回调函数,我们只需在回调函数中写入我们的用户代码即可。但是其中一定要包含打开中断的函数
,因为__HAL_UART_DISABLE_IT
这个函数已经关闭中断。可以仔细品读这个函数,详细的注释我已经写在了代码块里面,有了注释应该就不难理解。
2、HAL_UART_Receive
这个代码如下
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 == 0U))
{
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;
/* 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);
}
}
}
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
这个函数和UART_Receive_IT
这个函数内容大同小异,只是少了回调函数而已,可以参考上面的函数。
3、 HAL_UART_Receive_IT
代码如下
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
记住!这个函数不是用来接收数据的!这个函数不是用来接收数据的!这个函数不是用来接收数据的!他是用来打开中断,配置串口中断的!不是真正的接收数据的中断函数,很容易把它和其他两个函数混淆。看了上面两个函数的解释,这个函数的内容应该不难理解,这也就是,我们要手动打开串口中断,就要在main
函数里面首先写下它,否则无法进入串口中断(亲测如此),其次还要在回调函数里面添加这个函数(因为之前就说过一旦进入回调函数,串口中断就会关闭),为了下一次接收数据考虑,需要这么做。
PS:很多人一直觉得用户代码可以在中断函数里面写,但是我们一般不写在中断函数中,而是在回调函数里面写。如果写在中断函数中,和标准库没什么两样。而HAL库将函数都已封装完整,回调函数完好地提供一个API接口,供用户使用。回调函数和普通函数还是有一定区别的,读者可以查阅其他资料,在此不再赘述。
想要更加细致地了解这三个函数,推荐一下这篇文章:关于HAL库串口中断接收哪些路子 第二弹
希望看完本文能对串口接收函数有了更加深入的理解,每一个函数的内容都值得推敲一下
最后
以上就是甜蜜小天鹅为你收集整理的HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数前言1、UART_Receive_IT2、HAL_UART_Receive3、 HAL_UART_Receive_IT的全部内容,希望文章能够帮你解决HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数前言1、UART_Receive_IT2、HAL_UART_Receive3、 HAL_UART_Receive_IT所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复