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

Nic*_*ldo 3 c serial-port stm32 uart stm32f0

我试图了解 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);
Run Code Online (Sandbox Code Playgroud)

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

例如,如果我的数据包tx1[]是 100 字节,则该HAL_UART_Transmit_IT()功能会阻止 CPU 在将完整数据包发送到串行端口时等待,或者它的工作方式更像是一个单独的进程,我告诉微控制器发送该数据包,并且在发送数据包的同时,它还处理剩余的数据包。我的代码/主要功能的一部分?

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

小智 5

首先,您需要了解如何HAL_UART_Transmit_IT使用它。我们可以从STM FAQ获得一些帮助。

中断模式。

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

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

阻塞

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
}
Run Code Online (Sandbox Code Playgroud)

非阻塞

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;

}
Run Code Online (Sandbox Code Playgroud)

_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;
   }
Run Code Online (Sandbox Code Playgroud)

这又调用了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;
   }
 }
Run Code Online (Sandbox Code Playgroud)

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

中断

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

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