STM32标准库学习——PWM输出实验

你所浪费的今天,是昨天死去的人奢望的明天;
你所厌恶的现在,是未来的你回不去的曾经。——《哈佛校训》


一、实验内容

STM32PB5(TIM3的CH2) 配置为 PWM模式2 ,输出一个频率为 120Hz 的方波,默认的占空比为 50%,可以通过按下按键 KEY1 对占空比进行递增调节,每次递增方波周期的 1/12 ,当占空比递增到 100% 时, PB5 输出高电平,通过按下按键 KEY3 对占空比进行递减调节,每次递减方波周期的 1/12 ,当占空比递减到 0% 时, PB5 输出低电平。

所用工具:

  1. 芯片:STM32F103RCT6
  2. IDE :MDK-Keil 软件
  3. SMT32F10x 固件库函数
  4. TIM3 CH2 :通用定时器3 通道2(CH2)

二、实验原理

2.1、PWM简介

脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调试。 这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字输出来对 模拟电路 进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。


例如上图中,图b)是微处理输出的数字信号,实际上他接到电机等功率设备上时,效果相当于图a)。这就是 PWM 调制。例如输出占空比为50%,频率为10Hz的脉冲,高电平为3.3V.则其输出的模拟效果相当于输出一个1.65V的高电平。(1.65V = 3.3V * 50%)

脉冲调制(PWM)有两个重要的参数:

  • 输出频率: 频率越高,则模拟的效果越好;
  • 占空比 : 占空比就是改变输出模拟效果的电压大小。占空比越大则模拟出的电压越大。(通俗地说,就是高电平占一个电压周期的比例。)
  • 占空比是指在一个脉冲循环内,通电时间相对于总时间所占的比例。占空比(Duty Ratio)在电信领域中有如下含义:例如:脉冲宽度1μs,信号周期4μs的脉冲序列占空比为0.25。

    2.2、PWM输出实验流程图分析

  • 输出一个占空比为1/2的方波

    假设TIM3_CCR2为300,TIM3_CNT是从0计数到599,当TIM3_CNT从0计数到299时,比较输出引脚为高电平,TIM3_CNT从300计数到599时,比较输出引脚为低电平,周而复始,就可以输出一个占空比为1/2的方波,如下图所示。

  • 输出一个占空比为1/6的方波

    假设TIM3_CCR2为100,TIM3_CNT是从0计数到99,当TIM3_CNT0从0计数到99时,比较输出引脚为高电平,TIM3_CNT从100计数到599时,比较输出引脚为低电平,周而复始,就可以输出一个占空比为1/6的方波,如下图所示。

  • 输出一个占空比为5/6的方波

    假设TIM3_CCR2为500,TIM3_CNT是从0计数到499,当TIM3_CNT0从0计数到499时,比较输出引脚为高电平,TIM3_CNT从500计数到599时,比较输出引脚为低电平,周而复始,就可以输出一个占空比为5/6的方波,如下图所示。

  • 2.3、通用定时器部分寄存器

    本实验涉及的通用定时器寄存器除了包括定时器基本使用的控制寄存器1(TIMx_CR1)、控制寄存器2(TIMx_CR2)、DMA/中断使能寄存器(TIMx_DIER)、状态寄存器(TIMx_SR)、事件产生寄存器(TIMx_EGR)、计数器(TIMx_CNT)、预分频器(TIMx_PSC)和自动重载寄存器(TIMx_ARR),还包括捕获/比较模式寄存器1(TIMx_CCMR1)、捕获/比较使能寄存器(TIMx_CCER)和捕获/比较寄存器2(TIMx_CCR2)

    2.4、通用定时器部分固件库函数

    本实验涉及的通用定时器固件库函数包括 TIM_TimeBaseInitTIM_CmdTIM_ITConfigTIM_ClearITPendingBitTIM_GetITStatusTIM_SelectOutputTrigger,还包括 TIM_OC2InitTIM_SetCompare2 ,以及 TIM_OC2PreloadConfig

  • TIM_OC2Init 函数:可以配置定时器通道2的输出模式;
  • TIM_OC2PreloadConfig 函数:的功能是使能或除能 TIMxCCR2 上的预装载寄存器;
  • TIM_SetCompare2 函数:的功能是设置 TIMx 捕获比较2寄存器值;

  • 2.5、AFIO 部分寄存器

    AFIO:复用功能IO和调试配置。

    本实验涉及的 AFIO 寄存器只有复用重映射和调试 I/O 配置寄存器 (AFIO_MAPR)

    2.6、AFIO 部分固件库函数

    本实验涉及的AFIO固件库函数只有 GPIO_PinRemapConfig

  • GPIO_PinRemapConfig 函数的功能:是改变制定管脚的映射。

  • 三、代码编写

    3.1、复制并编译原始工程

    链接:https://pan.baidu.com/s/1Xacm_nI6tYkIDdvVWu7mag
    提取码:3lud

    3.2、添加 PWM 文件对 (.c/.h)

    3.3、完善 PWM.h 文件

    #ifndef _PWM_H_
    #define _PWM_H_
    
    /*********************************************************************************************************
    *                                              包含头文件
    *********************************************************************************************************/
    #include "DataType.h"
    
    /*********************************************************************************************************
    *                                              宏定义
    *********************************************************************************************************/
    
    /*********************************************************************************************************
    *                                              枚举结构体定义
    *********************************************************************************************************/
    
    /*********************************************************************************************************
    *                                              API函数声明
    *********************************************************************************************************/
    void  InitPWM(void);      //初始化PWM模块
    void  SetPWM(i16 val);    //设置占空比
    
    void  IncPWMDutyCycle(void);    //递增占空比,每次递增方波周期的1/12,直至高电平输出
    void  DecPWMDutyCycle(void);    //递减占空比,每次递减方波周期的1/12,直至低电平输出
    
    #endif
    

    3.4、完善 PWM.c 文件

    /*********************************************************************************************************
    *                                              包含头文件
    *********************************************************************************************************/
    #include "PWM.h"
    #include "stm32f10x_conf.h"
    
    /*********************************************************************************************************
    *                                              内部变量
    *********************************************************************************************************/
    static  i16 s_iDutyCycle = 0;  //用于存放占空比
    
    /*********************************************************************************************************
    *                                              内部函数声明
    *********************************************************************************************************/
    static void ConfigTimer3ForPWMPB5(u16 arr, u16 psc);  //配置PWM
    
    /*********************************************************************************************************
    * 函数名称:ConfigTimer3ForPWMPB5
    * 函数功能:配置TIM3
    * 输入参数:void 
    * 输出参数:void
    * 返 回 值:void
    * 创建日期:2018年01月01日
    * 注    意:
    *********************************************************************************************************/
    static void ConfigTimer3ForPWMPB5(u16 arr, u16 psc)
    {
      GPIO_InitTypeDef GPIO_InitStructure;            //GPIO_InitStructure用于存放GPIO的参数
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; //TIM_TimeBaseStructure用于存放定时器的基本参数
      TIM_OCInitTypeDef  TIM_OCInitStructure;         //TIM_OCInitStructure用于存放定时器的通道参数
    
      //使能RCC相关时钟
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    //使能TIM3的时钟
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   //使能GPIOB的时钟
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);    //使能AFIO的时钟
      
      //注意,GPIO_PinRemapConfig必须放在RCC_APBXPeriphClockCmd后
      GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);    //TIM3部分重映射TIM3.CH2->PB5
    
      //配置PB5,对应TIM3的CH2
      GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5;             //设置引脚  
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;        //设置模式
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //设置I/O输出速度
      GPIO_Init(GPIOB, &GPIO_InitStructure);                  //根据参数初始化GPIO
     
      //配置TIM3
      TIM_TimeBaseStructure.TIM_Period        = arr;  //设置自动重装载值
      TIM_TimeBaseStructure.TIM_Prescaler     = psc;  //设置预分频器值
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;                  //设置时钟分割:tDTS = tCK_INT  
      TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up; //设置向上计数模式  
      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);               //根据参数初始化TIM3
      
      //配置TIM3的CH2为PWM2模式,TIM_CounterMode_Up模式下,TIMx_CNT < TIMx_CCRx时为无效电平(高电平)  
      TIM_OCInitStructure.TIM_OCMode      = TIM_OCMode_PWM2;        //设置为PWM2模式
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能比较输出
      TIM_OCInitStructure.TIM_OCPolarity  = TIM_OCPolarity_Low;     //设置极性,OC2低电平有效 
      TIM_OC2Init(TIM3, &TIM_OCInitStructure);                      //根据参数初始化TIM3的CH2
    
      TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);             //使能TIM3的CH2预装载
        
      TIM_Cmd(TIM3, ENABLE);                                        //使能TIM3
    }
    
    /*********************************************************************************************************
    * 函数名称:InitPWM
    * 函数功能:初始化PWM模块
    * 输入参数:void 
    * 输出参数:void
    * 返 回 值:void
    * 创建日期:2018年01月01日
    * 注    意:
    *********************************************************************************************************/
    void  InitPWM(void)
    {
      ConfigTimer3ForPWMPB5(599, 999);  //配置TIM3,72000000/(999+1)/(599+1)=120Hz
      TIM_SetCompare2(TIM3, 0);         //设置初始值为0
    }
    
    /*********************************************************************************************************
    * 函数名称:SetPWM
    * 函数功能:设置占空比
    * 输入参数:void 
    * 输出参数:void
    * 返 回 值:void
    * 创建日期:2018年01月01日
    * 注    意:
    *********************************************************************************************************/
    void SetPWM(i16 val)
    {
      s_iDutyCycle = val;                   //获取占空比的值
      
      TIM_SetCompare2(TIM3, s_iDutyCycle);  //设置占空比
    }
    
    /*********************************************************************************************************
    * 函数名称:IncPWMDutyCycle
    * 函数功能:递增占空比,每次递增方波周期的1/12,直至高电平输出 
    * 输入参数:void 
    * 输出参数:void
    * 返 回 值:void
    * 创建日期:2018年01月01日
    * 注    意:
    *********************************************************************************************************/
    void IncPWMDutyCycle(void)
    {
      if(s_iDutyCycle >= 600)               //如果占空比不小于600
      {                                     
        s_iDutyCycle = 600;                 //保持占空比值为600
      }                                     
      else                                  
      {                                     
        s_iDutyCycle += 50;                 //占空比递增方波周期的1/12
      }
      
      TIM_SetCompare2(TIM3, s_iDutyCycle);  //设置占空比
    }
    
    /*********************************************************************************************************
    * 函数名称:DecPWMDutyCycle
    * 函数功能:递减占空比,每次递减方波周期的1/12,直至低电平输出 
    * 输入参数:void 
    * 输出参数:void
    * 返 回 值:void
    * 创建日期:2018年01月01日
    * 注    意:
    *********************************************************************************************************/
    void DecPWMDutyCycle(void)
    {
      if(s_iDutyCycle <= 0)               //如果占空比不大于0
      {                                   
        s_iDutyCycle = 0;                 //保持占空比值为0
      }                                   
      else                                
      {                                   
        s_iDutyCycle -= 50;               //占空比递减方波周期的1/12
      }
      
      TIM_SetCompare2(TIM3, s_iDutyCycle);//设置占空比
    }
    

    注: 每个文件的底部都要留一个空行。不然会出现一个如下图的 warning警告。

    3.5、完善 ProcKeyOne.c 文件

    3.6、添加 main.h 文件

    /*********************************************************************************************************
    * 函数名称:main
    * 函数功能:主函数 
    * 输入参数:void
    * 输出参数:void
    * 返 回 值:int
    * 创建日期:2018年01月01日
    * 注    意:
    *********************************************************************************************************/
    int main(void)
    { 
      InitSoftware();   //初始化软件相关函数
      InitHardware();   //初始化硬件相关函数
      
      printf("Init System has been finished.\r\n" );  //打印系统状态
    
      SetPWM(300);
      
      while(1)
      {
        Proc2msTask();  //2ms处理任务
        Proc1SecTask(); //1s处理任务   
      }
    }
    
    

    四、进阶任务

    呼吸灯是指灯光在被动控制下完成亮、暗之间的逐渐变化,类似于人的呼吸。利用PWM的输出高低电平持续时长变化,设计一个程序,实现呼吸灯功能。为了充分利用STM32核心板,可以通过固件库函数将PC5配置为浮空状态,然后通过杜邦线将PC5连接到PB5。在主函数中通过持续改变输出波形的占空比实现呼吸灯功能。要求占空比变化能在最小值和某个合适值的范围之内循环往复,以达到LED2亮度由亮到暗、由暗到亮渐变效果。

    进阶任务代码:
    链接:https://pan.baidu.com/s/1_oB77qmAccnl-tMUQ5Utnw
    提取码:k1i6

    五、结果演示

    谢谢阅读!!!

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32标准库学习——PWM输出实验

    发表评论