STM32 HAL USART驱动程序:此语法如何工作?

时间:2018-02-27 16:00:30

标签: c syntax embedded stm32 hal

我正在学习STM32编程,并试图在GPIO引脚上使用USART外设实现简单的异步串行通信。

HAL manual介绍了如何使用HAL USART驱动程序:

  1. 声明 USART_HandleTypeDef 结构
  2. 实施 HAL_USART_MspInit()
    • 启用USART& GPIO时钟
    • 配置GPIO
  3. USART_InitTypeDef
  4. 中编制通信参数
  5. 致电 HAL_USART_Init()

  6. 当我编写代码时,我声明了USART_HandleTypeDef,本能地填充了我的USART_InitTypeDef结构并开始填充HandleTypeDef:

      USART_HandleTypeDef UsartHandle;
    
      USART_InitTypeDef UsartInit;
      UsartInit.BaudRate   = 9600;
      UsartInit.WordLength = USART_WORDLENGTH_8B;
      UsartInit.StopBits   = USART_STOPBITS_1;
      UsartInit.Parity     = USART_PARITY_NONE;
      UsartInit.Mode       = USART_MODE_TX_RX;
    
      UsartHandle.Instance = USART6;
      UsartHandle.Init     = &UsartInit;
      /* do I really have to init EVERY data field? */
    
      HAL_USART_Init(&UsartHandle);
    


    然后我注意到要填充的数据字段很多。参考手册和网络上的代码示例,我注意到没有人真正定义所有USART_HandleTypeDef字段 - 它们以某种方式将HandleTypeDef和InitTypeDef组合在一起,如下所示:

    UART_HandleTypeDef UartHandle;
    
    UartHandle.Init.BaudRate = 9600;
    UartHandle.Init.WordLength = UART_DATABITS_8;
    UartHandle.Init.StopBits = UART_STOPBITS_1;
    UartHandle.Init.Parity = UART_PARITY_NONE;
    UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    UartHandle.Init.Mode = UART_MODE_TX_RX;
    UartHandle.Init.Instance = USART1;
    HAL_UART_Init(&UartHandle);
    


    这是如何运作的?我必须学习C语法的哪一部分,以了解哪里有 UartHandle。初始 .xxx 来自哪里? 按照我的计划,是否有可能“走很长的路”?如果我没有填充HandleTypeDef的每个数据字段,它们在哪里被初始化?

    PS。我没有使用STM32推荐的IDE或CubeMX,使用PlatformIO在Linux上工作。董事会:STM32F746发现工具包

    PPS。我真的不确定是将这个问题放在这里还是电子堆栈上。如果它不适合这种堆叠交换,请纠正我或移动问题。

1 个答案:

答案 0 :(得分:1)

  

这是如何工作的?我必须学习C语法的哪一部分   了解UartHandle.Init.xxx来自哪里?

这是基本的C struct语法。 USART_HandleTypeDef结构包含名为USART_InitTypeDef的{​​{1}}结构的实例。您可以将其视为嵌套结构。您可以使用重复的&#39; Init来引用嵌套结构的成员。请注意,.成员不是指向<{1}}结构的指针。它实际上是Init实例中包含的完整USART_InitTypeDef实例。

  

是否有可能做到这一点&#34;漫长的方式&#34;,正如我计划的那样?

是的,除了您的代码包含错误。你需要做这样的任务。

USART_InitTypeDef

请记住,USART_HandleTypeDef的{​​{1}}成员不是指针而是完整的结构。因此,您需要为其分配一个完整的结构,而不是指针。

但是要意识到,在定义UsartHandle.Init = UsartInit; // Note no `&` 变量时,您要为结构的实例分配空间。如果Init是函数局部变量,则该空间可能在堆栈上。您的初始化语句正在初始化结构的副本。然后,当您将USART_HandleTypeDef分配给UsartInit时,编译器会创建将复制结构的全部内容的代码。复制之后,如果UsartInit是一个局部变量,它将超出范围并被取消分配。

确实没有必要为您自己的UsartInit结构定义和分配空间,然后将整个结构复制到UsartHandle.InitUsartInit已经包含为其USART_InitTypeDef成员分配的空间。因此,直接简单地初始化UsartHandle.Init成员更有效,就像ST示例代码那样。

  

如果我没有填写HandleTypeDef的每个数据字段,他们会在哪里获得   初始化?

您不需要填写UsartHandle的每个数据字段。请参阅HAL参考手册以了解初始化所需的内容。您可能只需要初始化USART_InitTypeDefUsartHandle.Init成员。其余成员由HAL USART驱动程序在内部使用,它们将被驱动程序函数初始化并使用(如果有帮助,您可以将它们视为私有变量)。 API的设计者将该struct命名为&#34; Init&#34;作为一个提示,这是你需要初始化的。 ST示例代码提供了初始化所需内容的进一步证据。

[Stack Overflow上几位经验丰富的开发人员建议不要使用ST HAL,并鼓励人们根据设备的参考手册开发自己的驱动程序。要意识到这些开发人员拥有多年的经验,他们已经与各种微控制器系列和外设一起工作,并且他们能够理解参考手册并从头开始编写驱动程序。我同意ST HAL增加了一些可能对某些应用程序有害的膨胀。但我不同意初学者应该避免使用ST HAL。 ST HAL适用于许多应用程序,初学者使用起来比从头开始编写自己的驱动程序更容易(特别是考虑到HAL提供的许多示例)。]