一、代码自动生成以后的项目及代码结构:
main.c中,调用了串口初始化
串口初始化函数赋值了串口的参数
相当于底层的初始化,配置引脚、并开启中断。
至此串口1配置完毕
二、库文件stm32f1xx_hal_uart.c内的秘密
2.1 初始化
1.usart.c中,MX_USART1_UART_Init 调用了库的HAL_UART_Init,将结构体传递进该函数中
2.HAL_UART_Init干了些什么事?
if (huart->gState == HAL_UART_STATE_RESET)
{
huart->Lock = HAL_UNLOCKED;
HAL_UART_MspInit(huart);
}
huart->gState = HAL_UART_STATE_BUSY;
__HAL_UART_DISABLE(huart); /* Disable the peripheral */
UART_SetConfig(huart);/* Set the UART Communication parameters */
/* In asynchronous mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
__HAL_UART_ENABLE(huart); /* Enable the peripheral */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
调用MspInit-->修改状态忙-->配置寄存器-->清楚标志位
2.2 先理解HAL_UART_Receive函数
uint32_t tickstart = 0U;
if (huart->RxState == HAL_UART_STATE_READY) /* Check that a Rx process is not already ongoing */
{
__HAL_LOCK(huart); /* Process Locked */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
while (huart->RxXferCount > 0U)
{
huart->RxXferCount--;
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
return HAL_TIMEOUT;
*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
}
huart->RxState = HAL_UART_STATE_READY;
__HAL_UNLOCK(huart);
判断是否忙-->锁住-->标记接收忙-->获取tick计数
-->赋值RxXferCount有多少数据要接收-->每次从DR内获取一个Byte存在pData指向的空间
2.3 HAL_UART_Receive_IT只是配置了一下参数,并没有做任何处理
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
__HAL_LOCK(huart); /* Process Locked */
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
__HAL_UNLOCK(huart); /* Process Unlocked */
/*Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
__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;
}
存储在pData指向位置、空间大小RxXferSize 、接收计数RxXferCount ; 接收状态忙;使能接收中断
那么当有数据来的时候,就需要依靠中断函数来处理了。
2.4再看看中断函数在做什么
stm32f1xx_it.c内有定义USART1_IRQHandler,只调用了HAL_UART_IRQHandler函数,下面是
HAL_UART_IRQHandler具体内容
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
/* If some errors occur */
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
//略过错误处理
/* Call UART Error Call back function if need be --------------------------*/
if (huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/* UART in mode Receiver -----------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
UART_Receive_IT(huart);
//略过错误处理
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{ UART_Transmit_IT(huart); return; }
/* UART in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{ UART_EndTransmit_IT(huart); return; }
无非是三件事,判断是由什么中断响应的,有错误则处理,响应要调用的接收或者发送。
注意区别 UART_Receive_IT 和 HAL_UART_Receive_IT。
HAL_UART_Receive_IT是用户调用的需要接收多少数据存在何处。
UART_Receive_IT是中断调用的有数据收到该如何处理。
2.5 UART_Receive_IT 真正在接收数据的函数,但在最后会关闭中断
uint16_t *tmp;
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
if (--huart->RxXferCount == 0U)
{
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);
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;
}
如果是接收状态忙,则从DR中读取1Byte数据。
如果接收计数归零,则使中断失效,并调用回调函数(用户定义则调用用户的,否则调用系统的)
至此,所有用到的代码分析完毕
三、总结
1、HAL_UART_Receive_IT和HAL_UART_Receive的区别就是:中断接收是有数据到了才去读;直接接收是直接读取,如果超时就返回
2、HAL_UART_Receive_IT配置后,有数据来,计数会在调用中断函数之后自动减1。只有到计数为0时,才会关闭中断并调用回调函数。至此有数据来不再调用中断函数,因为中断已经失效。
3、HAL_UART_Receive_IT在计数未至0之前,应该可以读取之前接收到的数据,但这样做应该比较危险。
4、在开源电子的例程中,使用 HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, 1); 即Size设置为1,只接收1Byte数据,在每次中断结束后重新配置来使能中断。
四、还有必要再看一眼uart的结构体定义
/**
* @brief UART handle Structure definition
*/
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); /*!< UART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */
void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */
void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
一、代码自动生成以后的项目及代码结构:
main.c中,调用了串口初始化
串口初始化函数赋值了串口的参数
相当于底层的初始化,配置引脚、并开启中断。
至此串口1配置完毕
二、库文件stm32f1xx_hal_uart.c内的秘密
2.1 初始化
1.usart.c中,MX_USART1_UART_Init 调用了库的HAL_UART_Init,将结构体传递进该函数中
2.HAL_UART_Init干了些什么事?
if (huart->gState == HAL_UART_STATE_RESET)
{
huart->Lock = HAL_UNLOCKED;
HAL_UART_MspInit(huart);
}
huart->gState = HAL_UART_STATE_BUSY;
__HAL_UART_DISABLE(huart); /* Disable the peripheral */
UART_SetConfig(huart);/* Set the UART Communication parameters */
/* In asynchronous mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
__HAL_UART_ENABLE(huart); /* Enable the peripheral */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
调用MspInit-->修改状态忙-->配置寄存器-->清楚标志位
2.2 先理解HAL_UART_Receive函数
uint32_t tickstart = 0U;
if (huart->RxState == HAL_UART_STATE_READY) /* Check that a Rx process is not already ongoing */
{
__HAL_LOCK(huart); /* Process Locked */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
while (huart->RxXferCount > 0U)
{
huart->RxXferCount--;
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
return HAL_TIMEOUT;
*pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
}
huart->RxState = HAL_UART_STATE_READY;
__HAL_UNLOCK(huart);
判断是否忙-->锁住-->标记接收忙-->获取tick计数
-->赋值RxXferCount有多少数据要接收-->每次从DR内获取一个Byte存在pData指向的空间
2.3 HAL_UART_Receive_IT只是配置了一下参数,并没有做任何处理
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
__HAL_LOCK(huart); /* Process Locked */
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
__HAL_UNLOCK(huart); /* Process Unlocked */
/*Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
__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;
}
存储在pData指向位置、空间大小RxXferSize 、接收计数RxXferCount ; 接收状态忙;使能接收中断
那么当有数据来的时候,就需要依靠中断函数来处理了。
2.4再看看中断函数在做什么
stm32f1xx_it.c内有定义USART1_IRQHandler,只调用了HAL_UART_IRQHandler函数,下面是
HAL_UART_IRQHandler具体内容
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
/* If some errors occur */
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
//略过错误处理
/* Call UART Error Call back function if need be --------------------------*/
if (huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/* UART in mode Receiver -----------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
UART_Receive_IT(huart);
//略过错误处理
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{ UART_Transmit_IT(huart); return; }
/* UART in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{ UART_EndTransmit_IT(huart); return; }
无非是三件事,判断是由什么中断响应的,有错误则处理,响应要调用的接收或者发送。
注意区别 UART_Receive_IT 和 HAL_UART_Receive_IT。
HAL_UART_Receive_IT是用户调用的需要接收多少数据存在何处。
UART_Receive_IT是中断调用的有数据收到该如何处理。
2.5 UART_Receive_IT 真正在接收数据的函数,但在最后会关闭中断
uint16_t *tmp;
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
if (--huart->RxXferCount == 0U)
{
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);
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;
}
如果是接收状态忙,则从DR中读取1Byte数据。
如果接收计数归零,则使中断失效,并调用回调函数(用户定义则调用用户的,否则调用系统的)
至此,所有用到的代码分析完毕
三、总结
1、HAL_UART_Receive_IT和HAL_UART_Receive的区别就是:中断接收是有数据到了才去读;直接接收是直接读取,如果超时就返回
2、HAL_UART_Receive_IT配置后,有数据来,计数会在调用中断函数之后自动减1。只有到计数为0时,才会关闭中断并调用回调函数。至此有数据来不再调用中断函数,因为中断已经失效。
3、HAL_UART_Receive_IT在计数未至0之前,应该可以读取之前接收到的数据,但这样做应该比较危险。
4、在开源电子的例程中,使用 HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, 1); 即Size设置为1,只接收1Byte数据,在每次中断结束后重新配置来使能中断。
四、还有必要再看一眼uart的结构体定义
/**
* @brief UART handle Structure definition
*/
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); /*!< UART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */
void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */
void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
举报