HAL库中,关于串口收发数据的接口函数 提供了三种类型:
1、阻塞模式(blocking mode);2、中断模式(interrupt mode);3、DMA模式(DMA mode)
1、HAL_UART_Receive、HAL_UART_Transmit // 阻塞模式
2、HAL_UART_Receive_IT、HAL_UART_Transmit_IT // 中断模式
3、HAL_UART_Receive_DMA、HAL_UART_Transmit_DMA // DMA模式
阻塞模式消耗CPU资源多,霸占CPU资源,体现在 while 循环中。数据也需要通过cpu参与,进行外设到内存,和内存到外设的搬移(相对于DMA,数据的搬移就不是由CPU完成的)。
对于需要频繁的接收和发送的,可以使用轮训阻塞方式,相对于中断方式就会减少很多中断事件的处理。
阻塞发送,HAL_UART_Transmit
tickstart = HAL_GetTick(); // 为超时判断做准备
while(huart->TxXferCount > 0) // 占用CPU 阻塞方式(轮询)
{
huart->TxXferCount--;
UART_WaitOnFlagUntilTimeout() //超时判断使用的是 systick滴答定时器完成
huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU); // 数据发送寄存器,逐一发送
...
}
阻塞接收,HAL_UART_Receive
tickstart - HAL_GetTick(); // 为超时判断做准备
while(huart->RxXferCount > 0U) // 占用CPU 阻塞方式(轮询)
{
huart->RxXferCount--; // 接收多少字节
UART_WaitOnFlagUntilTimeout //超时判断 systick 滴答定时器
*pData++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask); //数据接收寄存器,逐一接收
}
中断模式,但是串口有数据发送或者接收时,会触发CPU中断产生,cpu跳转到中断服务函数进行数据的搬移,数据也需要通过cpu参与,进行外设到内存,和内存到外设的搬移(相对于DMA,数据的搬移就不是由CPU完成的)。
对于数据输入输出(吞吐)不频繁的接口,可以使用中断的方式。 不用像轮训阻塞方式一样,消耗大量的CPU资源来等待数据的到来。当数据到来会产生中断。没有产生中断, CPU就可以忙别的事情。
中断发送
HAL_UART_Transmit_IT(...)
{
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
//CR1.TXEIE 通过软件方式触发CPU发送中断产生
/* Enable the UART Transmit Data Register Empty Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
}
void USART1_IRQHandler(void)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
if(huart->TxXferCount == 0U)
{ //数据发送完成,再次触发数据发送完成中断
/* Disable the UART Transmit Data Register Empty Interrupt */
CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
/* Enable the UART Transmit Complete Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
return HAL_OK;
}
else
{ // CPU参数数据由内存搬移到外设, 这没有清除中断
huart->Instance->TDR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0xFFU);
huart->TxXferCount--;
return HAL_OK;
}
}
void USART1_IRQHandler(void)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
UART_EndTransmit_IT(huart);
{
/* Disable the UART Transmit Complete Interrupt */
// 清除中断
CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE);
// 执行发送完成中断回调函数
HAL_UART_TxCpltCallback(huart);
}
中断接收
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
// 软件方式使能串口接收中断,当有数据到来的时候,会产生中断
/* Enable the UART Parity Error and Data Register not empty Interrupts */
SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
}
void USART1_IRQHandler(void)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
*huart->pRxBuffPtr++ = (uint8_t)(uhdata & (uint8_t)uhMask);
if(--huart->RxXferCount == 0U)
{
// 清空中断
/* Disable the UART Parity Error Interrupt and RXNE interrupt*/
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
// 发送完成回调函数
HAL_UART_RxCpltCallback(huart);
return HAL_OK;
}
}