历史上的今天
返回首页

历史上的今天

今天是:2025年08月20日(星期三)

正在发生

2019年08月20日 | STM32——PWM基本知识及配置过程

2019-08-20 来源:eefocus


将通用定时器分为四个部分:

      1,选择时钟

      2,时基电路

      3,输入捕获

      4,输出比较

本节定时器PWM输出主要涉及到定时器框图右下方部分,即输出比较部分


输出比较部分框图

和上一讲相同,时基时钟来源于内部默认时钟


对此有疑问请参考 : 定时器中断实验 中 定时器时钟选择部分 和 定时器时钟来源部分


什么是PWM

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

PWM工作过程

每个定时器有四个通道,每一个通道都有一个捕获比较寄存器, 

将寄存器值和计数器值比较,通过比较结果输出高低电平,实现PWM信号


先简单说明一下: 


PWM简单说明

如图为向上计数:

     定时器重装载值为ARR,比较值CCRx

     t时刻对计数器值和比较值进行比较

     如果计数器值小于CCRx值,输出低电平

     如果计数器值大于CCRx值,输出高电平

 

PWM的一个周期

    定时器从0开始向上计数

    当0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平

    t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平

    当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数...循环此过程

    至此一个PWM周期完成

 

影响因素

    ARR : 决定PWM周期(在时钟频率一定的情况下,当前为默认内部时钟CK_INT)

    CCRx : 决定PWM占空比(高低电平所占整个周期比例)

PWM工作过程(以通道1为例)

PWM工作过程

1,TIMx_CCMR1寄存器的OC1M[2:0]位,设置输出模式控制器

    110:PWM模式1

    111:PWM模式2

 

2,计数器值TIMx_CNT与通道1捕获比较寄存器CCR1进行比较,通过比较结果输出有效电平和无效电平

    OC1REF=0 无效电平

    OC1REF=1 无效电平

 

3,通过输出模式控制器产生的信号

TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性

    0:高电平有效

    1:低电平有效

 

4,TIMx_CCER:CC1E位控制输出使能电路,信号由此输出到对应引脚

    0:关闭

    1:开启

PWM如何输出高低电平

计数器值TIMx_CNT与捕获比较寄存器值CCRx比较后,最终输出高电平还是低电平, 

由TIMx_CCMR1:OC1M位和TIMx_CCER:CC1P位共同决定


1,TIMx_CCMR1寄存器的OC1M[2:0]位,设置PWM模式1或模式2


CCMR1

通过设置模式1或模式2,决定了比较结果输出有效或无效电平


2,TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性


CCER

通过设置输出极性,确定有效或无效电平为最终输出的高电平或低电平


总结:

     模式1:

          CNT          CNT>CCR为无效电平 //(OC1REF = 0)

     模式2:

          CNT          CNT>CCR为有效电平 //(OC1REF = 1)

     CC1P:

          0:高电平有效

          1:低电平有效


PWM模式总结

PWM模式配置

PWM模式配置

TIM_OC1PreloadConfig函数:

     作用:TIM_CCMRx寄存器OCxPE位使能相应的预装在寄存器

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

 

TIM_ARRPreloadConfig函数:

     作用:操作TIMx_CR1寄存器ARPE位,使能自动重装载的预装载寄存器

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

ARPE的使能-ARR变更生效配置


ARPE=1

ARPE=0

ARPE=1,ARR立即生效

ARPE=0,ARR下周期生效

定时器3输出通道引脚

定时器3的4个通道对应的引脚及重映射


定时器3输出通道引脚

PWM输出库函数

1,定时器通道初始化-TIM_OC1Init

经过上面的讲解,我们知道了要想使用PWM需要配置


配置参数对应框图位置如下:


定时器通道初始化

1,TIMx_CCMR1寄存器的OC1M[2:0]位,设置输出模式控制器

2,TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性

3,TIMx_CCER:CC1E位控制输出使能电路,信号由此输出到对应引脚

初始化定时器输出比较通道


void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);


TIM_OCInitTypeDef结构体


typedef struct

{

  uint16_t TIM_OCMode;         // PWM模式1或者模式2

  uint16_t TIM_OutputState;    // 输出使能 OR失能

  uint16_t TIM_OutputNState;   // PWM输出不需要

  uint16_t TIM_Pulse;          // 比较值,写CCRx,可以有次函数

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

写入,这里暂时不设置。 

 uint16_t TIM_OCPolarity; // 比较输出极性 

  uint16_t TIM_OCNPolarity; // PWM输出不需要 

  uint16_t TIM_OCIdleState; // PWM输出不需要 

  uint16_t TIM_OCNIdleState; // PWM输出不需要

 } TIM_OCInitTypeDef;

 


2,设置比较值函数-TIM_SetCompare1

作用:外部改变TIM_Pulse值,即改变CCR的值


void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);


3,使能输出比较预装载-TIM_OC1PreloadConfig

作用:TIM_CCMRx寄存器OCxPE位使能相应的预装在寄存器


void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);


4,使能自动重装载的预装载寄存器允许位-TIM_ARRPreloadConfig

作用:操作TIMx_CR1寄存器ARPE位,使能自动重装载的预装载寄存器


void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);


5,修改通道极性

作用:操作TIMx_CCER的CC1P位,修改通道极性


void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);


PWM输出实验

使用定时器3初始PWM信号,输出占空比可变的PWM波驱动LED(PB5引脚),实现LED亮度变换


LED:低电平点亮,高电平熄灭,占空比越大,一个周期中高电平持续时间越长,亮度越大,反之越暗.


查找手册PB5引脚为定时器3的通道2,需要部分重映射


TIM3引脚重映射

PWM输出实验步骤

1,使能定时器3和相关IO时钟(LED-PB5)

    使能定时器3时钟:RCC_APB1PeriphClockCmd();

    使能GPIOB时钟:RCC_APB2PeriphClockCmd();

 

2,初始化IO口为复用功能输出 GPIO_Init();

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

 

3,PB5输出PWM(定时器3通道2),需要部分冲突映射

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟设置

    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//部分重映射

 

4,初始化定时器 (重装载值ARR,与分频系数PSC等)

    TIM_TimeBaseInit();//决定PWM周期

 

5,初始化输出比较参数:

    TIM_OC2Init();//通道2输出比较初始化

 

6,使能预装载寄存器

    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);//定时器3 通道2

 

7,使能定时器

    TIM_Cmd();

 

8,不断改变比较值CCRx,达到不同的占空比效果

    TIM_SetCompare2(); //通道2,改变比较值CCRx

代码实现

基于 定时器中断实验 代码进行编写


timer.h添加PWM初始化函数定义 void TIM3_PWM_Init(u16 arr,u16 psc);


#ifndef  __TIMER_H

#define  __TIMER_H

#include "sys.h"


void TIM3_PWM_Init(u16 arr,u16 psc);


#endif



timer.c 实现定时器PWM初始化函数


#include "timer.h"


//TIM3 PWM初始化

//arr   重装载值

//psc   预分频系数

void TIM3_PWM_Init(u16 arr,u16 psc)

{

    GPIO_InitTypeDef     GPIO_InitStrue;

    TIM_OCInitTypeDef     TIM_OCInitStrue;

    TIM_TimeBaseInitTypeDef     TIM_TimeBaseInitStrue;

    

    

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);        //使能TIM3和相关GPIO时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 使能GPIOB时钟(LED在BP5引脚),使能AFIO时钟(定时器3通道2需要重映射到BP5引脚)

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

    

    GPIO_InitStrue.GPIO_Pin=GPIO_Pin_5;     // TIM_CH2

    GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;    // 复用推挽

    GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;    //设置最大输出速度

    GPIO_Init(GPIOB,&GPIO_InitStrue);                //GPIO端口初始化设置

    

    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);

    

    TIM_TimeBaseInitStrue.TIM_Period=arr;    //设置自动重装载值

    TIM_TimeBaseInitStrue.TIM_Prescaler=psc;        //预分频系数

    TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up;    //计数器向上溢出

    TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1;        //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1

    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue);        //TIM3初始化设置(设置PWM的周期)

    

    TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM2;        // PWM模式2:CNT>CCR时输出有效

    TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效为高电平

    TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能

    TIM_OC2Init(TIM3,&TIM_OCInitStrue);        //TIM3的通道2PWM 模式设置


    TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);        //使能预装载寄存器

    

    TIM_Cmd(TIM3,ENABLE);        //使能TIM3

    

}

主程序的设计:


进行pwm的设置


  TIM_SetCompare2(TIM3,led0pwmval);        //改变比较值TIM3->CCR2达到调节占空比的效果



int main(void)

 {    

    u8 i=1;         // 设置方向 0:变暗 1:变亮

    u16 led0pwmval;        // 设置CCR值

    delay_init();             // 延时函数初始化

    LED_Init();                // LED初始化

    TIM3_PWM_Init(899,0); //设置频率为80KHz,公式为:溢出时间Tout=(arr+1)(psc+1)/Tclk

                                                //Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ

                                                //PWM时钟频率=72000000/(899+1) = 80KHZ,设置自动装载值899,预分频系数0(不分频)

    while(1)

    {    

        delay_ms(10);            

        if(i)led0pwmval++;        // 由暗变亮

            else led0pwmval--;        // 由亮变暗

        

        if(led0pwmval==0)i=1;        // 已达到最亮,开始变暗

        if(led0pwmval>100)i=0;    // 已达到最暗,开始变亮

        

        TIM_SetCompare2(TIM3,led0pwmval);        //改变比较值TIM3->CCR2达到调节占空比的效果

        

    }

 }

//此处led0pwmval值最大可以设置到899,输出pwm波基本全为1,大小随意设定。


推荐阅读

史海拾趣

General Instrument公司的发展小趣事
保持设备运行环境的温湿度适宜,定期清理灰尘。
承兴(CX)公司的发展小趣事

进入21世纪,承兴公司不满足于现状,开始寻求跨界合作的机会。2000年,承兴成为诺基亚中国区合作伙伴,共同推出了一系列定制化的电子产品。这一合作不仅提升了承兴的品牌影响力,也为其带来了更多的商业机会。随后,承兴还与中国石油、建设银行等大型企业和金融机构建立了合作关系,进一步拓展了其业务范围。

DALLAS公司的发展小趣事

Dallas公司一直将技术研发作为公司发展的核心驱动力。公司投入大量资源用于半导体领域的技术研发,不断探索新的技术方向和产品应用。这种持续的技术研发投入使得Dallas公司能够不断推出具有创新性和竞争力的产品,保持了在市场中的领先地位。

Hoffman_Enclosures__Inc.公司的发展小趣事

面对客户日益多样化的需求,Hoffman提供了超过12,000种标准产品以及量身定制的解决方案。公司拥有一支专业的研发团队和完善的生产体系,能够根据客户的具体需求,快速设计出符合要求的电气机柜和温控产品。这种灵活的定制化服务不仅满足了客户的个性化需求,也进一步增强了客户对公司的信任和忠诚度。

Analog Microwave Design公司的发展小趣事

随着市场的不断变化和客户需求的多样化,Analog Microwave Design公司意识到单一的产品线已经无法满足市场需求。为了丰富和完善产品线,公司开始加大对新产品的研发力度。除了继续深耕微波器件领域外,公司还积极拓展相关领域的产品线,如射频模块、天线等。通过不断推出新产品,公司不仅满足了客户的多样化需求,还进一步巩固了市场地位。

Excel Cell Electronic Co Ltd公司的发展小趣事

为了拓展海外市场,ECE公司制定了国际化战略。公司积极参与国际电子展会,与国际知名企业建立合作关系,不断提升品牌知名度和国际影响力。同时,ECE公司在海外设立分支机构,加强与国际市场的联系和沟通,进一步拓展市场份额。这些努力使ECE公司的产品成功进入欧洲、北美等发达地区市场,实现了全球化布局。

问答坊 | AI 解惑

我想问下为什么要在单片机的i/o0上加上啦电阻

为啥要在i/op.0上的管脚加上拉电阻??…

查看全部问答>

急问:MP3电路原理图!请教高手,帮我分析下这个MP3原理图中各个组成部分的原理、处理器的功能。

http://blog.ednchina.com/Upload/Blog/2007/3/30/826adf84-7829-4de7-8065-2149d80d0c85.jpg 请高手帮我分析下这个MP3原理图中各个组成部分的原理、处理器的功能。 谢谢!…

查看全部问答>

求助Could not find file 'C:\WINCE500\PBWorkspaces\e\RelDir\Geode_x86_Release\MyDri

Could not find file \'C:\\WINCE500\\PBWorkspaces\\e\\RelDir\\Geode_x86_Release\\MyDriver.exe\' on disk 在生成操作系统镜像的时候出现的问题 怎么解决啊 是编译的过程中出现的问题 …

查看全部问答>

弱弱的问一个问题,Windows中的WinInet API在Window Mobile中能用吗?

例如HttpSendRequest、InternetReadFile之类的函数。 如果不可以,是否手机就不能通过http协议请求某个服务器的数据?…

查看全部问答>

2812的flash怎么写不进去了

我的2812芯片flash写入了一次之后,就没办法写了怎么回事的?CCS连接之后点on-chip flash programmer,对话框全是灰色的,只有一个onlock按钮可以点,但是点了之后弹出unlock failed,CCS提示解锁失败,设备锁定。 但是上次烧写的时候我并没有改动 ...…

查看全部问答>

mtd-utils的nandwrite问题

在移植mtd-utils时遇到个问题,就是使用nandwrite写入文件系统的映像(jffs2格式)时,出现:Unknown flash (not normal NAND)错误,通过查看源码,这个错误是在程序中检测flash的页面大小处打印的,  /* Make sure device page sizes are val ...…

查看全部问答>

大家有谁知道430F1612 驱动在哪里有啊?

大家有谁知道430F1612 驱动在哪里有啊? USB的 发到我邮箱里吧,或者QQ上也行。谢谢。我的QQ78468469…

查看全部问答>

求教 DSP 外扩 FLASH 的问题

我正在学DSP,有几个问题: 关于C5416 外扩的FLASH型号该怎么选择,做音频处理的话,一般用什么型号的FLASH? C5416如何跟FLASH连接? 如何读取数据及存储数据? 希望和各位DSP的大牛们能帮帮我,非常感谢!…

查看全部问答>

新手求助!关于uCOS移植到S3C44B0X问题 不甚感激

本人刚开始学uCOS系统,现在有一块S3C44B0X的板子,想把uCOS移植进去,于是在网上找了一些基于S3C44B0X的uCOS源码,但是不知道如何运用编译器把源码处理,自然也就不知道怎么把内核系统烧进板子,现在不知道如何下手,而且在网上找的资料都没有运用 ...…

查看全部问答>

Pca脉冲次数采集求助????

Pca采集的问题: 单片机C8051F120 我用Pca采集脉冲传感器个数,为什么进入单片机只有一个脉冲,而采集出来的是很多个呢?? Pca初始化: PCA0L    = 0x00;        PCA0H    = 0x00;    &nb ...…

查看全部问答>