一.UART中断概述
如figure 302所示,在stm32中UART有多个中断,下面来逐一说明这些中断及其应用。
一.发送中断
1.1TXE:发送数据寄存器为空状态标志位
当TDR寄存器的内容已转移到移位寄存器中时,此位由硬件置1。 如果USART_CR1寄存器中的TXEIE位= 1,则会产生一个中断。 通过写USART_DR寄存器将其清除。
0:数据未传输到移位寄存器
1:数据传输到移位寄存器)
注:在单缓冲区传输期间使用此位。TXE位总是通过写数据寄存器来清除。TXE位由硬件置1,它指示:
?数据已从TDR移至移位寄存器,并且数据传输已开始。
?TDR寄存器为空。
?可以将下一个数据写入USART_DR寄存器,而不会覆盖前一个数据。
如果TXEIE位置1,此标志将产生中断。
1.2.TC 传输完成状态标志位
传输完成中断,如果包含数据的帧的传输完成并且TXE被置位,则该位置1。 如果USART_CR1寄存器中的TCIE = 1,则产生一个中断。 通过软件序列(从USART_SR寄存器读取,然后写入USART_DR寄存器)将其清除。 TC位也可以通过向其写入“ 0”来清除。 建议仅对多缓冲区通信使用此清除序列。
0:传输未完成。
1:传输完成。
1.3.CTS
<待整理>
1.4.中断发送
通过STM32CubeIDE创建工程后,设置好UART及其它相关的配置后,在UART的中断发送过程中,HAL库的相互调用关系如下:HAL_UART_Transmit_IT ---》 HAL_UART_IRQHandler ---》 UART_Transmit_IT ---》 UART_EndTransmit_IT。
HAL_UART_Transmit_IT :
此函数会将要发送的数据赋值给UART结构体。然后使能UART_IT_TXE中断,进入中断处理函数。
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/*
*此函数会将要发送的数据赋值给UART结构体。然后使能UART_IT_TXE中断,进入中断处理函数;从发送时序图Fig 282可以看到
*在使能UART_IT_TXE中断后会马上触发一次UART_IT_TXE中断中断。TXE flag在初始状态就是保持在高电平。
*
**//* Check that a Tx process is not already ongoing */if (huart->gState == HAL_UART_STATE_READY){if ((pData == NULL) || (Size == 0U)){return HAL_ERROR;}/* Process Locked */__HAL_LOCK(huart);huart->pTxBuffPtr = pData;huart->TxXferSize = Size;huart->TxXferCount = Size;huart->ErrorCode = HAL_UART_ERROR_NONE;huart->gState = HAL_UART_STATE_BUSY_TX;/* Process Unlocked */__HAL_UNLOCK(huart);/* Enable the UART Transmit data register empty Interrupt */__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);return HAL_OK;}else{return HAL_BUSY;}
}
HAL_UART_IRQHandler :
进入UART中断入口函数后,会调用中断处理函数HAL_UART_IRQHandler,在中断处理函数HAL_UART_IRQHandler中会根据中断标志位(TC TXE)不同调用不同的函数UART_Transmit_IT 和UART_EndTransmit_IT。其中UART_Transmit_IT在huart->gState == HAL_UART_STATE_BUSY_TX控制下循环将要发送的数据一帧一帧的写入串口的发送数据寄存器,并关闭TXE中断,使能TC中断。UART_EndTransmit_IT会关闭TC中断并调用用户自己的中断处理函数HAL_UART_TxCpltCallback。
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{uint32_t isrflags = READ_REG(huart->Instance->SR);uint32_t cr1its = READ_REG(huart->Instance->CR1);uint32_t cr3its = READ_REG(huart->Instance->CR3);uint32_t errorflags = 0x00U;uint32_t dmarequest = 0x00U;/* If no error occurs */errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));if (errorflags == RESET){/* UART in mode Receiver -------------------------------------------------*/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))){//error flag//此处代码暂时不关注已删除} /* End if some error occurs *//* UART in mode Transmitter ------------------------------------------------*/if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET)){//中断发送,每次发生TXE中断,就调用一次UART_Transmit_IT。UART_Transmit_IT(huart);return;}/* UART in mode Transmitter end --------------------------------------------*/if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET)){//如果是发送TC中断,则调用UART_EndTransmit_IT。UART_EndTransmit_IT(huart);return;}
UART_Transmit_IT :
huart->gState == HAL_UART_STATE_BUSY_TX软件定义的传输完成标志变量,如果特定的帧数据发送完成,会触发TC中断再次调用HAL_UART_IRQHandler,并在HAL_UART_IRQHandler中调用TC中断处理函数UART_EndTransmit_IT中复位HAL_UART_STATE_BUSY_TX。
static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{uint16_t *tmp;/* Check that a Tx process is ongoing */if (huart->gState == HAL_UART_STATE_BUSY_TX){if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)){//如果数据位是9位,则需要发送一个16位数tmp = (uint16_t *) huart->pTxBuffPtr;huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);huart->pTxBuffPtr += 2U;}else{//如果数据位是8位,则只需要发送一个8位数huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);}if (--huart->TxXferCount == 0U){/* Disable the UART Transmit Complete Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_TXE);/* Enable the UART Transmit Complete Interrupt */__HAL_UART_ENABLE_IT(huart, UART_IT_TC);}return HAL_OK;}else{return HAL_BUSY;}
}
UART_EndTransmit_IT :
执行到这里标志串口发送完成,在UART_EndTransmit_IT中关闭TC中断,复位HAL_UART_STATE_BUSY_TX,然后调用发送完成的用户中断处理程序HAL_UART_TxCpltCallback。
static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)
{/* Disable the UART Transmit Complete Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_TC);/* Tx process is ended, restore huart->gState to Ready */huart->gState = HAL_UART_STATE_READY;#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered Tx complete callback*/huart->TxCpltCallback(huart);
#else/*Call legacy weak Tx complete callback*/HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */return HAL_OK;
}
二.接收中断
https://blog.csdn.net/Hola_ya/article/details/81560204?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=5e1deb95-ae63-46d4-8bf3-744ae8dc909d&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
https://blog.csdn.net/qq_29413829/article/details/63262321?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase
2.1 IDLE:IDLE line detected
当检测到空闲线时,该位置1。 如果USART_CR1寄存器中的IDLEIE = 1,则产生一个中断。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:未检测到空闲线
1:检测到空闲线
注意:在RXNE位本身被置位之前(即出现新的空闲线),IDLE位将不会再次置位。
2.2 ORE:Overrun error(溢出错误)
当RXNE = 1时,当移位寄存器中当前接收的字准备好被传送到RDR寄存器中时,该位由硬件置1。 如果USART_CR1寄存器中的RXNEIE = 1,则产生一个中断。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:无溢出错误
1:检测到超限错误
注:置位时,RDR寄存器的内容不会丢失,但移位寄存器将被覆盖。 如果EIE位置1,则在进行多缓冲区通信时,在ORE标志上会产生一个中断。
2.3 RXNE : Read data register not empty
当RDR移位寄存器的内容已传输到USART_DR寄存器时,此位由硬件置1。 如果USART_CR1寄存器中的RXNEIE = 1,则产生一个中断。通过读取USART_DR寄存器将其清除。 也可以通过向其写入零来清除RXNE标志。 建议仅对多缓冲区通信使用此清除序列。
0:未收到数据
1:已准备好读取已接收的数据。
2.4 PE :Parity error
当在接收器模式下发生奇偶校验错误时,此位由硬件设置。 它由软件序列清除(先读取状态寄存器,然后读取USART_DR数据寄存器)。 在清除PE位之前,软件必须等待RXNE标志置1。
如果USART_CR1寄存器中的PEIE = 1,则会产生一个中断。
0:无奇偶校验错误
1:奇偶校验错误
2.5 LBD : LIN break detection flag
当检测到LIN中断时,由硬件将该位置1。 通过软件清除(将其写入0)。 如果USART_CR2寄存器中的LBDIE = 1,则会产生一个中断。
0:未检测到LIN Break
1:检测到LIN中断
注意:如果LBDIE = 1,则当LBD = 1时会产生一个中断。
2.6 NE/ORE/FE :
NE: Noise error flag
当在接收到的帧上检测到噪声时,该位由硬件设置。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:未检测到噪音
1:检测到噪音
注意:如果EIE位置1,则在多缓冲区通信的情况下,NE标志上会生成与本身产生中断中断的RXNE位同时出现的该位,不会产生中断。
ORE: Overrun error
当RXNE = 1时,当移位寄存器中当前接收的字准备好被传送到RDR寄存器中时,该位由硬件置1。 如果USART_CR1寄存器中的RXNEIE = 1,则产生一个中断。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:无溢出错误
1:检测到超限错误
注:置位时,RDR寄存器的内容不会丢失,但移位寄存器将被覆盖。 如果EIE位置1,则在进行多缓冲区通信时,在ORE标志上会产生一个中断。
FE: Framing error
当检测到去同步,过多的噪声或中断字符时,该位将由硬件置位。 它由软件序列清除(先读取USART_SR寄存器,再读取USART_DR寄存器)。
0:未检测到构图错误
1:检测到帧错误或中断字符
注:该位不会产生中断,因为它与本身会产生中断的RXNE位同时出现。 如果当前正在传输的字同时引起帧错误和溢出错误,则将传输该字,并且仅将ORE位置1。 如果EIE位置1,则在多缓冲区通信的情况下,FE标志上会产生一个中断。
EIE: Error interrupt enable
如果发生多缓冲器通信(DMAR = 1时),则在发生帧错误,溢出错误或噪声错误(USART_SR寄存器中的FE = 1或ORE = 1或NE = 1)时,需要错误中断允许位来使能中断生成。 USART_CR3寄存器)。
0:禁止中断
1:每当USART_CR3寄存器中的DMAR = 1和USART_SR寄存器中的FE = 1或ORE = 1或NE = 1时,都会产生一个中断。
DMAR :DMA enable receiver
该位由软件置位/复位
1:启用DMA模式进行接收
0:禁用DMA模式进行接收
该位不适用于UART5。
HAL_UART_Receive_IT : Enable the UART Parity Error ,Frame error, noise error, overrun error,UART Data Register not empty Interrupt.
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;}
}
HAL_UART_IRQHandler :
?
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{uint32_t isrflags = READ_REG(huart->Instance->SR);uint32_t cr1its = READ_REG(huart->Instance->CR1);uint32_t cr3its = READ_REG(huart->Instance->CR3);uint32_t errorflags = 0x00U;uint32_t dmarequest = 0x00U;/* If no error occurs */errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));if (errorflags == RESET){/* UART in mode Receiver -------------------------------------------------*/if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)){UART_Receive_IT(huart);return;}}/* If some errors occur *//* UART in mode Transmitter ------------------------------------------------*//* UART in mode Transmitter end --------------------------------------------*/}?
UART_Receive_IT :
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{uint8_t *pdata8bits;uint16_t *pdata16bits;/* Check that a Rx process is ongoing */if (huart->RxState == HAL_UART_STATE_BUSY_RX){if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)){pdata8bits = NULL;pdata16bits = (uint16_t *) huart->pRxBuffPtr;*pdata16bits = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);huart->pRxBuffPtr += 2U;}else{pdata8bits = (uint8_t *) huart->pRxBuffPtr;pdata16bits = NULL;if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE))){*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);}else{*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);}huart->pRxBuffPtr += 1U;}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;}
}