你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 PWM输出

[复制链接]
STMCU-管管 发布时间:2020-9-10 10:18
01 PWM介绍
PWM定义:脉冲宽度调制(PulseWidthModulation,PWM)简称脉宽调制。通俗讲,PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。
; c- g# B# k  \1 q$ g4 C; h% H
电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。

1 h0 L$ i6 N6 ?& U3 ?2 ~+ ~
占空比定义:占空比就是高电平所占整个周期的时间,如下图所示:
  w" T* z" D) y4 A0 d9 J% F( g" v
1.png

; V- e1 s, d( `3 A# ~* C
第一个PWM波,周期为10ms,高电平的时间为4ms,所以占空比为40%,同理第二个PWM波为60%,第三个为80%。
% H5 L% u1 g& ^0 q: w2 {
PWM的频率: PWM的频率的整个周期的倒数,所以说上图PWM的周期为1/0.01,也就是100HZ。改变PWM的频率是通过改变整个的周期实现的。所以通过改变高低电平总共的时间、改变高电平占总周期的比例就可以实现任意频率、任意占空比的PWM波。
  c  O2 G. {: W# ?7 t0 k+ q% g) p
PWM的用途和优点:电机调速、功率调制、PID调节、通信等等,配置简单、抗干扰能力强,从处理器到被控系统信号都是数字形式的,无需进行数模转换。并且让信号保持为数字形式可将噪声影响降到最小,噪声只有在强到足以将逻辑1改变为逻辑0或将逻辑0改变为逻辑1时,也才能对数字信号产生影响,这是PWM用于通信的主要原因。
: [) s& L# |) N/ N4 g
02 STM32的管脚复用
STM32没有专门的PWM引脚,所以使用IO口的复用模式。首先确认PWM功能的输出管脚,使用定时器9。从下面的框图中得知,timer9只有两个输出通道,所以timer9只能输出两路PWM。
$ i# ~) I1 S- e; ~- J; z. }
2.png

0 T1 t8 ^8 Q: O' }; R
在STM32F207数据手册中的Alternatefunction mapping图片中,timer9的两个通道分别可以复用为PA2,PA3,PE5和PE6。

) R+ [; T! T, l: h' G; L9 p  V
3.png
03 STM32输出PWM原理# n" `# u3 f/ J
下图中的①部分,在《[color=var(--weui-LINK)]STM32基础定时器详解》讲解过了,关于影子寄存器,也在《[color=var(--weui-LINK)]STM32影子寄存器》中讲述,下文不再赘述了。本文将重点在②部分,捕获/对比通道讲解,其中STM32的PWM就是利用对比通道实现的。
/ @. i; w; _: Q3 @6 a; N+ \
4.png

% s0 f% {( V8 _3 l: U' [, d, B% n- {
Pulse Width Modulation mode allows you to generate a signal with afrequency determined by the value of the TIMx_ARR register and a dutycycle determined by the value of the TIMx_CCRx register。
节选自STM32F207 Reference manual手册
; g& X. G/ G) o3 P+ \

" l- S# @$ x" T  C
脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR 寄存器值决定,其占空比则由TIMx_CCRx 寄存器值决定。
6 o. Q: d+ w3 u# X

& ~: f4 J9 S' j6 g
从下图可以看出,当CCR寄存器和CNT计数器数值一样时,会产生动作(改变通道对应的GPIO电平)。由于CNT溢出时,重载值由TIMx_ARR寄存器值决定的。所以说TIMx_ARR寄存器值决定周期,而TIMx_CCRx寄存器值决定CNT溢出时,经过多久会产生动作(改变通道对应的GPIO电平),也就是决定了占空比。

* M6 Y! `2 j' f1 I3 ?
5.png

& O# A, }  s3 h: G& l1 N
以向上计数为例,重载值为ARR,比较值为CRRx
, t1 I6 `% z! F8 g$ S  Q7 ^

7 u  c" k" z: m% l+ c
6.png
' u/ {8 [9 h) C3 q6 Q! @
上图可以看出:' F7 v# V( u6 p# g. t
$ m5 U, `' {- B# y( ?
  • 0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平。
  • t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平。
    1 T+ {) Q: B/ I3 ?

    ; U& @5 X7 ?$ t  \0 Z5 c1 E
当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数...循环此过程至此一个PWM周期完成。

$ h/ L% h0 ]$ D5 K& Z/ ?# y
上图更加形象的说明了
  • 信号频率由 TIMx_ARR 寄存器值决定。
  • 占空比则由 TIMx_CCRx 寄存器值决定。

    0 B2 R# T5 {, N+ [% m- T
    0 {5 q* O* v9 l) H+ q0 G

4 j+ i% q: v/ P* C" O
STM32输出PWM的过程:
1、首先配置GPIO,配置定时器,具体参考一下代码。定时器配置参考《STM32基础定时器详解》。
2、捕获/比较通道使能比较通道。

. J; k" ?4 C5 l  z) z) s
7.png
: z, P7 @/ J! G; _2 \0 `, w7 V" N
上图看到,①寄存器名字为:Capture/Compare1register。可以选择从②处输入捕获,也可以选择从从③中输出,也就是我们需要的PWM输出功能。选择捕获通道,还是选择比较通道,在框图中没有找到具体的说明,但在TIMx_CCMR1寄存器CC1S[1:0]控制位使能。

& N) F$ l" ~/ y% t3 g; [
8.png
" U  T" U) ?& y# [/ |& b+ Z8 J" `7 T& P
3、使能完输出,就要配置PWM输出了
3 `4 C$ S' ?, M! ~' R% J$ E% m
9.png
% o! Y9 n1 V) S7 Q' w6 t
①TIMx_CCMR1寄存器的OC1M[2:0]位,设置输出模式控制器

2 {( K' `: Q6 j7 U" E* S6 L* g8 u
110:PWM模式1,111:PWM模式2。
. Y' \+ L. ~: q/ i8 r2 I

+ D: m5 n& \9 e6 g9 h/ J
②计数器值TIMx_CNT与通道1捕获比较寄存器CCR1进行比较,通过比较结果输出有效电平和无效电平。

" V% o: [: h, |. l3 n1 g

: X4 d4 @/ Z6 b: ^) b% ~- h; J
OC1REF=0 无效电平,OC1REF=1无效电平。
9 _; C4 c8 k9 z! V
③通过输出模式控制器产生的信号。TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性。
- q  n' Z# I' n# ~
0:高电平有效,1:低电平有效。

6 ~8 `' G& x5 `% O" p  N7 J& K
④TIMx_CCER:CC1E位控制输出使能电路,信号由此输出到对应引脚。

3 ]4 r) `0 s0 k
0:关闭,1:打开。

! V' H" B- M/ A6 {, k
首先对PWM模式1和PWM模式2进行介绍:
01 模式1$ S) B) f2 C+ T4 ~7 l0 N) ~; F
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向上计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
02 模式2
) l: p7 y; P5 u. \% ~
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
) I0 I6 k$ p/ |
TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
0 X# n+ j! ^& ]" N1 T) B0 F3 N% q. H) ^
$ ]6 H3 I' s* R0 W  X
PWM输出高低电平由TIMx_CCMR1:OC1M位和TIMx_CCER:CC1P位共同决定。

; l7 X! s& s, B6 c# k% d
总结下来:
9 a% r  l8 P$ t
模式1:
1 h5 T2 `- U; ~1 B3 s  F; `
    CNT<CCR为有效电平//(OC1REF =1)
    CNT>CCR为无效电平//(OC1REF =0)
3 X+ N- z- a$ V$ E1 [
模式2:
- ?3 u( a0 t) W2 X
    CNT<CCR为无效电平//(OC1REF =0)
    CNT>CCR为有效电平//(OC1REF =1)

8 G  |5 [# f, m+ s: P/ f
CC1P:
    0:高电平有效
    1:低电平有效
5 `. D, p4 w* k7 V3 i2 O
04 STM32输出PWM配置

; H6 X0 O1 P# f$ d( k
分析了原理,那么下面就分析STM32生成PWM的过程。

9 s' {+ j; L+ T) v  q& k" y6 W
1、首先要将GPIO设置为复用输出

9 M, b9 t4 l# U, b7 [
  1. " C% ]9 c8 h* M+ o' R$ C
  2. /* GPIOE clock enable */4 A& Z9 U( m- ~! \8 Z
  3. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
    0 L- x* J7 N! t2 k  j

  4. % f3 k& Q( V/ [. T$ Z, e5 o/ N3 z; ~
  5. /* GPIOE Configuration: TIM9 CH2(PE6)*/9 d/ V3 [  M6 C9 _4 |  f
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 |GPIO_Pin_6;
    2 \8 Q& M7 q8 d6 G* q5 @) X
  7. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF;1 f1 L/ ]! z5 R3 |
  8. GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;
    5 o: P2 f) ^* y
  9. GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;
    . t# C) f, P5 \6 \2 o; @
  10. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;7 `2 d+ w4 y/ x9 I  I7 M
  11. GPIO_Init(GPIOE, &GPIO_InitStructure);
    ( o( Z# C& x- |: A- |
  12. 7 {1 u- ?9 x" N5 V
  13. /*Connect TIM9 pins to AF3 */  / W9 t5 H9 i1 J* o
  14. GPIO_PinAFConfig(GPIOE,GPIO_PinSource5, GPIO_AF_TIM9);; z9 k/ x2 g$ w5 w  N$ l
  15. GPIO_PinAFConfig(GPIOE,GPIO_PinSource6, GPIO_AF_TIM9);
复制代码
4 a7 V. C7 S' q+ J9 Z
2、配置定时器向上计数,配置定时器频率
) K$ @+ o6 l( H& K) B  T
, E0 N$ a0 a* i( `8 I

  1. $ f7 O1 G, F+ {, }1 X# S3 s
  2. /* TIM9 clock enable */
    % N) V1 n) Q( g* ~( Q( {& w
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE);
    5 N$ }$ D$ `* R& C! I3 q4 J6 j

  4. - t4 D+ t* H% ]' u* j1 G
  5. /* Compute the prescaler value */: j5 z0 f2 I1 E" G+ D7 ^( w$ \
  6. PrescalerValue= (uint16_t) ((SystemCoreClock) / 2000000) - 1;2 `" ]4 @) P! c$ I

  7. ' ]: g* ]  j6 Y6 T3 F/ u
  8. /* Timebase configuration */1 k, l% N/ @* H
  9. TIM_TimeBaseStructure.TIM_Period =1000-1;
    + o0 }% X% L' i! c  Y9 Y- S, k) l0 _
  10. TIM_TimeBaseStructure.TIM_Prescaler =PrescalerValue;  O4 S/ L% K3 T6 P' O
  11. TIM_TimeBaseStructure.TIM_ClockDivision =0;; g" U3 a2 v% R$ F% U3 r
  12. TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;4 {( p' |1 k/ @7 ^+ n- U& d

  13. 9 `/ S7 {4 X9 o6 {3 j& n( V6 e
  14. TIM_TimeBaseInit(TIM9,&TIM_TimeBaseStructure);
复制代码
4 o& z; G3 X# ]1 a1 [' ~) C
; |& d0 R9 J; F' m

5 k9 ]- g8 m$ y! H- i4 I! p5 x4 P0 A+ G$ q& _+ Q
3 K3 }) ~' u. E- S
3、配置PWM输出上面分析过程较为麻烦,ST提供了标准外设库,我们只需要配置TIM_OCInitTypeDef结构体即可。
# x' e. R3 ^. E, x! W

  1. ' J+ G. o! w+ b" o- i3 C1 {
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;! Y' z7 h/ A9 s- J( U1 z; V0 L
  3. ( ^, u3 k. ^% F# X6 b6 {2 B
  4. /* PWM Modeconfiguration: Channel1 */
    $ }6 m+ O7 `( V' h, z8 ]
  5. TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_PWM1;' A+ W6 R& _( ~) O# l3 l
  6. TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;
    ) c" i: l: a+ z, P" q& ~7 [6 l1 m
  7. TIM_OCInitStructure.TIM_Pulse =100-1;
    ; \" X$ w% |  ]3 a
  8. TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;
    * G& A5 d8 h% `: d! \4 T; z; C
  9. . q! I4 k% i8 |
  10. TIM_OC1Init(TIM9,&TIM_OCInitStructure);
    ! P$ n# A$ r1 e" B
  11. TIM_OC1PreloadConfig(TIM9,TIM_OCPreload_Enable);
复制代码

8 q7 u8 v# U4 a+ V" T- r$ H) ]. C4 [; r$ o, ^# W' c

) [, d' p3 h( [
TIM_OCInitTypeDef结构体解析
# c% K. w; i- W7 T0 y+ I5 A1 N; [- D

  1. $ h+ T7 Z; U' i8 }  ]* n
  2. typedef struct
    # N9 c5 J! Y1 ?4 e) j2 W' R" M) ]
  3. {( t2 O3 c, f& E1 s+ L" `4 Z% x
  4.   uint16_t TIM_OCMode;      //PWM模式1或者模式2
    0 b8 U. W3 t+ D6 b* u- J3 D& q7 {) |
  5. uint16_t TIM_OutputState; // 输出使能OR失能! c9 J. S3 d; k) T/ O# V
  6. uint16_t TIM_OutputNState;  // PWM输出不需要- d$ _( A/ k9 w# _) |
  7. uint32_t TIM_Pulse; // 比较值
    6 Z2 m, A! X  u6 [! N, a1 k. f
  8. uint16_t TIM_OCPolarity;// 比较输出极性
    / g4 B) Y% e! O6 m1 K7 Q% J; i
  9.   uint16_t TIM_OCNPolarity;   // PWM输出不需要$ U% t1 S' Q6 `% r- I$ @
  10.   uint16_t TIM_OCIdleState;// PWM输出不需要
    % C' P! o( C/ L* v0 W
  11. uint16_t TIM_OCNIdleState; // PWM输出不需要9 G6 Z4 G* @) s, j3 l, j; X
  12. }TIM_OCInitTypeDef;
复制代码

$ S1 a# b/ ^$ Q
其中TIM_Pulse可以在初始化时设置,设置完毕后,也可以通过以下接口再次更新。
& c6 u9 ^5 n) B! h

  1. 1 z  G2 T- ?2 m* u0 v9 p. W: h. J
  2. void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1)
复制代码
% E% ~% Z: b% b& G$ E. o
. C* N: |) P1 a  u
4、使能定时器
$ d3 ~' c4 [3 ]0 ^
  1. " |- n) |+ A% K& O0 x0 [6 {
  2. TIM_ARRPreloadConfig(TIM9, ENABLE);3 a# h+ s0 o+ c) {8 o9 A
  3. : B" M! ]8 u2 f9 Z  A/ i3 o4 L
  4. /* TIM9 enable counter*/
    ' P2 \8 d; S( o/ r5 j/ i. j, N' z
  5. TIM_Cmd(TIM9, ENABLE);
复制代码

8 b6 D% i2 ]! n! B( R0 ]
使用timer9输出PWM的波形。
10.png
" K; u  `. M, u: T8 u" C# {

! f" Q3 f' o; n
2 T0 f1 b+ v3 _9 M" t
1 收藏 2 评论0 发布时间:2020-9-10 10:18

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版