STM32中的比较输出模式与PWM模式:一窥其妙

文章目录

  • 前言
  • 一、输出比较模式和PWM模式
  • 二、PWM模式
  • 1.原理
  • 2.配置cubemx
  • 3.代码及验证
  • 三、输出比较模式
  • 1.原理
  • 2.配置cubemx
  • 2.代码及验证
  • 总结

  • 前言

    最近因为从标准库过渡到hal库,又重新温习了一遍定时器相关的功能,在stm32中定时器经常被用作输出PWM波,在此对定时器常用来输出PWM的两种模式:输出比较模式和PWM模式做一个总结

    本次实验使用stm32G431,使用cubemx生成底层代码。


    一、输出比较模式和PWM模式

    输出比较模式和PWM模式都可以用来输出PWM波,在功能上两者有相同之处,对于一个定时器这两种方式都可以做到四路输出PWM,每一路PWM占空比都可调,也有不同之处,输出比较模式可以方便的调节每一路PWM波的频率,可以输出四路频率不同,占空比不同的PWM。但是PWM模式如果想要调节PWM波的频率,那么就只能重新设置预分频系数或者自动重装载寄存器ARR,并且输出的四路PWM频率必定一致。

    PWM模式是输出比较模式的子集。

    二、PWM模式

    1.原理

    在预分频系数确定的条件下,PWM模式的信号频率是由自动重装载寄存器ARR来确定的,占空比则由比较寄存器CCR来确定。

    PWM模式分为两种,PWM1和PWM2,都可以设置计数器递增计数或者递减计数。具体如下表

    在使用PWM模式时,我们只需要设置预分频系数PSC,自动重装载值ARR,即可确定PWM具体频率,即 PWM频率 =(系统时钟频率)/((ARR+1)*(PSC+1))(单位:Hz)

    这里以PWM1的递增计数方式为例,假定系统时钟频率设置为80MHz,那么当ARR取999,PSC取79的时候,PWM的频率即为1kHz。配置完成后对时钟进行初始化,此时时钟开始以预分频之后的频率即1MHz开始计数,当CNT的值小于设置的CCR的值时,PWM输出引脚输出为高电平,当CNT的值大于CCR的值时,PWM输出引脚输出为低电平,当CNT计数至ARR时,计数器产生上溢事件,计数器的值更新为0,以此往复。

    2.配置cubemx

    1、首先需要对时钟频率进行设置,这里设置系统时钟频率为80MHz

    2、此处选用TIM3通用定时器,配置时钟来源为内部时钟,选择Channel1和Channel2的PWM模式

    3、配置PSC为79,ARR为999,向上计数模式,使能自动重载预装载,Channel1选择PWM1模式,pulse值取200,这里的pulse就是指比较寄存器CCR,理论上计算可得PWM频率为1KHz,占空比为20%
    Channel2的pulse值取300,其余和Channel1一致

    4、最后,配置project相关参数,生成代码。

    3.代码及验证

    cubemx配置生成完成后只需要再启动一下定时器即可完成PWM的输出

      HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
      __HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_1);	
      HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
      __HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_2);	
    

    此处实验使用的是TIM3的Channel1和Channel2,相应的引脚为PA6、PA7,下载到开发板上用逻辑分析仪可以得到如下波形

    可以看到波形符合预期,当然在代码中也可以通过
    __HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE)
    来重新设置CCR更改PWM的占空比
    或者通过__HAL_TIM_SET_AUTORELOAD(HANDLE, AUTORELOAD)
    来重新设置ARR来改变PWM的频率


    三、输出比较模式

    1.原理

    在上面的PWM模式下我们看一发现Channel1和Channel2的占空比可以不一样,但是其频率是一致的,那么如果需要在一个定时器下的多个通道分别输出频率不同,占空比不同的PWM那么就需要使用输出比较模式了。

    输出比较模式和PWM模式的原理很相似,在输出比较模式输出PWM的实验中,有一点不同的是PWM1递增模式下CNT与CCR作比较,若CNT小于CCR则输出为高电平,若CNT大于CCR则输出为低电平,并且在CNT计数至ARR时,CNT会更新至0并产生上溢事件。但是输出比较模式在CNT与CCR不断做比较的过程中,若CNT等于CCR,产生的则是电平翻转,并且会产生中断,通过对中断回调函数的编写,就能够实现多路不同频率信号的输出。

    例如,我们定义duty作为占空比,定义pulse作为周期计数数目,若duty为10%,pulse为10000,取ARR为最大值65535(在输出比较模式中ARR没啥用,定义成最大值就不用经常更新CNT为0了)系统时钟频率为80MHz,预分频系数为79,则预分频之后的时钟频率为1MHz,那么当计pulse个数目,则时间为10ms,占空比为10%,则所需高电平时间为1ms。

    当第一次CNT等于CCR时,进入中断回调函数,让CCR加上(pulse-pulse*duty),即9ms后再次进行反转电平,此时PWM持续了9ms的低电平;

    当第二次CNT等于CCR是,进入中断回调函数,让CCR加上(pulse*duty),即1ms后再进行反转电平,此时PWM持续了1ms的高电平;
    这样即可完成输出比较PWM的配置。

    有人可能会问,为什么CNT可以加这么多数,那是因为当CNT从65535溢出后,仍然会从头开始计数,对程序没有影响,具体如下图。请添加图片描述

    2.配置cubemx

    1、依然配置系统时钟频率为80MHz,此处选用TIM3通用定时器,配置时钟来源为内部时钟,选择Channel1和Channel2的输出比较模式

    2、如图配置参数,需要注意的是自动重载预装载和输出比较预装载都需要关闭,
    模式需要选择toogle on match

    3、最后配置project相关参数,生成代码


    2.代码及验证

    cubemx配置生成完成后,首先需要启动一下定时器,清除中断标志位

      HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
      __HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_1);	
      HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
      __HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_2);	
    

    然后对中断回调函数进行编写

    void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
    {
      uint32_t OC_Count = 0;
    
      OC_Count = __HAL_TIM_GET_COUNTER(htim);
    
      if(htim->Instance == TIM3)
      {
        if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
        {
          if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6))
          {
            __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,OC_Count + OC_Channel1_Pulse - OC_Channel1_Duty*OC_Channel1_Pulse/100);
          }
          else
          {
            __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,OC_Count + OC_Channel1_Duty*OC_Channel1_Pulse/100);
          }
        }
        else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
        {
          if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7))
          {
            __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,OC_Count + OC_Channel2_Pulse - OC_Channel2_Duty*OC_Channel2_Pulse/100);
          }
          else
          {
            __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,OC_Count + OC_Channel2_Duty*OC_Channel2_Pulse/100);
          }
        }
      }
    }
    

    此处OC_Channel1_Pulse和OC_Channel2_Pulse 我就是前面“原理”中的pulse,OC_Channel1_Duty和OC_Channel2_Duty就是“原理”中的duty,有定义了两个标志位,通过判断引脚电平,使之能够间次调用。

    其中duty和pulse的值可以自己设置,这里由于我duty定义的是整形,所以在代码中对其相应的除以了100,相当于转化为了小数。

    若取OC_Channel1_Duty为10%,OC_Channel1_Pulse为10000,则Channel1频率为100Hz,占空比为10%
    若取OC_Channel2_Duty为30%,OC_Channel1_Pulse为5000,则Channel1频率为200Hz,占空比为30%

    最后下载到开发板中,使用逻辑分析仪观察波形如下


    符合实验预期


    总结

    以上只是简单实现了PWM模式和输出比较模式下输出PWM的任务,还可以通过按键或其他触发条件,用相应函数对其占空比或者频率进行相应调整。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32中的比较输出模式与PWM模式:一窥其妙

    发表评论