1、PWM是什么?
( C) J% ^6 u' T/ [# x0 M& o& D- \/ i( R# e$ o0 [
是脉冲宽度调制,简称脉宽调制。利用微处理器数字输出对模拟电路进行控制的一种有效的技术,就是对脉冲宽度的控制。
+ o1 g8 b5 P% g) _" U* \6 b) U, ^7 x2 H' k# h% t# n }# y' C; I' P
这里说的脉冲,就是我们产生的方波。方波就是N个这样的周期连续的产生。 z1 h7 E" d9 B, R' _7 P' Q
9 @. B' J9 a" B7 ]
6 s! g9 n4 U5 `4 @7 m8 m+ [
4 P" L3 |( o; B X! S2 f
一个周期内高电平持续的时间就是脉冲宽度(脉宽),而PWM(脉冲宽度调制)就是控制一个周期内的高电平的持续时间。3 ^/ Q7 M8 g# L: |* S' F4 N6 v
i1 j% L' H! d
2、简单的PWM的原理示意图9 S, f8 j/ [$ z# Q7 U6 g. r+ M
S* ^/ R* {7 N8 {0 w9 l
* M! N% o9 ?) l) z# U3 O4 C; l; Q
6 R: w1 e }$ h; M% XCNT:是当前值寄存器,计数寄存器。3 B/ N" K. i1 O# \, C
- V3 F" q, S1 _ARR:是自动重载寄存器(初始化设定)。
4 ]7 S9 w4 e; Q1 j
6 [. f' [* j& S; |- YCCRx:比较值寄存器(TIM_SetCompare1()设定修改占空比)。# N f3 h: O1 E
1 L# e/ [0 j! \# `1 ]
( o* O6 v# T( X) p, O/ [
假定定时器工作在向上计数PWM模式下:
( |% R; l; j/ Z/ A" U
0 a+ Y8 m4 Q8 a3 _0 p当CNT<CCRx时,引脚输出0,当CNT>=CCRx时,引脚输出1。0 L1 F! ^, h1 y! C
0 N3 A$ d. c8 r
当CNT的值小于CCRx的时候,IO输出低电平(0),: G8 I2 P+ ~, J( B, y# n9 \
2 ^* v, Z3 H }% t4 ?
当CNT值大于或等于CCRx的时候,IO输出高电平(1),; j8 G$ I7 p" J* `# A+ \
& l5 Z. L: o. G+ k/ D/ C o: G
当CNT的值达到ARR的时候,就会重新归零,然后重新向上计数,依次循环。6 V, |+ b: e( s, a$ j) b$ u! y
) i1 O7 t r. a5 v改变CCRx的值就可以改变PWM的输出的占空比。改变ARR的值,就可以改变PWM的输出的频率,这就是PWM的输出原理。' X; D6 ~( x" v: @# S& V% a- ?7 c
$ S1 H! T, |9 s! Z3、寄存器工作流程:, u7 P* D; Q0 \: T
a4 H/ A) |3 b/ |& U+ Z
7 {& S7 i( y9 g+ i9 _0 W1 k: `7 c7 f/ K. S% c1 m3 ~, k' C
PWM 模式
& s- ]% m9 e+ j6 i" f! P! ~: j. ~1 \* {9 c( ?
脉冲宽度调制模式可以生成一个信号,该信号频率由 TIMx_ARR 寄存器值决定,其占空比由 TIMx_CCRx 寄存器值决定。
5 a: N' |8 S( I( R- I$ S& ^7 @2 d" }* F
通过向 TIMx_CCMRx 寄存器中的 OCxM 位写入 110(PWM 模式 1)或 111(PWM 模式 2) ,可以独立选择各通道 (每个 OCx 输出对应一个 PWM)的 PWM 模式。必须通过将TIMx_CCMRx 寄存器中的 OCxPE 位置 1 使能相应预装载寄存器,最后通过将 TIMx_CR1寄存器中的 ARPE 位置 1 使能自动重载预装载寄存器(在递增计数或中心对齐模式下)。
: I* ]+ Z/ h' B; H0 I" E
* V. ~; I `3 M7 c- h由于只有在发生更新事件时预装载寄存器才会传送到影子寄存器,因此启动计数器之前,必须通过将 TIMx_EGR 寄存器中的 UG 位置 1 来初始化所有寄存器。OCx 极性可使用 TIMx_CCER 寄存器的 CCxP 位来编程。既可以设为高电平有效,也可以设为低电平有效。 OCx 输出通过将 TIMx_CCER 寄存器中的 CCxE 位置 1 来使能。有关详细信息,请参见 TIMx_CCERx 寄存器说明在 PWM 模式(1 或 2)下, TIMx_CNT 总是与 TIMx_CCRx 进行比较,以确定是TIMx_CNT =< TIMx_CCRx。- b) D( J6 C/ ?1 M3 s8 G. P1 k
9 ~8 e2 l) x( M7 h' H+ a因为计数器采用递增方式计数,所以定时器能够在边沿对齐模式下生成 PWM。4 y" K, \: \! [
% x, q, N% {, k6 C7 z/ j4、PWM 边沿对齐模式5 l0 G# [% I6 l' y! ]5 @ x
) L8 F. d) `/ h B以下以 PWM 模式 1 为例。只要 TIMx_CNT < TIMx_CCRx, PWM 参考信号 OCxREF 便为高电平,否则为低电平。如果 TIMx_CCRx 中的比较值大于自动重载值(TIMx_ARR 中),则 OCxREF 保持为“1”。如果比较值为 0, 则 OCxRef 保持为“0”。 图 183 举例介绍边沿对齐模式的一些 PWM 波形 (TIMx_ARR=8)。
7 D: {# \/ L/ b* J5 R) `/ @% |1 v( ^: I& P9 i r! c# a
/ V% b, P% K. o9 { L4 \
; J4 Q, i; |: ?9 N: U9 B9 u5、PWM步骤-灯光亮度控制:$ f+ a+ t/ n# l' w k7 H
1 d, J' u) x& W% y! u, h- a% h8 u 查看LED的原理图:8 B3 `& Z% v1 {: Q: [. y+ b
( L' _6 a% H- o. M2 D" `
/ |7 \% U; n2 w
X! c6 q9 F; \3 J
+ K- D( o. V+ N( C% W! ?- //①根据原理图找到4个引脚:) z* z6 \" l ?3 ^( R( c, l: P
- PF9可以使用TIM14_CH1,表示可以使用定时器14的通道1产生PWM输出。; z' M4 \) u$ C5 X! z: \2 J
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; // 定义的TIM属性结构体变量0 j1 A! q: i6 @* S9 W \
- GPIO_InitTypeDef GPIO_InitStruct; // 定义GPIO类型变量, [3 E% o0 q; a: L+ G4 {) [, X
- TIM_OCInitTypeDef TIM_OCInitStruct; // 定义复用功能的变量
4 N( C* }; s% M
; W, L$ B, F9 B! v& {% L- ②// 1.初始化时钟:TIM14 和 PF95 ?( ]) S! R6 z# `3 \% }: t2 O
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);; D4 Q; a6 G/ M H z/ i2 c/ t0 ^0 v1 G
- j+ D# n) y6 l& W( W" B
- /* TIM3 clock enable */
7 H Z$ ^8 }. ^ A# b$ D - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
4 V& I+ q* }* _
3 m ]5 M% t- ?$ O! C! y1 m& Y7 B' R- // 2.配GPIO引脚为复用功能
5 x# K3 ^8 ^$ }! F( a: Q# O - /* GPIOC Configuration: TIM14 CH1 (PF9) */
1 A8 B3 v; W/ S; M8 {5 g/ k - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; // 选择引脚为PF98 S# G+ i$ N+ [& Y# f8 o" K
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 设置为复用功能4 }1 J$ b4 N# R) j
- GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed; // 设置输出速度为100MHz9 K7 k j5 o" v" i4 T! j
- GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // 设置为推挽输出1 F! J& e+ m1 M0 k9 [! ~
- GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 设置为上拉输出
: U" c+ `+ A' C2 _# j8 S0 o - GPIO_Init(GPIOC, &GPIO_InitStruct); // 安装参数
, `" f9 O# [0 o8 a: d# M, a
- {" Y: R2 u0 M- n O9 G5 j0 n- // 3.将TIM和引脚的复用功能连接:TIM14和PF9连接起来
+ F' ?" i" a: \ a) t1 Q - GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);+ O; Q9 f5 N! R4 W) |
- * s+ K7 A8 X2 @6 x5 k9 x5 q
- // 4.配置TIM定时器的参数1 z' p, w% I) R# m) T, f1 D! d# h
- TIM_TimeBaseInitStruct.TIM_Period = 100-1; // 设置重装载值 ARR(控制频率)7 O( ~/ ~; s; b4 J* W F1 Z
- TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1; // 设置预分频系数:周期(次) 100Hz == 100us- Q7 m% ^) A4 f% B+ F
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 设置再分频值:TIM_CKD_DIV1就是不分频- k8 G! X9 D7 x* N6 b, \
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式- o* X( ~; _0 h: u
- TIM_TimeBaseInit(TIM14, &TIM_TimeBaseInitStruct);' z8 g/ R4 `+ q" w: w, O
: B3 @1 g4 j- a: q- // 5.配置复用功能:PWM
" ^3 b: U a4 Q3 P9 @ - TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // 配置为PWM模式15 ?, M! G1 `" c7 P. Q( t2 P5 o
- TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; // 开启输出使能5 n: \5 i7 s- y; _' j
- //TIM_OCInitStruct.TIM_Pulse = CCR1_Val; // 初始化配置比较值寄存器
0 H5 L* d9 p% x - TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 配置为高电平有效
% Z7 j) L3 Z2 B* Q - " v# Y* K+ B8 M& n3 y7 U5 m1 p0 |
- // 6.TIM14通道1初始化/ f d$ n4 p* Y7 n1 F& w8 [3 V$ B
- TIM_OC1Init(TIM14, &TIM_OCInitStruct); // TIM14通道1初始化' M$ r, U8 |& u9 b
- 5 g9 x2 e' ]( O$ w5 Z9 s
- // 7.设置自动重载比较值CCR1初值,不断产生PWM脉冲1 D3 I% R+ S5 P* v
- TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);% |* B8 o3 ]+ ?1 U6 M, C
4 D$ M7 m1 s) B0 P1 u- , G& `+ `, f" u$ W
- // 8.设置自动重装载值(ARR),不断产生PWM脉冲+ w6 J% ^$ I; N/ k# r
- TIM_ARRPreloadConfig(TIM14, ENABLE);0 n. q2 q) s' C P* w6 V3 @
& y8 H& L" o1 \" z0 `/ J* c- /* 9.使能定时器14 */
+ z9 T. c% x* @' G - TIM_Cmd(TIM14, ENABLE);. [2 e; s# j3 \. r
- ! l. k! `- q+ V1 c* B& n( g. H7 Y
- // 10.使能TIM1PWM输出(高级定时器)" C* }% {8 T2 v
- //TIM_CtrlPWMOutputs(TIM1, ENABLE)3 ], t' u% m( n1 o' n
! @1 T) I+ i4 y% V
复制代码
; ?6 n$ }7 |8 F设置比较值函数
' z! t( `! j' f6 T" w$ k
. a" [' u3 B5 e( n* h. B9 B- void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);
复制代码 ) |; R9 G3 c/ `6 Q0 y
' W( [- f0 ]: S _' v, [
" ]/ n2 H) u' p/ v8 ?
|