2

繁殖条件:

这是我想解决的现实生活示例:我正在 stm32f411RET 上开发一个应用程序,该应用程序需要动态更改两个 PWM 的周期。两个 PWM 需要同步并且具有完全相同的频率,但是由于某些引脚限制我正在使用两个不同的计时器。在我的主循环中,我计算了我想要的时间段并调用:

TIM3->ARR = (uint16_t)period;
LL_TIM_OC_SetCompareCH4(TIM3, period/2);
TIM2->ARR=(uint16_t)period;
LL_TIM_OC_SetCompareCH3(TIM2, period/2);

一切都很好,但对我来说模糊的是两个计时器的初始化设置的组合:

  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
  NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(TIM2_IRQn);
  TIM_InitStruct.Prescaler = 0;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 0;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_EnableARRPreload(TIM2);  //Important Line!!
  LL_TIM_Init(TIM2, &TIM_InitStruct);
  LL_TIM_OC_EnablePreload(TIM2, LL_TIM_CHANNEL_CH3);
  TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
  TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
  TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
  TIM_OC_InitStruct.CompareValue = 0;
  TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
  LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct);
  LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH3);
  LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);
  LL_TIM_DisableMasterSlaveMode(TIM2);
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
  GPIO_InitStruct.Pin = BBD_R_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
  LL_GPIO_Init(BBD_R_GPIO_Port, &GPIO_InitStruct);

这对于计时器 2 来说是相当标准的,几乎相同的代码适用于计时器 3,唯一的例外是LL_TIM_EnableARRPreload(TIM2);更改为LL_TIM_DisableARRPreload(TIM3);.

TLDR 实际问题

当我更改这两个初始化函数中的任何一个时,计时器开始工作,但更改频率会使计时器完全失效。我从参考手册的第 316页以及包含原理图但仍然存在的第 320 页和第 321页了解此函数的作用我无法理解为什么此设置会导致计时器冻结。

PS它可能有用,也可能没用,所以我把它留在这里定时器2的ARR寄存器是32位长,定时器3的ARR是16,这从我发布的配置中并不明显,但我怀疑这会影响结果。

4

1 回答 1

2

首先,相同的初始化例程应该适用于用于生成所需 PWM 信号的两个定时器,除非您使用一个配置不同的定时器。

突出的TIM_InitStruct.Autoreload是在初始化期间设置为,在参考手册中未记录0计时器在计数器模式/pwm 模式下ARR设置为的行为。0明智的做法是根据计时器将 设置TIM_InitStruct.AutoreloadUINT32_MAX或。UINT16_MAX

此外,查看您的问题中显示的初始化例程(对于计时器 2 通道 3),该调用LL_TIM_EnableARRPreload可以更改ARR要缓冲的值。当ARR更改被缓冲时,该ARR值仅在更新事件 ( UEV) 上更新。禁用缓冲更新时LL_TIM_DisableARRPreloadARR会立即使用新值更新该值。参考手册中的下图显示了带和不带缓冲的行为。

  • ARR 缓冲 ( LL_TIM_EnableARRPreload):

ARR 缓冲 (LL_TIM_EnableARRPreload)

  • ARR 无缓冲 ( LL_TIM_DisableARRPreload): * ARR 无缓冲(LL_TIM_DisableARRPreload):

在循环中动态更新ARR值(PWM 周期)和比较计数器值(PWM 占空比CCRn)的情况下,最好将两个更新都缓冲/预加载。使用CCRn启用缓冲LL_TIM_OC_EnablePreload,如您的初始化例程中所示。缓冲ARR更改,将保持ARR更新之间 PWM 周期的完整性,避免任何无意的长脉冲;特别是,如果系统发现自己处于ARRnew < TIMx CNT< ARRold 的状态。请注意,如果您希望保持 PWM 信号同步,重要的ARR是两个定时器使用相同的预加载配置。

请注意,如果之前没有为其他目的初始化计时器,则以下调用是多余的。

  • LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH3);
  • LL_TIM_DisableMasterSlaveMode(TIM2);
  • LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET);

除了您的问题之外,还有更多的用例;根据您希望 PWM 信号同步的紧密程度,您可能需要考虑一个定时器作为主机 ( TIMxCR2.MMS=001) 运行而另一个作为从机 ( TIMxSMCR.SMS=100) 的基本配置,其中在启用主机时启用从机定时器。

于 2021-02-27T18:44:47.590 回答