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

STM32 PWM输出

[复制链接]
STMCU-管管 发布时间:2020-9-10 10:18
01 PWM介绍
PWM定义:脉冲宽度调制(PulseWidthModulation,PWM)简称脉宽调制。通俗讲,PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。

! I2 \" D5 B$ n: j" T
电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。
+ O( P1 E/ J2 N7 S" O6 i
占空比定义:占空比就是高电平所占整个周期的时间,如下图所示:

; d% n- q1 {) f" y! f
1.png
, B4 O- y, k  Z0 Y) D* K
第一个PWM波,周期为10ms,高电平的时间为4ms,所以占空比为40%,同理第二个PWM波为60%,第三个为80%。

: N! s$ T  G9 _0 V1 ~2 c
PWM的频率: PWM的频率的整个周期的倒数,所以说上图PWM的周期为1/0.01,也就是100HZ。改变PWM的频率是通过改变整个的周期实现的。所以通过改变高低电平总共的时间、改变高电平占总周期的比例就可以实现任意频率、任意占空比的PWM波。
( I6 I$ m: l9 j$ e( k
PWM的用途和优点:电机调速、功率调制、PID调节、通信等等,配置简单、抗干扰能力强,从处理器到被控系统信号都是数字形式的,无需进行数模转换。并且让信号保持为数字形式可将噪声影响降到最小,噪声只有在强到足以将逻辑1改变为逻辑0或将逻辑0改变为逻辑1时,也才能对数字信号产生影响,这是PWM用于通信的主要原因。
8 G# q$ }+ e7 B! [+ o5 H- Y) v4 T
02 STM32的管脚复用
STM32没有专门的PWM引脚,所以使用IO口的复用模式。首先确认PWM功能的输出管脚,使用定时器9。从下面的框图中得知,timer9只有两个输出通道,所以timer9只能输出两路PWM。
  T8 \3 O$ g/ |$ a( c3 x% `
2.png
5 L! m/ S, c# L/ S# a2 b
在STM32F207数据手册中的Alternatefunction mapping图片中,timer9的两个通道分别可以复用为PA2,PA3,PE5和PE6。

* a% a+ O. T6 q/ t8 d* w
3.png
03 STM32输出PWM原理# c* Y9 K* C% V! j3 C0 B1 l$ R
下图中的①部分,在《[color=var(--weui-LINK)]STM32基础定时器详解》讲解过了,关于影子寄存器,也在《[color=var(--weui-LINK)]STM32影子寄存器》中讲述,下文不再赘述了。本文将重点在②部分,捕获/对比通道讲解,其中STM32的PWM就是利用对比通道实现的。
1 r  A3 f3 P) d
4.png

2 Y, w$ N; O# f) q% R6 Y1 _
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手册

. x9 V# m5 w- l) x! `  j

- s& Z1 k, P) m9 |. i0 N
脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR 寄存器值决定,其占空比则由TIMx_CCRx 寄存器值决定。
9 |# g/ r* q5 ~

1 Z/ f" {+ b) c: T/ B
从下图可以看出,当CCR寄存器和CNT计数器数值一样时,会产生动作(改变通道对应的GPIO电平)。由于CNT溢出时,重载值由TIMx_ARR寄存器值决定的。所以说TIMx_ARR寄存器值决定周期,而TIMx_CCRx寄存器值决定CNT溢出时,经过多久会产生动作(改变通道对应的GPIO电平),也就是决定了占空比。

. [( I8 S1 E0 I) y. N
5.png

; o0 y' j, w7 \$ i# p
以向上计数为例,重载值为ARR,比较值为CRRx
. w! I; H: F, v) y# z4 }

4 A; a1 ~  w8 A* _( g5 X7 V" W1 e1 [
6.png
* @7 e7 `1 E0 ?7 Z6 l4 e/ b
上图可以看出:7 z* _: D( D' e5 `; [9 C
4 f, f0 A9 B( V+ k2 ?
  • 0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平。
  • t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平。
    7 t- W) _6 O3 g1 x" l
    - A$ u% b+ S" S
当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数...循环此过程至此一个PWM周期完成。
7 Q) O$ [* n! S! V
上图更加形象的说明了
  • 信号频率由 TIMx_ARR 寄存器值决定。
  • 占空比则由 TIMx_CCRx 寄存器值决定。

    6 j% i: t" S4 B/ o+ i1 z  @
    ! P4 b; Y$ z, R$ i8 r/ W/ o" H5 r$ ?

2 W# P/ E# I1 O& v. ^- E" I8 E
STM32输出PWM的过程:
1、首先配置GPIO,配置定时器,具体参考一下代码。定时器配置参考《STM32基础定时器详解》。
2、捕获/比较通道使能比较通道。

2 H" P. m8 U( L& P, ~
7.png
2 W2 C; g4 t+ B
上图看到,①寄存器名字为:Capture/Compare1register。可以选择从②处输入捕获,也可以选择从从③中输出,也就是我们需要的PWM输出功能。选择捕获通道,还是选择比较通道,在框图中没有找到具体的说明,但在TIMx_CCMR1寄存器CC1S[1:0]控制位使能。

  k- y6 i* Q4 t! k
8.png
7 _2 x' e3 z# _; j- }; |$ d/ X0 m( A7 }
3、使能完输出,就要配置PWM输出了
5 o1 B$ I$ M( @* z4 m
9.png

5 K) X5 g$ R7 N3 n" M: R. u
①TIMx_CCMR1寄存器的OC1M[2:0]位,设置输出模式控制器
7 O! J# i% E; K' s) i: b( I
110:PWM模式1,111:PWM模式2。
- M" h" Y, h, }/ j! ~( h
. |( g7 h$ G. L4 J% g/ ]/ W$ q
②计数器值TIMx_CNT与通道1捕获比较寄存器CCR1进行比较,通过比较结果输出有效电平和无效电平。
  `3 j& c8 ?0 ?! ?/ J
( R  H% ]6 _7 @4 l, g& M
OC1REF=0 无效电平,OC1REF=1无效电平。
8 _9 T! _, g  I
③通过输出模式控制器产生的信号。TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性。
  w8 i3 B  m5 f3 y2 T& h9 B5 E
0:高电平有效,1:低电平有效。
4 d& i8 q) ^, Z6 W2 o
④TIMx_CCER:CC1E位控制输出使能电路,信号由此输出到对应引脚。
; E+ X/ x. u+ b7 R2 }  }8 S
0:关闭,1:打开。
, e4 k, e* |; E3 ]+ N
首先对PWM模式1和PWM模式2进行介绍:
01 模式1
/ \/ G8 l! F) h+ w$ Y# x, u
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向上计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
02 模式2) L, z2 C' [, E8 `0 @; }
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。

7 }7 N# y& ?5 J  F
TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。9 ~$ u5 i. ~  M3 T& Y; s& }, G
: }$ X3 y# M# n9 `8 e6 i. K7 k2 s
PWM输出高低电平由TIMx_CCMR1:OC1M位和TIMx_CCER:CC1P位共同决定。

: I, ?! p. z% A$ t
总结下来:

) I3 q% E0 K' ?1 k: i1 J
模式1:
* O# A0 L8 y: [9 b0 I# z. i& q
    CNT<CCR为有效电平//(OC1REF =1)
    CNT>CCR为无效电平//(OC1REF =0)

9 ?1 u# L  X  T5 \- t! Z0 P
模式2:
! Z3 H8 e3 g( _9 p3 o1 @) ^% G  ?8 O
    CNT<CCR为无效电平//(OC1REF =0)
    CNT>CCR为有效电平//(OC1REF =1)
5 _7 m2 y8 l& E0 ?4 ~3 D5 Y/ T
CC1P:
    0:高电平有效
    1:低电平有效
( i4 K8 }! O' e
04 STM32输出PWM配置

" g" f  F; w3 g# O" W$ o
分析了原理,那么下面就分析STM32生成PWM的过程。

" z. h& z/ ~# J8 o9 T3 }- [
1、首先要将GPIO设置为复用输出
7 m2 {1 U6 V3 o+ N: V8 E
  1. + h: o/ l3 L$ y. }8 j
  2. /* GPIOE clock enable */
    ! A$ ~. k9 b0 c3 G' S
  3. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
    ) l4 K8 }5 a$ R0 a

  4. 8 l* P5 Z' Y1 m4 u' y0 z
  5. /* GPIOE Configuration: TIM9 CH2(PE6)*/9 V% ?$ P1 q) Q. ~- k% M. e3 K
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 |GPIO_Pin_6;% x- {" S* G" d7 X  Z9 H9 ~8 U
  7. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF;
    0 O* ~1 v( Y+ o1 B$ w
  8. GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;9 b* W" h) D7 W% q3 {+ N: U3 e
  9. GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;) t3 V0 E$ O4 v
  10. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;" |( v: f( }9 j( `0 m# \6 B
  11. GPIO_Init(GPIOE, &GPIO_InitStructure);
    / `3 W% P  f1 x
  12. % R( r6 c* W) ^/ C# `5 j" z
  13. /*Connect TIM9 pins to AF3 */  
    ; n  o( F! ~. o* L2 |
  14. GPIO_PinAFConfig(GPIOE,GPIO_PinSource5, GPIO_AF_TIM9);
    " [  G/ l  [8 e! E$ S
  15. GPIO_PinAFConfig(GPIOE,GPIO_PinSource6, GPIO_AF_TIM9);
复制代码
  d5 N7 ~  A3 E% D9 V0 d  }6 {8 _
2、配置定时器向上计数,配置定时器频率
; C' L1 Q5 T1 V" b; Z' A% j
- ?  Y+ r9 j( I2 ^
  1.   @$ W+ F- v; ?5 n6 ^+ x/ n! S7 J
  2. /* TIM9 clock enable */
    , w3 Z, L( O' }% }! ~9 L( R
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE);
    & ~' v9 S" h# n( Y( k, P  B3 v

  4. 9 U, l/ Y$ Z: m7 k0 I/ t( h$ f
  5. /* Compute the prescaler value */
    . V+ N2 ?# S0 ?1 m. T( k% L
  6. PrescalerValue= (uint16_t) ((SystemCoreClock) / 2000000) - 1;0 _, |, k7 S/ ^' z& c" F
  7. / i1 N% \9 f, ]  C4 u
  8. /* Timebase configuration */" g2 k7 r1 N4 f  M9 N0 [
  9. TIM_TimeBaseStructure.TIM_Period =1000-1;7 n; W3 A4 J- e7 X, h- V+ [+ V/ `
  10. TIM_TimeBaseStructure.TIM_Prescaler =PrescalerValue;
    . k' t3 L+ x0 r( V3 P
  11. TIM_TimeBaseStructure.TIM_ClockDivision =0;
      P* ]/ j) S( ~* I6 V7 Y
  12. TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;
    8 A( R) y; u3 p

  13. , I# G- n4 ^) [# k
  14. TIM_TimeBaseInit(TIM9,&TIM_TimeBaseStructure);
复制代码
: z+ Q9 t* g, s+ o4 [
; C3 S" S4 P1 [1 ?- H

0 |6 j9 Q8 t6 x+ s
9 z9 Q' l4 d- g, M8 [4 P) \5 f) n

% e% i  V2 q5 H8 `3、配置PWM输出上面分析过程较为麻烦,ST提供了标准外设库,我们只需要配置TIM_OCInitTypeDef结构体即可。* R/ z( ]7 I8 @) F: n

  1. 9 O$ f' V* _, `  m& y
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;
    ' v8 I, B3 K( D) u( l& i
  3. ! h4 U8 }, M- V7 J
  4. /* PWM Modeconfiguration: Channel1 */
      A& [7 W$ ~1 E! c, Y6 C
  5. TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_PWM1;
    # [- `7 F; D0 [2 P7 |2 ?
  6. TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;% ?1 g3 B$ B4 e. Z. C( t9 N
  7. TIM_OCInitStructure.TIM_Pulse =100-1;+ g9 v% l) ]$ [7 j7 a. B" a
  8. TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;
    ; [2 m6 i8 G* ]

  9. ( g$ n# _3 W5 q& f6 \% c
  10. TIM_OC1Init(TIM9,&TIM_OCInitStructure);
    6 ~  O9 D( e+ U4 U( P
  11. TIM_OC1PreloadConfig(TIM9,TIM_OCPreload_Enable);
复制代码
  o) c7 |0 B+ p" ]  p! Z; U7 K

$ J; A% n# _! A& x6 ~, @0 i
4 Z; `7 u  o3 G4 r" }9 K
TIM_OCInitTypeDef结构体解析

; k' n3 y" x9 o4 e
  1. : F. \: r4 W& H- N) ~2 a
  2. typedef struct1 g+ s& E" D, c" b
  3. {( w* o2 j4 W: w$ E# T. O
  4.   uint16_t TIM_OCMode;      //PWM模式1或者模式2
    ) f7 n5 A6 t' p7 n5 Q5 T
  5. uint16_t TIM_OutputState; // 输出使能OR失能
    1 E1 a0 D( s- ]3 |/ v" e! e$ i
  6. uint16_t TIM_OutputNState;  // PWM输出不需要
    & ~% ^) u  @2 P4 D% q+ |8 Q
  7. uint32_t TIM_Pulse; // 比较值* j; f8 }  e  s; H5 g" @
  8. uint16_t TIM_OCPolarity;// 比较输出极性
    * E" |- I5 E: e: y8 P7 O
  9.   uint16_t TIM_OCNPolarity;   // PWM输出不需要) G2 w8 y" O) |# A: E  I
  10.   uint16_t TIM_OCIdleState;// PWM输出不需要. K9 c# W6 g$ t9 n& r1 v
  11. uint16_t TIM_OCNIdleState; // PWM输出不需要
    & r+ d1 Q- W. o
  12. }TIM_OCInitTypeDef;
复制代码

8 W+ G4 Z; w0 X3 N9 B( v9 j2 s
其中TIM_Pulse可以在初始化时设置,设置完毕后,也可以通过以下接口再次更新。
, [( j" P7 `3 k$ W. n, D+ z

  1. / Z8 ~: m% N8 C1 I% p, a0 Y
  2. void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1)
复制代码

! h, [+ e  B* p; V! P8 ~& _" S4 Q
0 l7 K; @2 o: l/ y# z4 H
4、使能定时器
9 n( l- l' l/ Z5 G- z

  1. 4 `) j4 T% Y( y: `( y* u! H
  2. TIM_ARRPreloadConfig(TIM9, ENABLE);( P: _. h" ^. H6 }+ m# C

  3. 6 b2 V& i! }" g
  4. /* TIM9 enable counter*/
    , g  g  m% r" Q, P- y( P: A
  5. TIM_Cmd(TIM9, ENABLE);
复制代码

0 M9 h0 ]4 a4 T
使用timer9输出PWM的波形。
10.png

, p& o# G0 `; c( s0 E! {  f8 u! i4 e* [

+ [$ q4 h. z6 p
赞 1 收藏 2 评论0 发布时间:2020-9-10 10:18

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版