HAL_UART_Transmit_IT 如何在 STM32F091VB 上管理串行发送数据

How HAL_UART_Transmit_IT manages sending data on serial on the STM32F091VB

我正在尝试了解 STM32F091VB 如何使用函数 HAL_UART_Transmit_IT()

通过串行协议管理数据发送

目前我在 main() 中调用了一个函数来创建数据包并通过串行发送;它是这样的:

tx1[0] = STX;    
tx1[1] = 0xFF;
tx1[2] = 0x80;
tx1[3] = 0x80;

DE_TAST_HIGH;
HAL_UART_Transmit_IT(&huart3, tx1, 8);

现在,我发送的数据非常小,所以代码 运行 非常快,我试图了解如果我尝试通过串行协议发送一个巨大的数据包会发生什么。

例如,如果我的 tx1[] 是 100 字节,HAL_UART_Transmit_IT() 函数会阻止 CPU 在将完整数据包发送到串行端口时等待,或者它更像是一个单独的进程我在哪里告诉 micro 发送那个数据包,并且在发送它的同时还处理我的 code/main 函数的剩余部分?

我试图在微型数据表上搜索以查看是否有关于此过程的内容,但我没有运气。我已经阅读了stm32f0xx_hal_uart.c,它确认它是通过中断以非阻塞模式发送的,但我想要一些关于它的更深入的文档

首先,您需要了解 HAL_UART_Transmit_IT 的用途。我们可以从 STM FAQ.

那里得到一些帮助

该函数是“非阻塞”的,因为当您调用它时,它会对中断进行一些配置,然后 return。在调用您的函数期间不会传输缓冲区,而是将繁重的工作推迟到稍后阶段。

我们可以进一步查看源代码,以得到我所说的证据(注意我只保留了有趣的部分)。

阻止

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint16_t* tmp;
  uint32_t tickstart = 0U;
  
    // [ ... ]

    huart->TxXferSize = Size;
    huart->TxXferCount = Size;
    while(huart->TxXferCount > 0U)
    {

        // [ ... ]
        // This is were the actual HW regs are accessed, starting the transfer
        huart->Instance->DR = (*pData++ & (uint8_t)0xFF);
      } 
    }
    
    // [ ... ]

  return HAL_OK
}

非阻塞

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{

    
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    /* Enable the UART Transmit data register empty Interrupt */
    // This is the only part were HW regs are accessed. What is happening here??
    SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
    
    return HAL_OK;

}

_IT 函数只激活一个中断,同样基于数据表:

这意味着只要 TX 缓冲区空闲,我们就会收到一个中断。 那么实际上是谁在发送数据?

借助常见问题解答和阅读源代码,我们发现 void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) 做了这样的事情:

/* UART in mode Transmitter ------------------------------------------------*/
   if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
   {
     UART_Transmit_IT(huart);
     return;
   }

这又调用了 UART_Transmit_IT

 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)
   {

       huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);
 
     if(--huart->TxXferCount == 0U)
     {
       /* Disable the UART Transmit Complete 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
   {
     return HAL_BUSY;
   }
 }

这个函数只传输一个字节!然后它递减传输计数器(记住,所有信息都设置到 uart 处理程序中),如果它达到 0,最后调用 complete 中断。

中断

请注意,StmCube 为您完成外设初始化和中断链接,但如果您从头开始编程,您需要记住编写和注册UART_IRQ_Handler

您可以找到 here 代码导航器来查看我的代码片段并进一步调查。