历史上的今天
今天是:2025年08月20日(星期三)
2019年08月20日 | STM32——PWM基本知识及配置过程
2019-08-20 来源:eefocus
将通用定时器分为四个部分:
1,选择时钟
2,时基电路
3,输入捕获
4,输出比较
本节定时器PWM输出主要涉及到定时器框图右下方部分,即输出比较部分

和上一讲相同,时基时钟来源于内部默认时钟
对此有疑问请参考 : 定时器中断实验 中 定时器时钟选择部分 和 定时器时钟来源部分
什么是PWM
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
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为例)

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

通过设置模式1或模式2,决定了比较结果输出有效或无效电平
2,TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性

通过设置输出极性,确定有效或无效电平为最终输出的高电平或低电平
总结:
模式1:
CNT 模式2: CNT CC1P: 0:高电平有效 1:低电平有效 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,ARR立即生效 ARPE=0,ARR下周期生效 定时器3输出通道引脚 定时器3的4个通道对应的引脚及重映射 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,需要部分重映射 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,大小随意设定。






史海拾趣
|
急问: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写入了一次之后,就没办法写了怎么回事的?CCS连接之后点on-chip flash programmer,对话框全是灰色的,只有一个onlock按钮可以点,但是点了之后弹出unlock failed,CCS提示解锁失败,设备锁定。 但是上次烧写的时候我并没有改动 ...… 查看全部问答> |
|
在移植mtd-utils时遇到个问题,就是使用nandwrite写入文件系统的映像(jffs2格式)时,出现:Unknown flash (not normal NAND)错误,通过查看源码,这个错误是在程序中检测flash的页面大小处打印的, /* Make sure device page sizes are val ...… 查看全部问答> |
|
我正在学DSP,有几个问题: 关于C5416 外扩的FLASH型号该怎么选择,做音频处理的话,一般用什么型号的FLASH? C5416如何跟FLASH连接? 如何读取数据及存储数据? 希望和各位DSP的大牛们能帮帮我,非常感谢!… 查看全部问答> |
|
本人刚开始学uCOS系统,现在有一块S3C44B0X的板子,想把uCOS移植进去,于是在网上找了一些基于S3C44B0X的uCOS源码,但是不知道如何运用编译器把源码处理,自然也就不知道怎么把内核系统烧进板子,现在不知道如何下手,而且在网上找的资料都没有运用 ...… 查看全部问答> |
|
Pca采集的问题: 单片机C8051F120 我用Pca采集脉冲传感器个数,为什么进入单片机只有一个脉冲,而采集出来的是很多个呢?? Pca初始化: PCA0L = 0x00; PCA0H = 0x00; &nb ...… 查看全部问答> |




