1、PWM是什么?
0 c7 X/ g& h* s0 g
! E, h0 B4 B( [! V* N N! \ 是脉冲宽度调制,简称脉宽调制。利用微处理器数字输出对模拟电路进行控制的一种有效的技术,就是对脉冲宽度的控制。
8 H( {7 ~# D3 `9 \ j8 J; D7 d( I5 t* p% K# b
这里说的脉冲,就是我们产生的方波。方波就是N个这样的周期连续的产生。
0 X* y% |9 T8 w8 \: v5 C& Q
1 A$ ]5 t& w2 Z' j! o# m
. V; Z5 v: B$ W& [% r- s! G
6 Z& g) g- V+ K一个周期内高电平持续的时间就是脉冲宽度(脉宽),而PWM(脉冲宽度调制)就是控制一个周期内的高电平的持续时间。
S: A! {$ R8 F. m: T) d0 X; U2 g# g* [) V4 J
2、简单的PWM的原理示意图
3 c7 ?% E! M1 V- |9 {7 [1 b
7 A6 j* ?; @5 O2 K$ l9 V
9 B: B; S$ j8 f+ a- a# y6 o" e
! N' R. ]0 n6 p% PCNT:是当前值寄存器,计数寄存器。
6 e( d* H3 \& J9 E
0 U/ y6 Q' f+ [: ~ARR:是自动重载寄存器(初始化设定)。) ^" p, Q. ^8 w5 W3 S
" T% Z l! T3 c
CCRx:比较值寄存器(TIM_SetCompare1()设定修改占空比)。
$ s( @* O/ _+ k8 ]( d1 T5 `" T6 H
% J+ Z& J' o" E( m3 y' S
假定定时器工作在向上计数PWM模式下:- p$ L# V$ d8 s* Y( R2 j8 ~" X
) ~! T9 G7 ^% t当CNT<CCRx时,引脚输出0,当CNT>=CCRx时,引脚输出1。
8 B2 o9 A0 d9 w, `4 K) S3 h. j. [
当CNT的值小于CCRx的时候,IO输出低电平(0),
/ Q1 A0 N5 H! U& e: n% A. Z+ J2 a7 V
当CNT值大于或等于CCRx的时候,IO输出高电平(1),9 c1 O0 o1 N& ^5 {5 L) Z
, I8 |2 ]4 Q( V' X) f9 W6 @ Z当CNT的值达到ARR的时候,就会重新归零,然后重新向上计数,依次循环。/ @0 u% ], w7 F2 [
& A: u# @7 A9 h. [- C$ }改变CCRx的值就可以改变PWM的输出的占空比。改变ARR的值,就可以改变PWM的输出的频率,这就是PWM的输出原理。0 z2 y0 i) B' ?3 X
R, ~% W7 |( f! Y# }& |
3、寄存器工作流程:
$ ?6 d+ e' X) ]5 h6 _( R. X
, x3 z( e8 D( }- `
6 N9 }1 K/ W7 O# U: s$ Z4 S
1 p- i$ j" z& O& v$ D7 e3 B! X$ U R7 ~PWM 模式
; [3 U8 p+ a' g0 ]* u5 o* P
" k4 z) x3 ~% D, F! T4 l* w脉冲宽度调制模式可以生成一个信号,该信号频率由 TIMx_ARR 寄存器值决定,其占空比由 TIMx_CCRx 寄存器值决定。
6 q9 z! Z1 W( n
! D0 g; w' Q- L& b通过向 TIMx_CCMRx 寄存器中的 OCxM 位写入 110(PWM 模式 1)或 111(PWM 模式 2) ,可以独立选择各通道 (每个 OCx 输出对应一个 PWM)的 PWM 模式。必须通过将TIMx_CCMRx 寄存器中的 OCxPE 位置 1 使能相应预装载寄存器,最后通过将 TIMx_CR1寄存器中的 ARPE 位置 1 使能自动重载预装载寄存器(在递增计数或中心对齐模式下)。
4 R& i& B5 g& N& o% f+ m+ `8 b0 e/ ], U7 y# K
由于只有在发生更新事件时预装载寄存器才会传送到影子寄存器,因此启动计数器之前,必须通过将 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。
" l$ ^; x; `! |3 X* T
7 {4 R" C/ R& B6 f/ c因为计数器采用递增方式计数,所以定时器能够在边沿对齐模式下生成 PWM。; u% K. n) k6 ` H2 @9 A/ J
3 f9 ~8 k4 ]' `7 b$ m9 S+ P
4、PWM 边沿对齐模式0 G/ \1 }, @3 O5 y. ?
2 ? u& o. b1 k* ]3 z以下以 PWM 模式 1 为例。只要 TIMx_CNT < TIMx_CCRx, PWM 参考信号 OCxREF 便为高电平,否则为低电平。如果 TIMx_CCRx 中的比较值大于自动重载值(TIMx_ARR 中),则 OCxREF 保持为“1”。如果比较值为 0, 则 OCxRef 保持为“0”。 图 183 举例介绍边沿对齐模式的一些 PWM 波形 (TIMx_ARR=8)。
3 J m( r: C2 h1 U: x/ l$ g
4 B$ v0 D3 ^* T7 d
: O, U4 q, ?3 z+ h, S6 S/ v3 R0 ^8 t/ Q
5、PWM步骤-灯光亮度控制:- t! n8 v" E: F
/ f4 V0 ]; e0 [" J. E& \ 查看LED的原理图:) m5 R( N' G4 L Z2 P
k" q# A, F. s0 M6 n
% z# F. R( H2 ^. m5 ~$ I. o4 a+ \
" @& P. l8 |3 H" w y" d* u" D1 t# F& p& U& ]% Z3 Q
- //①根据原理图找到4个引脚:, } `! H/ b6 X& M5 a
- PF9可以使用TIM14_CH1,表示可以使用定时器14的通道1产生PWM输出。4 Y* |8 T. d1 K# \' v9 r
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; // 定义的TIM属性结构体变量( G1 p8 n F) ?+ f0 B- y
- GPIO_InitTypeDef GPIO_InitStruct; // 定义GPIO类型变量, B0 O* t8 X9 _0 F9 O& m& F# C( k
- TIM_OCInitTypeDef TIM_OCInitStruct; // 定义复用功能的变量
2 f1 U+ i, ^0 r! J* R6 r
! O2 D3 h" l) p& p' I* P9 s- ②// 1.初始化时钟:TIM14 和 PF9
% K! l `2 i, o* @) G; l9 W - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);" v9 V& g5 v8 I6 }1 O) g$ z
- $ h$ P* [; @# ^! O
- /* TIM3 clock enable */+ I0 x* c9 x! G8 G. Y, n) \# n' i O( ^
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
; C. e3 [9 s2 ?" ]
/ u/ S1 E1 w' O, \; u) C- // 2.配GPIO引脚为复用功能& w O# h2 a0 a( F
- /* GPIOC Configuration: TIM14 CH1 (PF9) */' [) E& F' q6 h1 \
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; // 选择引脚为PF9
* @ o; w. J3 O. A, i( } - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 设置为复用功能2 e: \5 M! l& V0 F
- GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed; // 设置输出速度为100MHz
, X" [7 i+ G8 j3 S8 b/ _: B - GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // 设置为推挽输出( \9 V7 _& N3 a* i$ {$ _! |' W
- GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 设置为上拉输出
e, q4 Y- ]% P4 K# C - GPIO_Init(GPIOC, &GPIO_InitStruct); // 安装参数
% N% K' ?. m( s1 n/ w5 U - : D7 x% K+ G/ [9 m0 k: p+ P
- // 3.将TIM和引脚的复用功能连接:TIM14和PF9连接起来9 M6 P/ i9 _2 F8 c1 J2 G$ V' u7 t
- GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);
7 _$ R$ G8 z+ R/ O
+ |6 l4 h" B, G8 g) L- // 4.配置TIM定时器的参数
" f8 z8 x2 }4 f2 @; R! s - TIM_TimeBaseInitStruct.TIM_Period = 100-1; // 设置重装载值 ARR(控制频率)
) i' F) e2 \5 e - TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1; // 设置预分频系数:周期(次) 100Hz == 100us
/ I/ J$ Z; h$ k" G6 ?$ X% P - TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 设置再分频值:TIM_CKD_DIV1就是不分频 J9 b' E' I* ?
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式$ g/ j& \4 V6 e% M) G4 U# R
- TIM_TimeBaseInit(TIM14, &TIM_TimeBaseInitStruct);4 e# u G5 h: U) v: O# G
- / [: q$ }3 L) t1 c8 s! a) v& \/ a
- // 5.配置复用功能:PWM( v8 f6 G5 M, ^ x$ I6 P* L2 ]' D
- TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // 配置为PWM模式1
9 J, ~- j: G2 q+ L - TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; // 开启输出使能
7 L+ r9 F$ U1 R - //TIM_OCInitStruct.TIM_Pulse = CCR1_Val; // 初始化配置比较值寄存器( n$ j9 e) t8 ]- Y8 e/ w s# r9 S/ O
- TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 配置为高电平有效
* W4 `* v; b! I& x - / t- H6 E# N l
- // 6.TIM14通道1初始化
! _3 H, E/ W# N6 s1 L - TIM_OC1Init(TIM14, &TIM_OCInitStruct); // TIM14通道1初始化
+ z; ~% P2 v# X
5 ]- p5 t& o8 q: v. A, y5 z L' s- // 7.设置自动重载比较值CCR1初值,不断产生PWM脉冲
+ o% ^3 Z+ y& e0 [/ {& w - TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);. o9 m, c2 W, L- A5 N1 Z
1 V7 p0 a9 s/ {6 }8 {) ^- 5 V; Y9 M6 A: O1 t, m5 \0 b
- // 8.设置自动重装载值(ARR),不断产生PWM脉冲
, k- M, q5 M* G% \* x- ~ - TIM_ARRPreloadConfig(TIM14, ENABLE);3 ~, L# F d# C' A
o) ^. @+ D; j6 w: D0 ?3 H7 k- /* 9.使能定时器14 */# i6 p: ~# l% d% J# C- x
- TIM_Cmd(TIM14, ENABLE);) B5 b- [; j) c6 E$ _
- ; Q# ]& ]8 f& h/ C
- // 10.使能TIM1PWM输出(高级定时器)
+ M7 R' O5 ?2 @; S7 k3 Z) T$ M - //TIM_CtrlPWMOutputs(TIM1, ENABLE)
! K( M# \8 @$ m5 [' L - & Q1 k: x* S* u
复制代码
; E1 U$ K- f* L* s! d3 _2 u设置比较值函数- M' G! g) B9 `5 }
: F @" _* L. G7 |2 t$ c- void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);
复制代码 ! r3 \. y, m% B% Z
! _" O( t# s7 @) s2 j' W
4 u; N% q l7 k, E: c4 U |