1+X传感网中级备考:PWM原理及通用定时器配置解析

1.任务解析

2.PWM原理

3. 通用定时器TIM4配置原理

4. 图形化配置对应的HAL库软件代码

5. 补充代码

1.任务解析

1.1:LED灯效果显示为逐渐变量,然后逐渐变暗;
1.2:系统刚上电,LED灯为关闭状态,第奇数次按键按下,LED灯显示呼吸灯效果,第偶数次按下按键,LED灯关闭;

目标:先实现任务1.1。要实现LED灯逐渐变量,逐渐变暗的交替效果;定位到硬件原理图,观察LED9发光二极管直接连接PB8_PWM,于是我们可以直接使用GPIOB_8引脚,实现PWM脉冲输出;


图1:呼吸灯的电路原理图

2.PWM解析

脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用数字输出来对模拟电路进行控制的一种技术。

图1:PWM 信号生成过程示意图

PWM 信号的生成样式与计数器寄存器(TIMx_CNT)、自动重载寄存器(TIMx_ARR)以及捕获/比较寄存器(TIMx_CCRy)有关。
假定定时器工作在向上计数 PWM模式,且当 CNT=CCRx 时输出 1。如上的 PWM示意图:当 CNT 值小于 CCRx 的时候,IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。
改变 CCRx 的值,就可以改变 PWM 输出的占空比,
改变 ARR 的值,就可以改变 PWM 输出的频率
,这就是 PWM 输出的原理。<本小节参考《正点原子HAL库开发指南》>

3.通用定时器TIM4配置原理

3.1 TMI4通用定时器功能框图
补充功能框图的解释:

图2:通用定时器的功能框图

图2:通用定时器的功能框图

3.2 关键寄存器介绍
之前定时器控制LED闪灭1秒,我们使用了三个寄存器,详情请看
https://www.jianshu.com/p/8403dedd1785
本文重点介绍捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。
模式寄存器(TIMx_CCMR1/2)
捕获/比较模式寄存器(TIMx_CCMR1/2)该寄存器总共有 2 个,TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4;

图3:模式寄存器

该寄存器分了 2层,上面一层对应输出而下面的则对应输入。可用于输入(捕获模式)或输出(比较模式),通道的方向由相应的CCxS定义;当使用的是 PWM 模式时,OCxM 3 位必须设置为 110/111;


图4OC1M2-0配置

图5 PWM1模式图例

图6:PWM2模式图例

PWM1模式:OCxM=110,在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
PWM2模式:OCxM=111: 在向上计数时,一旦TIMx_CNT

捕获/比较使能寄存器(TIMx_CCER)
该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如图7所示:

图7:TIMx_ CCER 寄存器各位描述

我们这里只用到了 CC3E 位,该位是输入/捕获 3 输出使能位,要想PWM 从 IO 口输出,这个位必须设置为 1,所以我们需要设置该位为 1;
图8:寄存器引脚功能

捕获/比较寄存器(TIMx_CCR1~4)
最后,我们介绍一下捕获/比较寄存器(TIMx_CCR1~4),该寄存器总共有 4 个,对应 4 个输通道 CH1~4。
该寄存器总共有 4 个,对应 4 个输通道 CH1~4。因为这 4 个寄存器都差不多,我们仅以 TIMx_CCR1 为例介绍;

图9:寄存器 TIMx_ CCR1 各位描述

在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽度了。本章,我们使用的是 TIM4的通道 3,所以我们需要修改 TIM4_CCR3 以实现脉宽控制 LED9 的亮度。

4.软件代码的功能实现顺序

1)开启 TIM4 和 GPIO 时钟;使能GPIO8寄存器;

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM4)
  {
    /* TIM4 clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();
  }
}
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
}

2)初始化 TIM4,设置 TIM4 的 ARR 和 PSC 等参数;
设置 TIM4_CH3 的 PWM 模式,输出比较极性,比较值等参数。

void MX_TIM4_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 71;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 99;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim4);

}

其中,这些参数的配置对应图形化配置为:

  htim4.Instance = TIM4; 使能定时器4
  htim4.Init.Prescaler = 71; 预分频系数71
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 99; 重载计数器初值99;
  sConfigOC.OCMode = TIM_OCMODE_PWM1; PWM1模式为1;
  sConfigOC.Pulse = 0;捕捉比较寄存器TIMx_CCR1初始值为0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
图形化配置的变量

HAL 库为我们提供了一个独立的定时器初始化函数 HAL_TIM_PWM_Init,该函数,作用是初始化定时
器 的 ARR 和 PSC 等参 数;它调用了 MSP 回 调 函 数
HAL_TIM_PWM_MspInit;

HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
{
  /* Check the TIM handle allocation */
  if (htim == NULL)
  {
    return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_TIM_INSTANCE(htim->Instance));
  assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
  assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
  assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload));

  if (htim->State == HAL_TIM_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    htim->Lock = HAL_UNLOCKED;

#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
    /* Reset interrupt callbacks to legacy weak callbacks */
    TIM_ResetCallback(htim);

    if (htim->PWM_MspInitCallback == NULL)
    {
      htim->PWM_MspInitCallback = HAL_TIM_PWM_MspInit;
    }
    /* Init the low level hardware : GPIO, CLOCK, NVIC */
    htim->PWM_MspInitCallback(htim);
#else
    /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
    HAL_TIM_PWM_MspInit(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
  }

  /* Set the TIM state */
  htim->State = HAL_TIM_STATE_BUSY;

  /* Init the base time for the PWM */
  TIM_Base_SetConfig(htim->Instance, &htim->Init);

  /* Initialize the DMA burst operation state */
  htim->DMABurstState = HAL_DMA_BURST_STATE_READY;

  /* Initialize the TIM channels state */
  TIM_CHANNEL_STATE_SET_ALL(htim, HAL_TIM_CHANNEL_STATE_READY);
  TIM_CHANNEL_N_STATE_SET_ALL(htim, HAL_TIM_CHANNEL_STATE_READY);

  /* Initialize the TIM state*/
  htim->State = HAL_TIM_STATE_READY;

  return HAL_OK;
}

3)设置 TIM4_CH3 的 PWM 比较初值;调用函数实现:

 __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 0);

PWM 模式,输出比较极性的设置:

  sConfigOC.Pulse = 0;捕捉比较寄存器TIMx_CCR1初始值为0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; 比较极性

4)使能 TIM4,使能 TIM4 的 CH3 输出。该函数第二个入口参数 Channel 是用来设置要使能输出的通道号;

  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);

5)修改 TIM4_CCR3 来控制占空比。

 static uint16_t pwm_value = 0;
 __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, pwm_value);
    

5.补充代码

为了实现任务1.2,按键按下奇数次灯逐渐变亮,按键按下偶数次变灭的效果;需要用到全局变量 keydown_flag,pwm_enable来做判断按键是否按下,是否使能PWM模式;注意pwm_value的时函数__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, pwm_value);
的参数,用于给寄存器TIM_CCRx赋值,修改比较寄存器的值。用于调整脉冲宽度;

 typedef enum
 {
 count_up = 0x01,
  count_down,
 } pwm_mode_enum_TypeDef;

 pwm_mode_enum_TypeDef pwm_mode = count_up;
 uint8_t keydown_flag = 0;
 uint8_t pwm_enable = 0;
 static uint16_t pwm_value = 0;
int main(void)
{
 

while (1)
 {
    if (keydown_flag == 1)
   {
      HAL_Delay(300);
     if (keydown_flag == 1)
      {
       keydown_flag = 0;

         if (pwm_enable == 0)
            pwm_enable = 1;
         else if (pwm_enable == 1)
            pwm_enable = 0;
       }
    }
/* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */
    if (pwm_enable == 1)
   {
      if (pwm_value == 0) 
        {
        pwm_mode = count_up;
         }
      else if (pwm_value == 30)
        {
          pwm_mode = count_down;
         }
  
       if (pwm_mode == count_up)
        {
         pwm_value++;
        }
       if (pwm_mode == count_down)
        {
        pwm_value--;
        }
      __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, pwm_value);
    }
    else if (pwm_enable == 0)
   {
    __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 0);
    }
 HAL_Delay(50);
}
  /* USER CODE END 3 */
}

你可能感兴趣的:(1+X传感网中级备考:PWM原理及通用定时器配置解析)