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

STM32 PWM输出

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

+ `- [! _( y  e5 x; V
电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。

# q0 c1 G# m, i, L! d$ A/ d3 n
占空比定义:占空比就是高电平所占整个周期的时间,如下图所示:
+ P4 J5 q3 I' m/ k2 M
1.png
9 Z: O+ x6 O2 G" T" H/ e
第一个PWM波,周期为10ms,高电平的时间为4ms,所以占空比为40%,同理第二个PWM波为60%,第三个为80%。

+ j5 }/ v% L8 c
PWM的频率: PWM的频率的整个周期的倒数,所以说上图PWM的周期为1/0.01,也就是100HZ。改变PWM的频率是通过改变整个的周期实现的。所以通过改变高低电平总共的时间、改变高电平占总周期的比例就可以实现任意频率、任意占空比的PWM波。

6 n# Y0 h& ?* o3 m
PWM的用途和优点:电机调速、功率调制、PID调节、通信等等,配置简单、抗干扰能力强,从处理器到被控系统信号都是数字形式的,无需进行数模转换。并且让信号保持为数字形式可将噪声影响降到最小,噪声只有在强到足以将逻辑1改变为逻辑0或将逻辑0改变为逻辑1时,也才能对数字信号产生影响,这是PWM用于通信的主要原因。

  f. J* A& l* P1 c- p
02 STM32的管脚复用
STM32没有专门的PWM引脚,所以使用IO口的复用模式。首先确认PWM功能的输出管脚,使用定时器9。从下面的框图中得知,timer9只有两个输出通道,所以timer9只能输出两路PWM。
7 k3 I5 n5 L4 j/ G: j  ?9 e" a
2.png

9 |0 Y# v6 ?+ l
在STM32F207数据手册中的Alternatefunction mapping图片中,timer9的两个通道分别可以复用为PA2,PA3,PE5和PE6。

) q5 t2 ^0 ]; B" j0 h7 T
3.png
03 STM32输出PWM原理
' X: \8 m& F& ^3 |% n
下图中的①部分,在《[color=var(--weui-LINK)]STM32基础定时器详解》讲解过了,关于影子寄存器,也在《[color=var(--weui-LINK)]STM32影子寄存器》中讲述,下文不再赘述了。本文将重点在②部分,捕获/对比通道讲解,其中STM32的PWM就是利用对比通道实现的。
2 K2 f0 s' X8 G
4.png
/ U* I! [. }+ C1 w  x$ p
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手册
% t4 J: c& |' V- W$ v. v/ b
* {! @7 Z& Q5 b. w& @
脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR 寄存器值决定,其占空比则由TIMx_CCRx 寄存器值决定。
! S6 {: _' x$ v) d5 _

' }# X! C' x; T- Q- s9 N' e4 V9 f1 `
从下图可以看出,当CCR寄存器和CNT计数器数值一样时,会产生动作(改变通道对应的GPIO电平)。由于CNT溢出时,重载值由TIMx_ARR寄存器值决定的。所以说TIMx_ARR寄存器值决定周期,而TIMx_CCRx寄存器值决定CNT溢出时,经过多久会产生动作(改变通道对应的GPIO电平),也就是决定了占空比。
, Y$ \$ e( }. x
5.png

0 R- t; Y4 {4 T- g8 g% B" `8 Z; ~
以向上计数为例,重载值为ARR,比较值为CRRx
8 V" K5 A( E4 ^! ^9 d2 m

' u5 l) O9 o- Q
6.png
1 ]5 F3 x$ p* H$ Y/ z! z9 U
上图可以看出:
8 {1 [/ _9 k. f! ^2 U
" q& b. u7 {7 R
  • 0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平。
  • t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平。

    & A2 A9 {9 E/ }6 L  ]) O4 q; n

    8 _( G8 z0 j8 j6 J2 ], V
当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数...循环此过程至此一个PWM周期完成。
  U7 {  k, c& o3 }  y. W1 `
上图更加形象的说明了
  • 信号频率由 TIMx_ARR 寄存器值决定。
  • 占空比则由 TIMx_CCRx 寄存器值决定。

      k, q, x5 x1 g( g' L$ H

    : j2 n. s6 N# @$ c4 d

' K# C0 [( D8 u
STM32输出PWM的过程:
1、首先配置GPIO,配置定时器,具体参考一下代码。定时器配置参考《STM32基础定时器详解》。
2、捕获/比较通道使能比较通道。

! y0 `9 X: H) A4 C" E
7.png
6 p1 f4 l0 j9 D  S  [, ]% f
上图看到,①寄存器名字为:Capture/Compare1register。可以选择从②处输入捕获,也可以选择从从③中输出,也就是我们需要的PWM输出功能。选择捕获通道,还是选择比较通道,在框图中没有找到具体的说明,但在TIMx_CCMR1寄存器CC1S[1:0]控制位使能。
: ~" Q3 }5 |2 h% P# }! }* R+ H
8.png

4 W  X) z: T, R2 ?$ O, e$ j
3、使能完输出,就要配置PWM输出了
# J( Z: U! Q/ \+ h9 P
9.png
7 {, r' L' [$ U- U
①TIMx_CCMR1寄存器的OC1M[2:0]位,设置输出模式控制器

- ]9 A" i3 d- f7 _$ E/ ^
110:PWM模式1,111:PWM模式2。

+ n1 k0 R% m5 a; e
& Y) w' A, ?$ e3 B1 t  Q
②计数器值TIMx_CNT与通道1捕获比较寄存器CCR1进行比较,通过比较结果输出有效电平和无效电平。
% N% }: l# [/ j* o( {7 P

9 _3 G# O1 Z& G0 ?
OC1REF=0 无效电平,OC1REF=1无效电平。
; o# c! L6 Y. t9 T/ V0 P+ x
③通过输出模式控制器产生的信号。TIMx_CCER寄存器的CC1P位,设置输入/捕获通道1输出极性。
( D9 G+ e" A/ W1 F* [
0:高电平有效,1:低电平有效。
* u4 I* I; y* K/ u+ X
④TIMx_CCER:CC1E位控制输出使能电路,信号由此输出到对应引脚。
4 ]  Y# H) P# r& i: |$ z: P
0:关闭,1:打开。
. l1 V+ y6 x6 ]
首先对PWM模式1和PWM模式2进行介绍:
01 模式1' R  @' C# b; I" B0 u, Q
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向上计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
02 模式2/ O6 u( L+ y. a" v5 e$ y
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。

* E8 D5 }1 _4 E1 v( H/ h
TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
3 v7 a- M0 i6 e+ |+ q

7 H% v0 U: g6 n$ p, S- l$ P# N# T7 |
PWM输出高低电平由TIMx_CCMR1:OC1M位和TIMx_CCER:CC1P位共同决定。
; U; j2 |7 N2 y% G: J  D8 R
总结下来:
  E: ~( l% u7 }) N- U) Y( v
模式1:

( ^& I) u; t- @8 _2 W  S/ S- s
    CNT<CCR为有效电平//(OC1REF =1)
    CNT>CCR为无效电平//(OC1REF =0)
+ Z" m% z- @+ Q4 z/ D" p
模式2:
3 L0 \9 V" O  Z2 ~$ J
    CNT<CCR为无效电平//(OC1REF =0)
    CNT>CCR为有效电平//(OC1REF =1)

4 K# q  y" n8 a! Z
CC1P:
    0:高电平有效
    1:低电平有效
, |4 h7 r' R* D1 V6 F
04 STM32输出PWM配置
+ V/ S& Z* G" m3 \1 M( n; u, _& P
分析了原理,那么下面就分析STM32生成PWM的过程。
7 ~1 b0 l+ z+ `  I& \
1、首先要将GPIO设置为复用输出

% b( r3 z1 V2 {0 d2 s

  1. 3 c2 \- y$ n1 [% A1 q; o
  2. /* GPIOE clock enable */0 H+ h3 P" R1 o3 J: T
  3. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
    / A2 g5 ?% s7 r* w- \
  4. & e9 D! ~3 _: c1 S# ~- [/ A, p
  5. /* GPIOE Configuration: TIM9 CH2(PE6)*/
    ; _5 u7 \0 o# m4 n2 ~$ [9 E
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 |GPIO_Pin_6;
    $ Q% q% d" J  }6 N$ ]  [
  7. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF;
    ( Y! V" @6 X$ ?# B7 d5 h7 z7 H
  8. GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;
    , f( w9 ~. I* v7 ^
  9. GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;
    5 A' j5 R, o% j* r
  10. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    : `' Q( Y, S6 a: T- g
  11. GPIO_Init(GPIOE, &GPIO_InitStructure);) x2 k3 `- q6 U4 A
  12. , O3 e1 N# f& q7 d# O' q7 w+ |
  13. /*Connect TIM9 pins to AF3 */  
    0 c% ]: c7 I% N/ a+ x
  14. GPIO_PinAFConfig(GPIOE,GPIO_PinSource5, GPIO_AF_TIM9);, ]2 }5 U1 T# g  {0 M
  15. GPIO_PinAFConfig(GPIOE,GPIO_PinSource6, GPIO_AF_TIM9);
复制代码

; h/ l" m: U( D6 ~; q
2、配置定时器向上计数,配置定时器频率

3 k. h1 c) m* k2 q8 j
. E/ n  p- Q  [5 C

  1. ) Z, c- V; L3 L& \
  2. /* TIM9 clock enable *// z9 f/ h0 c* G* U8 ?
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE);
    7 y6 \; }3 S' x4 Z

  4. 3 v5 T$ V6 w9 p6 |3 p- t$ H6 [
  5. /* Compute the prescaler value */
    ( t* |) V1 X' q; W# E) l& U. _
  6. PrescalerValue= (uint16_t) ((SystemCoreClock) / 2000000) - 1;  {" _: s+ |$ l3 s

  7. ! P) p( V8 M3 w/ A# p! A
  8. /* Timebase configuration */
    2 S% t8 Q4 g7 R* e# `# F
  9. TIM_TimeBaseStructure.TIM_Period =1000-1;
    2 X* s+ g. h2 c( B5 F) X
  10. TIM_TimeBaseStructure.TIM_Prescaler =PrescalerValue;5 k7 v' W6 @. y
  11. TIM_TimeBaseStructure.TIM_ClockDivision =0;& n) k; D; W1 c9 U6 O/ B+ ?
  12. TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;% h( K& H5 W! U- l- e1 y8 J" n
  13. 4 n! \7 `1 I3 n- A, Q& k, m' x
  14. TIM_TimeBaseInit(TIM9,&TIM_TimeBaseStructure);
复制代码
9 M/ {0 k8 @" K4 h
# \% P& F6 d6 r( Y$ q$ {
& l2 S# E2 H* N3 ?6 P0 t; `9 v1 k

  F8 w" F5 J3 m: U9 l
( }6 S; S( p  R# H) T
3、配置PWM输出上面分析过程较为麻烦,ST提供了标准外设库,我们只需要配置TIM_OCInitTypeDef结构体即可。$ t% _+ S' Y6 S# s5 n8 s! d

  1. . V/ W( L* C* Y; F! ^  t
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;
    ; j4 [% t, r( ~8 u- v3 d  j- T7 E
  3. ! N& @0 L/ f  @% z/ \
  4. /* PWM Modeconfiguration: Channel1 */' E% V  n! g3 j7 a: N# h4 r2 w
  5. TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_PWM1;' Y: F' A  O3 ]7 v
  6. TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;
    8 T/ I# d; |( \5 h6 u0 g+ J/ C
  7. TIM_OCInitStructure.TIM_Pulse =100-1;! |! S7 R. A2 r! c  P! K
  8. TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;- X& }" a0 B* l8 B" N4 `
  9. . g" u$ H' D# p& k5 h9 U
  10. TIM_OC1Init(TIM9,&TIM_OCInitStructure);
    ; D+ T& t  G9 \7 E: ~( U( O
  11. TIM_OC1PreloadConfig(TIM9,TIM_OCPreload_Enable);
复制代码

5 P( ^- n; a* g* t8 ?2 e; `
+ c. r% u% `, I% ~
" `: i/ z7 n  s; `6 w
TIM_OCInitTypeDef结构体解析

! p- r' S9 Y9 a% C4 S) n
  1. * z6 A$ m9 P  _$ h8 j
  2. typedef struct
      h$ Y8 T9 l6 ^8 p! I9 `
  3. {
    ) H  J1 ?( M' ]8 s; U; C5 a+ I
  4.   uint16_t TIM_OCMode;      //PWM模式1或者模式2
    0 m7 p% P! H( v3 P* E8 _3 V) G
  5. uint16_t TIM_OutputState; // 输出使能OR失能
    7 U9 `, I2 l) A" Q( s8 C$ R
  6. uint16_t TIM_OutputNState;  // PWM输出不需要
    / F+ W) M! i4 N7 ?' o1 n6 U
  7. uint32_t TIM_Pulse; // 比较值; j) e# n% [; S$ C" e
  8. uint16_t TIM_OCPolarity;// 比较输出极性/ V4 _- k% a; E/ X# o3 R
  9.   uint16_t TIM_OCNPolarity;   // PWM输出不需要
    ; h" ^$ a3 G2 K6 D( I1 u, M$ e
  10.   uint16_t TIM_OCIdleState;// PWM输出不需要) W9 p7 n5 R, V3 D) k) s
  11. uint16_t TIM_OCNIdleState; // PWM输出不需要
    2 e- Q3 W' a7 Y) [+ G5 O
  12. }TIM_OCInitTypeDef;
复制代码

2 }/ u& Y, j9 T6 U5 c# A
其中TIM_Pulse可以在初始化时设置,设置完毕后,也可以通过以下接口再次更新。
. k+ e, k+ \2 k! U
  1. 8 y9 q2 G0 ?$ a+ e- L6 k
  2. void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1)
复制代码
# J2 o+ z( G9 Y% [
) ?% r* h: M; r: m
4、使能定时器
& H- q: M' G* B6 M3 f/ S
  1. ; Z: n$ G8 Y8 ^  L  }2 o( ~
  2. TIM_ARRPreloadConfig(TIM9, ENABLE);) E, b& C, i" B* a4 b
  3. . j2 [9 h- X+ a
  4. /* TIM9 enable counter*/* g+ W9 m' o' y7 W* T! U; Y
  5. TIM_Cmd(TIM9, ENABLE);
复制代码

  ~7 @7 }+ n- v' y1 m1 F# b, [
使用timer9输出PWM的波形。
10.png
+ U  M$ Z2 e3 m; u7 [- I

) L, y: B& B6 N6 {; l
6 F( L0 I, J* W$ P" L) z/ T
1 收藏 2 评论0 发布时间:2020-9-10 10:18

举报

0个回答

所属标签

相似分享

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