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

STM32通过PWM控制电机速度

[复制链接]
STMCU-管管 发布时间:2020-12-7 10:50
STM32通过PWM控制电机速度
# \4 ~4 Q$ f9 c3 x' S0 H: u
1 M3 @% s4 l1 R2 k5 E8 r/ e- q) q
做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速。分享本文了解如何通过PWM实现对电机速度的控制。
* K3 `  Z9 ?3 s& \# H+ x' f; P1 C2 b  M( t
+ H, D( W  ?0 z9 I. u/ m
PWM控制电机速度的基本原理
3 u+ f/ ?' U* K    PWM(Pulse Width Modulation),也就是脉冲宽度调制。
1 ?. G. o5 B9 {- Q: x1 {    PWM中有一个比较重要的概念,占空比:是一个脉冲周期内有效电平在整个周期所占的比例。
" z9 n5 S1 k" K5 s5 Y( \( e
4 ]- @7 g; Y3 }2 U/ W3 i
( a! z- Z0 [- u
    为了实现IO口上电压的持续性变化,可以调节PWM的占空比。这也能够使外设的功率进行持续性变化,最终控制直流电机转速的快慢。如何调节PWM波形的输出就是重点。
: R# A) b' T7 B
11.png
    上图中的ARR是我们给定时器的一个预装载值,CCRx的上下变化是产生PWM波的关键。我们假设ARR大于CCRx的部分输出为高电平(即t1-t2、t3-t4、t5-t6),ARR小于CCRx的部分输出为低电平(即0-t1、t2-t3、t4-t5),则改变CCRx的值就能改变输出PWM的占空比。因此,想要控制PWM的输出波形,重要的就是如何设置ARR与CCRx这两个寄存器的值了。# @$ E+ C, G# \3 X6 T5 {, B- n6 {

; d7 z3 {7 L* l# `# U; W

- k' s( |  U- H& L& VSTM32定时器中断4 ^9 f. h6 k& q1 L8 L5 X- c( @
    为了便于理解接下来关于PWM应用的内容,先插一段定时器中断的知识。3 ~# o3 c9 J0 h  z2 P# @! P
% T* W2 v, t$ B3 ^- l' B

, N6 l1 c' e$ t    产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解、掌握。
  `" D& u0 d2 l0 y, n; a原理简介6 ^8 n6 b/ k/ j; b# h
    使用通用定时器进行中断的原理,其实和开发板Systick定时器进行中断延时很相似(Stm32入门——Systick定时器),即:用psc(预分频系数)设置好定时器时钟后,arr(预装载值)在每个时钟周期内减1,当arr减为0时触发中断然后进入中断处理程序进行中断处理。以下代码为例:
# l4 ^( v- e0 \$ T

  1. ) B+ N9 w% I. h: s) ^  Y" n& B* k
  2. void TIM3_Int_Init(u16 arr,u16 psc)
    & o( }) C0 D  ^, d5 P5 f$ Y- s
  3. {
    ' N) u/ v; F3 I$ B* p4 g$ j
  4.   RCC->APB1ENR|=1<<1;  //TIM3时钟使能    9 f& l0 k4 c4 c6 `
  5.    TIM3->ARR=arr;    //设定计数器自动重装值 5 B, N4 C7 O" t4 H) V% W) D; z3 h2 u
  6.   TIM3->PSC=psc;    //预分频器设置% {. S& C4 P* Q& O
  7.   TIM3->DIER|=1<<0;   //允许更新中断        9 G/ C2 r2 Q5 b+ ~9 t" ^
  8.   TIM3->CR1|=0x01;    //使能定时器3! ^3 ^/ T; @6 ~- y
  9.     MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2                  
    ( a, f3 b0 M7 @% r2 X
  10. }
复制代码
  1. RCC->APB1ENR|=1<<1
复制代码
解释一下上面这行代码,由于定时器3(TIM3)是挂在APB1上的外设,所以要打开APB1,这里的预分频器值psc是来设置TIM3的时钟频率的,如果系统时钟(SYSTICK)频率为72MHz、psc为7199,则TIM3的时钟频率就为:
/ l' B& ^0 }6 z/ L, c! Q/ t9 G
  1. 72MHz/(7199+1)Hz = 10KHz    //这里的“+1”是手册中规定的。
复制代码
10KHz是什 么意思呢?就是一秒钟会产生10K个周期,那么一个周期的时间长度就是1/10KHz,如果你想将定时器中断的时间间隔设置为0.5秒,那么你将arr设置为5000即可,因为arr每减1就需要一个周期的时间,减5000次就经过了5000*(1/10KHz)=0.5秒。! }9 F, x. ^( o# x2 _) G
  1. TIM3->DIER|=1<<0
复制代码
再解释下上面这一行,设置允许更新中断,即arr减到0以后可以触发更新中断,还有其他类型的中断。
$ X' x+ V; n2 m% I0 }: ]
  1. MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2
复制代码
看上面这行代码,中断优先级有抢占优先级和响应(即子优先级)优先级两种,抢占优先级即:若程序1正在使用CPU,这时如果程序2要求使用CPU,并且程序2的抢占优先级高,则CPU被程序2抢占;若两者抢占优先级相同,则就算程序2的响应优先级高于程序1,CPU也不能被抢占;若程序1正在使用CPU,程序2和程序3的抢占优先级等于或低于程序1,且程序2的响应优先级高于程序三,则待CPU空出后,程序2先运行,程序3最后运行。TIM3_IRQn是指定将要运行的中断处理程序号。“组2”是设置中断优先级分组的,这是因为寄存器提供了四位来设置优先级,组2代表的是前两位给抢占优先级,后两位给响应优先级。
/ U6 p- S; t8 x$ C4 \
, K( x% v, g$ K( j1 r" e7 F$ H2 K

. E" K1 j2 a) l& J( APWM模式、有效电平$ ?2 ~. T3 r5 x* V3 _1 w  J  W

* Q6 \! W" D+ X) A* ~# ?

$ o2 O4 R1 k0 y, o2 q. K$ D8 [3 [* N    前面介绍完中断,再说一下PWM工作原理。4 \$ v/ [6 }" N" ]; \
; C" a$ G1 w3 l. B
/ \, E$ h% Q# A
    假设上图中ARR大于CCRx时输出为高电平,ARR小于CCRx时输出为低电平,但在实际运用中可能并非如此,有可能是相反的情况——ARR大于CCRx时输出为低电平,ARR小于CCRx时输出为高电平,至于到底是哪种情况,还要看PWM是哪种模式、有效电平又设置的是何种极性了。2 T5 G% p2 k9 e% L! q6 d# m
- D  U" D0 c- H

6 y1 O" ~* g9 ~3 @( D( r( D2 F模式1:ARR小于CCRx时输出为“有效”电平,ARR大于CCRx时输出为“无效”电平。
2 W- j- F- ~: Z6 @3 A
4 B' ]  \( \8 e' m4 R* D* h9 q
9 d' S4 m: j- K4 m4 L# d3 ~7 l
模式2:ARR小于CCRx时输出为“无效”电平,ARR大于CCRx时输出为“有效”电平。- o5 W& t0 m# u; w3 y1 u1 b% P

# w, s6 a6 O* s# z: `6 ]. A

  ]) }4 f: a& v    这里说的是“有效”和“无效”,而不是“高”和“低”,也就是说有效电平可高可低,并非一定就是高电平。PWM模式、效电平极性,需要程序员自己配置相关的寄存器来实现。通过下面的代码来讲解。3 P' b# }$ `1 }
  1. TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
复制代码
上一小节讲过关于定时器参数的设置。使用定时器1的通道1来输出一路PWM波,这里的899设置的就是ARR的值,至于那个0是用来设置TIM1的频率的,不分频就代表TIM1的时钟频率和系统时钟相同,这里假设为72MHz。
# Q+ |! _! k5 k5 L/ o7 i

  1. % a3 m( o2 V4 w5 _9 c& l' R
  2. void TIM1_PWM_Init(u16 arr,u16 psc)
    3 h; o  y( |( e& o
  3. {                # T. _' W% r2 B7 h/ O
  4.   //此部分需手动修改IO口设置
    / k" [7 j( x2 ~0 T
  5.   RCC->APB2ENR|=1<<11;   //TIM1时钟使能    . W9 N! n3 g) N: l9 N( k, T
  6.   GPIOA->CRH&=0XFFFFFFF0;  //PA8清除之前的设置: }' e1 V. H1 b0 _7 r" \
  7.   GPIOA->CRH|=0X0000000B;  //复用功能输出
    # i6 p8 U( G# d8 `' K$ j; g, z' m3 g
  8.   
    ; u1 c4 ~5 m( ?8 V% h/ A' y, I* p
  9.   TIM1->ARR=arr;      //设定计数器自动重装值 4 s0 O' D7 V7 |% a
  10.   TIM1->PSC=psc;      //预分频器设置( B  S9 ^; J# j! C
  11.   . s& m& u; t% e' c2 s- N
  12.   TIM1->CCMR1|=7<<4;    //CH1 PWM2模式     3 z4 h# d$ k- P( @, b; w! Q* O/ b% c
  13.   TIM1->CCMR1|=1<<3;     //CH1预装载使能   0 h; }6 h9 y4 D' f+ I
  14.    TIM1->CCER|=0<<1;     //OC1 输出使能     
    2 _1 G/ }) P1 I
  15.   //TIM1->CCER|=1<<1;
    # t5 t5 p) T9 M  R" T) O
  16.     B8 o3 l  K8 w- w% ^
  17.   2 Z1 b  }% h& L+ R8 ^
  18.   TIM1->BDTR|=1<<15;     //MOE 主输出使能     
    $ y1 m7 w( y* t4 D
  19. ; w) Y) J' D+ k0 Z2 b8 H
  20.   TIM1->CR1=0x0080;     //ARPE使能 $ _1 S# t$ d+ u) M0 {- N9 f
  21.   TIM1->CR1|=0x01;      //使能定时器1                       
    - i0 ^" }; J$ o
  22. }
复制代码
下文具体分析上面的代码。
3 d4 q. H+ ~) |( n前面4-6行是用来配置GPIO口的。* z- P: Y% H# X2 o- h
  1. TIM1->ARR=arr; //设定计数器自动重装值
    * _" V. k5 O6 s2 _1 Q3 u/ U
  2. TIM1->PSC=psc; //预分频器设置
复制代码
这两行就是我上门提到的设置定时器的频率和重装载值。
" ]+ T9 X, c+ M' Y* Q
  1. TIM1->CCMR1|=7<<4; //CH1 PWM2模式4 x; v# C- d( B! j5 e' T
  2. TIM1->CCMR1|=1<<3; //CH1预装载使能* ?  c) r# x% l/ l% B
  3. TIM1->CCER|=0<<1; //OC1 输出使能
复制代码
这三行是用来设置PWM输出模式和设置通道的,通道是什么呢?简单地讲就是输出PWM波的GPIO口,代码一开始不是设置了PA8这个GPIO口嘛,这个PA8就是通道1。使用通道的话要先进行输入输出方向、通道使能的设置。
2 y. `2 |& k( @* q2 L. A% z
  1. TIM1->CCER|=1<<1;
复制代码
这行代码是用来设置“有效电平”极性的,根据手册,当TIM1->CCER[1]这位置1时,有效电平为低电平,置0时有效电平为高电平,而默认情况下置0。
* I8 _  \1 }* B
  1. TIM1->BDTR|=1<<15; //MOE 主输出使能
复制代码
这行代码只要对高级定时器进行设置,普通定时器无需设置。
% O/ @0 h+ M; w6 P& j1 d
  1. TIM1->CR1=0x0080; //ARPE使能
复制代码
这行代码是用来使能ARPE,ARPE是什么呢,就是当它被置1时,你自己设置的CCRx会立即生效,如果它被置为0,那么你自己设置的CCRx值不会立即生效(可能之前ARPE已经有值了),而是当之前设置的CCRx生效后才会使用你最新设置的CCRx值。$ w- V, f2 s5 w8 I8 C1 I) U5 _

9 }) a: s0 N: H6 Y: A/ ~: G. B
; H7 K8 [, t1 F
上面的代码里没有对CCRx进行设置,这是因为CCRx常常是一个变化的值,你可以在主函数中用一个for循环+if判断语句对它进行++或–的操作,从而达到连续改变CCRx值得目的,例如:
+ B: {4 z: ]3 V9 D
  1. ( U/ S# ~, L6 x: Y# `+ o, e
  2. for(i=0;i<300;i++){7 h% l+ D% s" R. N6 o" N6 `
  3.   TIM1->CCR1=i;
    * R% \% P; n2 M* Z0 s  D7 M* }
  4.   if(i==300){  I" D4 c  X) Y! l* Q% U
  5.     i=0;
    $ m: ~9 U' J( ?, R+ P8 S/ t7 T7 W
  6.   }
    6 ?+ u1 }: R3 H! |' h
  7. }
复制代码
PWM波的周期是由定时器时钟频率和预装载值两者决定的,预装载值就是ARR。' K' ]$ T4 t$ v' c$ z4 q

. u$ R5 R' z( {: u4 K6 z! N! `. V! t6 i

) I, o. ^  n* n. e    预装载值PSC设置为899,那么,当定时器的当前值val从0增加到899时,一共经过了900个时钟周期,这900个时钟周期会产生一个PWM波形,也就是说900个定时器时钟周期才相当于一个PWM周期,那么PWM的频率就为72MHz/900=80KHz,周期为1/80KHz。& e. D7 ?# U3 c7 v% ?: s
; ~0 ^- b4 y- K
* D6 u* i% O4 m% O9 B, n$ _- _- z. ^5 N

) T6 ?& V$ D+ p% D+ u) k
/ \& [2 y: t( {4 |; K

5 }  c$ P" N2 r2 r

+ k7 K7 g1 _1 V% W  M. R/ m
" P' T3 a/ N3 v" h3 [$ C
收藏 1 评论0 发布时间:2020-12-7 10:50

举报

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