1、PWM是什么?; W) ^3 u0 T) k* c* e4 D# m
) s1 j; V/ d: J! H3 q! I: t' X6 U! V 是脉冲宽度调制,简称脉宽调制。利用微处理器数字输出对模拟电路进行控制的一种有效的技术,就是对脉冲宽度的控制。( H0 Q: T2 S4 }2 o# f, x
( m! U6 z* q( _- v; ~6 l
这里说的脉冲,就是我们产生的方波。方波就是N个这样的周期连续的产生。
8 ?3 L. }; a% S9 D M
4 u+ r' }3 S: C4 P
* B7 h/ B/ ?4 ~$ d4 V3 }
8 ~' }6 W5 `. P% r0 V. s5 `% ~一个周期内高电平持续的时间就是脉冲宽度(脉宽),而PWM(脉冲宽度调制)就是控制一个周期内的高电平的持续时间。/ S: V# a2 |$ E; a! ]
; K$ q; r$ b2 Y/ n. m5 z# n# G2、简单的PWM的原理示意图
! j* N& Z3 J Q& G
& j) B# O' h! a/ K$ U
) l! @4 A0 d0 W
k# I- e3 J8 U% q5 L: T
CNT:是当前值寄存器,计数寄存器。, U- _* u, p( J$ ]$ v# }# N, I
% [! s5 |+ i3 g% D( F6 }& EARR:是自动重载寄存器(初始化设定)。; f( U, g4 [, N5 ]* v$ J
0 W1 v, t- {+ S% E2 DCCRx:比较值寄存器(TIM_SetCompare1()设定修改占空比)。
; [) {- F g9 ~1 W3 O% Z6 X3 @0 E2 y! p( T+ }& I6 L6 i" h
6 ?! G4 d5 a! ]
假定定时器工作在向上计数PWM模式下:) }, H( W6 J9 L% E& A
3 m- p* L' |( N& d
当CNT<CCRx时,引脚输出0,当CNT>=CCRx时,引脚输出1。; S: k8 Z* j6 b' {) Y
* c; M4 V! ?$ S" [1 L4 u' `, m1 t当CNT的值小于CCRx的时候,IO输出低电平(0),) m y V: A% ~/ N% S
/ G" E. U" c6 m6 R2 G" ^/ w
当CNT值大于或等于CCRx的时候,IO输出高电平(1),
: Y% p# v$ Z4 {6 _8 U! W; Q( K
/ o* F6 L+ @: f3 D当CNT的值达到ARR的时候,就会重新归零,然后重新向上计数,依次循环。
5 l0 B3 W7 J9 q) o/ z' u+ S
6 J8 X0 {/ C4 c1 v$ B% h+ H% m改变CCRx的值就可以改变PWM的输出的占空比。改变ARR的值,就可以改变PWM的输出的频率,这就是PWM的输出原理。
2 l ^: g' \' L6 P6 {
' Y( Y( \$ D3 R3、寄存器工作流程:$ F( b& G4 N0 |
% i+ y, N2 K6 J* a6 i: P' U+ r
8 L) b7 A9 p$ V2 [ @$ P
& \& m! C9 Q8 Y
PWM 模式
" \( R7 g/ a7 B k% u1 b; f$ z }* O& b7 Y; ?% Y6 _
脉冲宽度调制模式可以生成一个信号,该信号频率由 TIMx_ARR 寄存器值决定,其占空比由 TIMx_CCRx 寄存器值决定。
2 _" v! | f3 c1 L: e1 O
0 i# N( p: i$ u0 y) j/ S8 L& f通过向 TIMx_CCMRx 寄存器中的 OCxM 位写入 110(PWM 模式 1)或 111(PWM 模式 2) ,可以独立选择各通道 (每个 OCx 输出对应一个 PWM)的 PWM 模式。必须通过将TIMx_CCMRx 寄存器中的 OCxPE 位置 1 使能相应预装载寄存器,最后通过将 TIMx_CR1寄存器中的 ARPE 位置 1 使能自动重载预装载寄存器(在递增计数或中心对齐模式下)。4 E* B }! a7 o" Q
! t1 d0 K$ u, g* Z: G/ {! l/ s2 L
由于只有在发生更新事件时预装载寄存器才会传送到影子寄存器,因此启动计数器之前,必须通过将 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。
# m( S9 } }8 W3 r; b4 A
5 t* e) i0 d. Q5 Y因为计数器采用递增方式计数,所以定时器能够在边沿对齐模式下生成 PWM。
6 E( r e8 v. Q& `9 I/ L2 H) x6 Y6 T& q e1 U* a" c3 d
4、PWM 边沿对齐模式( r. e% I6 q! N; I
8 q" W) K# N, A. u/ u# p6 i/ `$ ]以下以 PWM 模式 1 为例。只要 TIMx_CNT < TIMx_CCRx, PWM 参考信号 OCxREF 便为高电平,否则为低电平。如果 TIMx_CCRx 中的比较值大于自动重载值(TIMx_ARR 中),则 OCxREF 保持为“1”。如果比较值为 0, 则 OCxRef 保持为“0”。 图 183 举例介绍边沿对齐模式的一些 PWM 波形 (TIMx_ARR=8)。
% D2 h' ~8 L' z+ i
% ?3 P% @+ ~( _3 {
) a- T9 ]6 w& T4 V, c+ I% {1 T; ?7 ]3 e/ P1 q- P0 I. o+ Y+ y0 _
5、PWM步骤-灯光亮度控制:. H/ y- U& C9 j+ U- ~3 T) X; X+ d+ L3 b
/ q" w% q" t: E$ u& c5 C; }" w' B 查看LED的原理图:
0 g7 X1 g5 J. B: R9 K( j# f
- X1 y/ x/ j% _
" b8 {7 L! _0 |8 z# x) H6 t6 T9 G
( {0 D G5 F$ s0 |- _
7 ^6 h* l) M5 O5 \- //①根据原理图找到4个引脚:' A" ~: @/ G: U: e( U5 x
- PF9可以使用TIM14_CH1,表示可以使用定时器14的通道1产生PWM输出。" R) J% `, ~, h) Y! H% d
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; // 定义的TIM属性结构体变量; q0 n2 d/ `$ K! ~2 A4 g: F
- GPIO_InitTypeDef GPIO_InitStruct; // 定义GPIO类型变量6 n8 Q; P5 J: w
- TIM_OCInitTypeDef TIM_OCInitStruct; // 定义复用功能的变量' |# W6 @: p2 t" B; O o
' S9 W& t' n' F# a3 ~* A: n- ②// 1.初始化时钟:TIM14 和 PF9
) _2 ~" V2 h; b. q" X. ~2 S - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
0 T6 U/ u6 E y( H
1 f: G0 z! p# q. y* a" |. g- /* TIM3 clock enable */
+ A: z* v' o L; L) m/ l$ r - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);' R7 f D3 ~0 s1 A9 d1 v
- / ~$ I0 k! Q1 t+ \# s
- // 2.配GPIO引脚为复用功能7 G0 y! c6 h, i" H" h( E5 C
- /* GPIOC Configuration: TIM14 CH1 (PF9) */) k! f# H! x& B* i {) K
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; // 选择引脚为PF9
/ c) G6 v4 D0 D0 Q! A) h D+ g - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 设置为复用功能
# ]) I9 ?0 n3 C m v - GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed; // 设置输出速度为100MHz
6 ?8 `% a+ K2 O4 Q) d3 J - GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // 设置为推挽输出
' A) H2 ~( }- V1 B$ @: R, {4 o - GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 设置为上拉输出+ |2 S5 |4 O( b" b: N; M: K
- GPIO_Init(GPIOC, &GPIO_InitStruct); // 安装参数5 d! ^7 S, L, }0 ?/ X, m! Q
& S/ ~0 K8 A- ?' H- u' s4 ]- // 3.将TIM和引脚的复用功能连接:TIM14和PF9连接起来0 Z. `- ?3 \0 f; h) e: P' X* K2 f
- GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);/ q5 }3 Z: c* H4 t- }( ^+ x# N
4 @& n& _1 @. y- // 4.配置TIM定时器的参数7 y) @" z( p) ~% D- N; v" A: O9 M) W
- TIM_TimeBaseInitStruct.TIM_Period = 100-1; // 设置重装载值 ARR(控制频率)3 u# A2 l' O5 u( P
- TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1; // 设置预分频系数:周期(次) 100Hz == 100us8 c+ Y! w y( r! }9 `: V
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 设置再分频值:TIM_CKD_DIV1就是不分频
D. P1 ^# n. {+ I, x- k& U - TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式( k1 {* }0 F' I( t Q( y( n- Z9 w
- TIM_TimeBaseInit(TIM14, &TIM_TimeBaseInitStruct);" a8 q7 b4 Y9 u+ x5 ^* ]
' t0 r1 C& @; T) F8 H- // 5.配置复用功能:PWM# d' m8 F* J2 X& a% ]
- TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // 配置为PWM模式11 t6 J. E) w# V
- TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; // 开启输出使能$ `; m H% i( o6 H5 }, E
- //TIM_OCInitStruct.TIM_Pulse = CCR1_Val; // 初始化配置比较值寄存器& x% f4 N! {: w5 H. u
- TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 配置为高电平有效
9 u {+ Q e8 n' B8 z6 h - z3 _# G0 @: A4 K* p
- // 6.TIM14通道1初始化
( R- t6 ~5 l: c - TIM_OC1Init(TIM14, &TIM_OCInitStruct); // TIM14通道1初始化' w3 o3 K7 t5 _2 u8 @
' i1 ]1 S, @6 Q- // 7.设置自动重载比较值CCR1初值,不断产生PWM脉冲
& z7 Z! {; b, [$ S - TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
& Q9 c1 r3 W: Z5 a; i d - # [& s: `. k+ h- G- I
- - U' j1 E) j% b1 |5 h% [+ Z, R
- // 8.设置自动重装载值(ARR),不断产生PWM脉冲% H0 r/ ^9 j" t+ U0 W1 u! H
- TIM_ARRPreloadConfig(TIM14, ENABLE);
4 B$ a& y% ]8 C- s& ]% Z - ' T6 c3 K: i4 p0 b
- /* 9.使能定时器14 */) K. k7 {' ~ M7 H$ z5 k/ r3 X
- TIM_Cmd(TIM14, ENABLE);
" Y1 z& M8 o! O* B - - t9 n. S( N3 t( O6 I
- // 10.使能TIM1PWM输出(高级定时器)
0 o! G. h) F& L6 u4 w/ `7 w/ j - //TIM_CtrlPWMOutputs(TIM1, ENABLE)- W0 R, d. Z- U/ J1 e
W4 C6 T3 e0 L4 R& S- Q4 s7 R- T" a
复制代码 1 }2 ^& i! m- s( B& c
设置比较值函数4 u; p: p7 N5 O: F
- w- h/ X F' K4 t
- void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);
复制代码 # _7 b" C s' R' X4 ]8 D
& ?# F! [+ ]6 h# r, N' X
' J: c! u' S1 t8 o |