使用 ST 的 HAL 库让 PWM 在 STM32F4 上工作

电器工程 脉宽调制 stm32f4 stm32cubemx 图书馆
2022-01-20 22:32:25

我正在尝试切换到 ST HAL 库,但似乎无法让 PWM 工作。编译正常,就是启动不了。

在我的 main() 中,我调用了 Timer 初始化函数:

/* TIM3 init function */
void MX_TIM3_Init(void)
{

  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 1300;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_PWM_Init(&htim3);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_SET;
  sConfigOC.Pulse = 650;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;

  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3);
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4);
  HAL_TIM_PWM_MspInit(&htim3);

} 

GPIO在HAL_TIM_PWM_MspInit()函数中初始化:

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(htim_pwm->Instance==TIM3)
  {
    /* Peripheral clock enable */
    __TIM3_CLK_ENABLE();

    /**TIM3 GPIO Configuration    
    PC9     ------> TIM3_CH4
    PC8     ------> TIM3_CH3
    PC7     ------> TIM3_CH2
    PC6     ------> TIM3_CH1 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  }

}

最后我的 main() 看起来像这样:(我从 main 调用 SystemInit() 因为我正在使用带有 coocox coide 的 STCube 生成的文件)

int main(void)
{

    SystemInit() ;

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_TIM3_Init();
  MX_GPIO_Init();
  MX_LWIP_Init();
  while (1)
  {

  }

}
4个回答

我参加聚会迟到了,但我发现自己处于类似情况并且得到了真正的答案,或者至少我亲自验证过的答案可以与我自己的 STM32 板和 STM32CubeMx 驱动程序一起使用。

  1. 确保初始化(清零)堆栈分配的结构。例如memset(&sConfigOC, 0, sizeof(sConfigOC));,局部变量不会自动初始化,并且您会遇到意外/意外的配置,因为 HAL 基于这些句柄变量对外围设备状态做出非常基本的假设。当堆栈内存发生变化时,当行为从编译变为编译或从函数调用变为函数调用时,尤其令人抓狂。
  2. 不要HAL_TIM_PWM_MspInit()手动调用。它会在您调用 时自动调用HAL_TIM_PWM_Init(),但您必须确保您的句柄变量已正确初始化(参见上面的#1)。
  3. HAL_TIMEx_MasterConfigSynchronization()如果您不更改默认(非链接/同步)配置,则无需调用。它不会伤害任何东西,但也没有必要。
  4. 您的MspInit()功能很好,除了您还应该启用 GPIOC 外设的时钟。

以及阻止它工作的魔力:

  1. 必须在每次调用HAL_TIM_PWM_Start()后调用HAL_TIM_PWM_ConfigChannel()——首先要做的HAL_TIM_PWM_ConfigChannel()是禁用定时器输出(中的CCxETIMx_CCER)。HAL_TIM_PWM_ConfigChannel()不会重新启用定时器输出!

由于手动更新 PWM 占空比的唯一 HAL 方法是通过HAL_TIM_PWM_ConfigChannel(),因此您必须始终调用HAL_TIM_PWM_Start(),否则您将没有 PWM 输出。我认为这样做是因为使用 PWM 的正常方式是使用_IT()或的_DMA()变体HAL_TIM_PWM_Start(),因此可以说是在“在后台”更新占空比。

其他一些答案(包括您最初标记为已接受的答案)是错误的:

  1. 不要调用HAL_TIM_Base_Start(), norHAL_TIM_Base_Init()或任何其他非 PWM 调用;首先,HAL 不会调用您的PWM_MspInit()函数,因为外设句柄将不再处于复位状态,但更重要的是,PWM(以及 OC 和其他变体)都可以正确调用低级内部函数,而无需您手动执行。HAL 的全部意义在于不必过于担心细节,但您必须很好地掌握 HAL 正在做什么以及它的预期。完整的源代码是可用的,并且有很好的文档记录。你只需要阅读它。
  2. 除非您使用免费输出,否则您不必调用HAL_TIMEx_PWMN_Start()或任何其他功能。TIMEx同样,这在 HAL 源中得到了很好的记录。

我正在使用 STCubeMX 和生成的 HAL 初始化文件。在我的 F302 Nucleo 板上验证了过程。我设置了具有正常和互补输出的高级定时器 1 (TIM1),没有死区时间。

以下是我在 CubeMX 中配置 PWM 的方法:

  1. 在引脚排列视图中,我选择了两个引脚作为 TIM1_CH 和 TIM1_CHN 引脚。在左侧窗格中,将 TIM1 通道 1 设置为“PWM Generation CH1 CH1N”。
  2. 在配置选项卡中,我输入了以下设置(TIM1 clk 为 64MHz)CubeMX TIM1 配置设置
  3. 生成代码后,我们仍然需要启动 PWM。这是通过在 main() 中的 while(1) 之前在用户代码区域中调用以下函数来完成的:

    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //starts PWM on CH1 pin HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); //starts PWM on CH1N pin

  4. 要更改配置设置,请使用 stm32f3xx_hal_tim.h 中提供的以下宏。HAL_TIM_PWM_ConfigChannel()正如@akohlsmith 所说,这并不是手动更新 PWM 设置的唯一方法。

    __HAL_TIM_GET_AUTORELOAD(&htim1); //gets the Period set for PWm __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyCycle); //sets the PWM duty cycle (Capture Compare Value)

无需再次调用HAL_TIM_PWM_Start()这些宏在运行时更改设置。

使用 Cube Mx 时,生成的代码会初始化定时器外设,但不会启动它运行。解决方案正如其他人所建议的那样:添加 Start 功能。

HAL_TIM_Base_Start(&htim3); 
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_ALL); 

将此代码放在生成的调用MX_TIM3_Init().

您需要先启动计时器。在 上添加下一行以main()启动 timer3 CH1

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);