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的亮度。

 #include "stm32f10x_lib.h"

 void RCC_cfg();

 void GPIO_cfg();

 void TIMER_cfg();

 void PWM_cfg();

 //占空比,取值范围为0-100

 int dutyfactor = ;

 int main()

 {

      int Temp;

        RCC_cfg();

        GPIO_cfg();

        TIMER_cfg();

        PWM_cfg();

        //使能TIM3计时器,开始输出PWM

        TIM_Cmd(TIM3, ENABLE);

        while();

 }

 void RCC_cfg()

 {

        //定义错误状态变量

        ErrorStatus HSEStartUpStatus;

        //将RCC寄存器重新设置为默认值

        RCC_DeInit();

        //打开外部高速时钟晶振

        RCC_HSEConfig(RCC_HSE_ON);

        //等待外部高速时钟晶振工作

        HSEStartUpStatus = RCC_WaitForHSEStartUp();

        if(HSEStartUpStatus == SUCCESS)

        {

               //设置AHB时钟(HCLK)为系统时钟

               RCC_HCLKConfig(RCC_SYSCLK_Div1);

               //设置高速AHB时钟(APB2)为HCLK时钟

               RCC_PCLK2Config(RCC_HCLK_Div1);

               //设置低速AHB时钟(APB1)为HCLK的2分频

               RCC_PCLK1Config(RCC_HCLK_Div2);

               //设置FLASH代码延时

               FLASH_SetLatency(FLASH_Latency_2);

               //使能预取指缓存

               FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

               //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz

               RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

               //使能PLL

               RCC_PLLCmd(ENABLE);

               //等待PLL准备就绪

               while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

               //设置PLL为系统时钟源

               RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

               //判断PLL是否是系统时钟

               while(RCC_GetSYSCLKSource() != 0x08);

        }

        //开启TIM3的时钟

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

        //开启GPIOB的时钟和复用功能

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);

 }

 void GPIO_cfg()

 {

        GPIO_InitTypeDef GPIO_InitStructure;

        //部分映射,将TIM3_CH2映射到PB5

 //     GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);

        GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);

        //选择引脚5

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

        //输出频率最大50MHz                                                        

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        //复用推挽输出                                              

       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 

        GPIO_Init(GPIOB,&GPIO_InitStructure);

 }

 void TIMER_cfg()

 {

        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

        //重新将Timer设置为缺省值

        TIM_DeInit(TIM3);

        //采用内部时钟给TIM3提供时钟源

        TIM_InternalClockConfig(TIM3);

        //预分频系数为0,即不进行预分频,此时TIMER的频率为72MHz

        TIM_TimeBaseStructure.TIM_Prescaler = ;

        //设置时钟分割

        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

        //设置计数器模式为向上计数模式

        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

        //设置计数溢出大小,每计7200个数就产生一个更新事件,即PWM的输出频率为10kHz

        TIM_TimeBaseStructure.TIM_Period =  - ;

        //将配置应用到TIM3中

        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);

 }

 void PWM_cfg()

 {

        TIM_OCInitTypeDef TimOCInitStructure;

        //设置缺省值

        TIM_OCStructInit(&TimOCInitStructure);

        //PWM模式1输出

        TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

        //设置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%

        TimOCInitStructure.TIM_Pulse = dutyfactor *  / ;

        //TIM输出比较极性高

        TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

        //使能输出状态

        TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

        //TIM3的CH2输出

        TIM_OC2Init(TIM3, &TimOCInitStructure);

        //设置TIM3的PWM输出为使能

        TIM_CtrlPWMOutputs(TIM3,ENABLE);

 }

(五)转载:通用定时器PWM输出的更多相关文章

  1. STM32(7)——通用定时器PWM输出

    1.TIMER输出PWM基本概念         脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种 ...

  2. NUCLEO-L053R8 TIM定时器 PWM输出

    TIM2 PWM输出测试 今天给大伙分享一个TIM2 PWM输出小实验. 实验开发板:Nucleo-L053R8,即STM32L053R8T6. 开发环境:MDK5 图1 - 工程界面 本次实验测试的 ...

  3. STM32学习笔记(五)——通用定时器计数延时

    STM32定时器概述 STM32F40x系列总共最多有14个定时器,定时器分为三类:基本定时器.通用定时器和高级定时器.它们的都是通过计数来达到定时的目的,和51的定时器差不多,基本原理都是一样的,就 ...

  4. STM32F103ZET6 PWM输出

    1.通用定时器的PWM功能 STM32F103ZET6有4个通用定时器,分别是TIM2.TIM3.TIM4.TIM5. 通用定时器由一个可编程预分频器驱动的16位自动装载计数器构成. 通用定时器的很多 ...

  5. STM32通用定时器(转载)

    STM32的定时器功能很强大,学习起来也很费劲儿. 其实手册讲的还是挺全面的,只是无奈TIMER的功能太复杂,所以显得手册很难懂,我就是通过这样看手册:while(!SUCCESS){看手册-}才搞明 ...

  6. 关于普通定时器与高级定时器的 PWM输出的初始化的区别

    不管是普通定时器还是高级定时器,你用哪个通道,就在程序里用OC多少.比如CH3对应OC3 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  TIM_ ...

  7. STM32 HAL库学习系列第4篇 定时器TIM----- 开始定时器与PWM输出配置

    基本流程: 1.配置定时器 2.开启定时器 3.动态改变pwm输出,改变值  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); 函数总结: __HAL_TIM ...

  8. 基于STM32F429和Cube的主从定时器多通道输出固定个数的PWM波形

    主从定时器的原理已在上篇博文: 基于STM32F429+HAL库编写的定时器主从门控模式级联输出固定个数PWM脉冲的程序 讲解了,这篇重点就讲如何实现多通道的PWM级联输出. 1.软件环境 Keil5 ...

  9. 合宙AIR105(三): 定时器, 定时器中断和PWM输出

    目录 合宙AIR105(一): Keil MDK开发环境, DAP-Link 烧录和调试 合宙AIR105(二): 时钟设置和延迟函数 合宙AIR105(三): 定时器, 定时器中断和PWM输出 Ai ...

随机推荐

  1. C#文件复制功能

    目的是将用户自定义文件复制到指定文件夹并且能查看该文件,下面是个人做的源码: sing System; using System.Collections.Generic; using System.C ...

  2. 5种风格的 jQuery 分页效果【附代码】

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...

  3. Stream Byte[] 转换

    public byte[] StreamToBytes(Stream stream) { byte[] bytes = new byte[stream.Length]; stream.Read(byt ...

  4. set集合类型 redis

    向名称为key的set中添加元素: 命令:sadd                      #不允许有重复的值 2 删除名称为key的set中的元素: 命令:srem 3 随机返回并删除名称称为ke ...

  5. Spring实战学习笔记之SpEL表达式

            在Spring XML配置文件中装配Bean的属性和构造参数都是静态的,而在运行期才知道装配的值,就可以使用SpEL实现         SpEL表达式的首要目标是通过计算获得某个值. ...

  6. 使用migrate.exe执行EF code first 迁移

    Code First 迁移可用于从 Visual Studio 内部更新数据库,但也可通过命令行工具 migrate.exe 来执行.本页简单介绍如何使用 migrate.exe 对数据库执行迁移. ...

  7. [转]Linux进程间通信——使用信号

    转载于:http://blog.csdn.net/ljianhui/article/details/10128731         经典!!! Linux进程间通信——使用信号 一.什么是信号 用过 ...

  8. AngularJS--学习笔记(一)

    AngularJS官方网站提供了一个用于学习的示例项目:PhoneCat.这是一个Web应用,用户可以浏览一些Android手机,了解它们的详细信息,并进行搜索和排序操作. 对于PhoneCat项目的 ...

  9. thinkphp中模块和操作映射

    模板和操作映射功能是3.1.2版本支持的对模块和操作设置的映射机制,由于可以通过改变配置动态改变(实际真正改变,并非别名)URL访问地址,加强了应用的安全性,而且,映射机制具有URL不区分大小写访问的 ...

  10. HDU 1062 Text Reverse(水题,字符串处理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1062 解题报告:注意一行的末尾可能是空格,还有记得getchar()吃回车符. #include< ...