• (五)转载:通用定时器PWM输出


    1.     TIMER输出PWM基本概念

      脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。一般用来控制步进电机的速度等等。

    STM32的定时器除了TIM6和TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1和TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出。

    1.1   PWM输出模式

      STM32的PWM输出有两种模式,模式1和模式2,由TIMx_CCMRx寄存器中的OCxM位确定的(“110”为模式1,“111”为模式2)。模式1和模式2的区别如下:

    110:PWM模式1-在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。

    111:PWM模式2-在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。

    由此看来,模式1和模式2正好互补,互为相反,所以在运用起来差别也并不太大。

    而从计数模式上来看,PWM也和TIMx在作定时器时一样,也有向上计数模式、向下计数模式和中心对齐模式,关于3种模式的具体资料,可以查看《STM32参考手册》的“14.3.9 PWM模式”一节,在此就不详细赘述了。

    1.2   PWM输出管脚

      PWM的输出管脚是确定好的,具体的引脚功能可以查看《STM32参考手册》的“8.3.7 定时器复用功能重映射”一节。在此需要强调的是,不同的TIMx有分配不同的引脚,但是考虑到管脚复用功能,STM32提出了一个重映像的概念,就是说通过设置某一些相关的寄存器,来使得在其他非原始指定的管脚上也能输出PWM。但是这些重映像的管脚也是由参考手册给出的。比如说TIM3的第2个通道,在没有重映像的时候,指定的管脚是PA.7,如果设置部分重映像之后,TIM3_CH2的输出就被映射到PB.5上了,如果设置了完全重映像的话,TIM3_CH2的输出就被映射到PC.7上了。

     

    1.3   PWM输出信号

      PWM输出的是一个方波信号,信号的频率是由TIMx的时钟频率和TIMx_ARR预分频器所决定的,具体设置方法在前面一个学习笔记中有详细的交代。而输出信号的占空比则是由TIMx_CRRx寄存器确定的。其公式为“占空比=(TIMx_CRRx/TIMx_ARR)*100%”,因此,可以通过向CRR中填入适当的数来输出自己所需的频率和占空比的方波信号。

     

    2.     TIMER输出PWM实现步骤

      1.设置RCC时钟;

      2.设置GPIO时钟;

      3.设置TIMx定时器的相关寄存器;

      4.设置TIMx定时器的PWM相关寄存器。

     

    第1步设置RCC时钟已经在前文中给出了详细的代码,在此就不再多说了。需要注意的是通用定时器TIMx是由APB1提供时钟,而GPIO则是由APB2提供时钟。注意,如果需要对PWM的输出进行重映像的话,还需要开启引脚复用时钟AFIO。

    第2步设置GPIO时钟时,GPIO模式应该设置为复用推挽输出GPIO_Mode_AF_PP,如果需要引脚重映像的话,则需要用GPIO_PinRemapConfig()函数进行设置。

    第3步设置TIMx定时器的相关寄存器时,和前一篇学习笔记一样,设置好相关的TIMx的时钟和技术模式等等。具体设置参看“TIMER基本定时功能”的学习笔记。

    第4步设置PWM相关寄存器,首先要设置PWM模式(默认情况下PWM是冻结的),然后设置占空比(根据前面所述公式进行计算),再设置输出比较极性:当设置为High时,输出信号不反相,当设置为Low时,输出信号反相之后再输出。最重要是是要使能TIMx的输出状态和使能TIMx的PWM输出使能。

    相关设置完成之后,就可以通过TIM_Cmd()来打开TIMx定时器,从而得到PWM输出了。

     

    3.     TIMER输出PWM源代码

    由于我现在手上的奋斗开发板是将PB.5接到LED上,因此需要使用TIM3的CH2通道,并且要进行引脚重映像。打开TIM3之后,PWM输出,使得LED点亮,通过改变PWM_cfg()中的占空比可以调节LED的亮度。

     

      1 #include "stm32f10x_lib.h"
      2 
      3  
      4 
      5 void RCC_cfg();
      6 
      7 void GPIO_cfg();
      8 
      9 void TIMER_cfg();
     10 
     11 void PWM_cfg();
     12 
     13 //占空比,取值范围为0-100
     14 
     15 int dutyfactor = 50;
     16 
     17  
     18 
     19 int main()
     20 
     21 {
     22 
     23      int Temp;
     24 
     25        RCC_cfg();
     26 
     27        GPIO_cfg();
     28 
     29        TIMER_cfg();
     30 
     31        PWM_cfg();
     32 
     33  
     34 
     35        //使能TIM3计时器,开始输出PWM
     36 
     37        TIM_Cmd(TIM3, ENABLE);
     38 
     39  
     40 
     41        while(1);
     42 
     43 }
     44 
     45  
     46 
     47 void RCC_cfg()
     48 
     49 {
     50 
     51        //定义错误状态变量
     52 
     53        ErrorStatus HSEStartUpStatus;
     54 
     55       
     56 
     57        //将RCC寄存器重新设置为默认值
     58 
     59        RCC_DeInit();
     60 
     61  
     62 
     63        //打开外部高速时钟晶振
     64 
     65        RCC_HSEConfig(RCC_HSE_ON);
     66 
     67  
     68 
     69        //等待外部高速时钟晶振工作
     70 
     71        HSEStartUpStatus = RCC_WaitForHSEStartUp();
     72 
     73        if(HSEStartUpStatus == SUCCESS)
     74 
     75        {
     76 
     77               //设置AHB时钟(HCLK)为系统时钟
     78 
     79               RCC_HCLKConfig(RCC_SYSCLK_Div1);
     80 
     81  
     82 
     83               //设置高速AHB时钟(APB2)为HCLK时钟
     84 
     85               RCC_PCLK2Config(RCC_HCLK_Div1);
     86 
     87  
     88 
     89               //设置低速AHB时钟(APB1)为HCLK的2分频
     90 
     91               RCC_PCLK1Config(RCC_HCLK_Div2);
     92 
     93              
     94 
     95               //设置FLASH代码延时
     96 
     97               FLASH_SetLatency(FLASH_Latency_2);
     98 
     99  
    100 
    101               //使能预取指缓存
    102 
    103               FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    104 
    105  
    106 
    107               //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz
    108 
    109               RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    110 
    111  
    112 
    113               //使能PLL
    114 
    115               RCC_PLLCmd(ENABLE);
    116 
    117  
    118 
    119               //等待PLL准备就绪
    120 
    121               while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    122 
    123  
    124 
    125               //设置PLL为系统时钟源
    126 
    127               RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    128 
    129  
    130 
    131               //判断PLL是否是系统时钟
    132 
    133               while(RCC_GetSYSCLKSource() != 0x08);
    134 
    135        }
    136 
    137  
    138 
    139        //开启TIM3的时钟
    140 
    141        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    142 
    143        //开启GPIOB的时钟和复用功能
    144 
    145        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
    146 
    147  
    148 
    149 }
    150 
    151  
    152 
    153 void GPIO_cfg()
    154 
    155 {
    156 
    157        GPIO_InitTypeDef GPIO_InitStructure;
    158 
    159  
    160 
    161       
    162 
    163        //部分映射,将TIM3_CH2映射到PB5
    164 
    165 //     GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
    166 
    167        GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
    168 
    169  
    170 
    171        //选择引脚5
    172 
    173        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    174 
    175        //输出频率最大50MHz                                                        
    176 
    177        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    178 
    179        //复用推挽输出                                              
    180 
    181       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    182 
    183  
    184 
    185        GPIO_Init(GPIOB,&GPIO_InitStructure);
    186 
    187 }
    188 
    189  
    190 
    191 void TIMER_cfg()
    192 
    193 {
    194 
    195        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    196 
    197  
    198 
    199        //重新将Timer设置为缺省值
    200 
    201        TIM_DeInit(TIM3);
    202 
    203        //采用内部时钟给TIM3提供时钟源
    204 
    205        TIM_InternalClockConfig(TIM3);
    206 
    207        //预分频系数为0,即不进行预分频,此时TIMER的频率为72MHz
    208 
    209        TIM_TimeBaseStructure.TIM_Prescaler = 0;
    210 
    211        //设置时钟分割
    212 
    213        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    214 
    215        //设置计数器模式为向上计数模式
    216 
    217        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    218 
    219        //设置计数溢出大小,每计7200个数就产生一个更新事件,即PWM的输出频率为10kHz
    220 
    221        TIM_TimeBaseStructure.TIM_Period = 7200 - 1;
    222 
    223        //将配置应用到TIM3中
    224 
    225        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
    226 
    227 }
    228 
    229  
    230 
    231 void PWM_cfg()
    232 
    233 {
    234 
    235        TIM_OCInitTypeDef TimOCInitStructure;
    236 
    237        //设置缺省值
    238 
    239        TIM_OCStructInit(&TimOCInitStructure);
    240 
    241        //PWM模式1输出
    242 
    243        TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    244 
    245        //设置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%
    246 
    247        TimOCInitStructure.TIM_Pulse = dutyfactor * 7200 / 100;
    248 
    249        //TIM输出比较极性高
    250 
    251        TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    252 
    253        //使能输出状态
    254 
    255        TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    256 
    257        //TIM3的CH2输出
    258 
    259        TIM_OC2Init(TIM3, &TimOCInitStructure);
    260 
    261        //设置TIM3的PWM输出为使能
    262 
    263        TIM_CtrlPWMOutputs(TIM3,ENABLE);
    264 
    265 }

     

  • 相关阅读:
    Vue blur事件优先级高于click事件
    常用的正则表达式
    vue-socket.io 3.0.9 的最新版本不能用
    nvm
    Webpack4:Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
    Echart 挪动滑块时,前端根据起始日期重新计算数据,造成了数据渲染错误
    Ant Design table 排序 ,点击头部只有升序和降序
    雷达图 点击事件
    修改远程仓库地址
    vue.cli发布不同的环境
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/5415175.html
Copyright © 2020-2023  润新知