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

STM32通过PWM控制电机速度

[复制链接]
STMCU-管管 发布时间:2020-12-7 10:50
STM32通过PWM控制电机速度

2 F% x4 q1 H- J- I" ^

0 ~) d6 s( R$ N9 E' i' l$ I0 Q6 w做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速。分享本文了解如何通过PWM实现对电机速度的控制。
+ R# c0 r! `& n/ W7 G8 w; ?% T( B  U1 ^- t0 n

) _& u0 r& B8 aPWM控制电机速度的基本原理7 S$ z  N" s. M7 t
    PWM(Pulse Width Modulation),也就是脉冲宽度调制。" p1 {+ b2 Y: S- \: [5 o8 H
    PWM中有一个比较重要的概念,占空比:是一个脉冲周期内有效电平在整个周期所占的比例。4 X/ t6 K/ O$ Z3 }  S+ r
9 {7 F8 \. G! d( K, z

, N: T$ ^' `. n& W    为了实现IO口上电压的持续性变化,可以调节PWM的占空比。这也能够使外设的功率进行持续性变化,最终控制直流电机转速的快慢。如何调节PWM波形的输出就是重点。
% p% s$ S' C+ r4 j  I/ z. }3 v
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这两个寄存器的值了。
+ t  t$ l; x( }$ g6 o6 A7 X5 J. J6 ^4 S" `  K# N9 G
8 o3 e& Z/ L2 s, _, V
STM32定时器中断) I! \5 T9 j! O$ B) p
    为了便于理解接下来关于PWM应用的内容,先插一段定时器中断的知识。
# b) A) ~% R2 Z, d- N& `( J, x: Q! V" G: N! K( _' r. E

2 l5 E  P: {# y/ m7 V    产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解、掌握。
) K  r$ N' y. `+ y# a) [3 b原理简介
7 E8 \" H1 ?+ n. @6 B    使用通用定时器进行中断的原理,其实和开发板Systick定时器进行中断延时很相似(Stm32入门——Systick定时器),即:用psc(预分频系数)设置好定时器时钟后,arr(预装载值)在每个时钟周期内减1,当arr减为0时触发中断然后进入中断处理程序进行中断处理。以下代码为例:8 g) L6 ^1 {/ ^: `# E
  1. 0 B( z) y# I* R. _; x
  2. void TIM3_Int_Init(u16 arr,u16 psc)3 m* }3 y  O$ y
  3. {
    ( m- O$ L0 p  D5 j! v
  4.   RCC->APB1ENR|=1<<1;  //TIM3时钟使能    - C& k- M9 g+ `0 B4 H& d* t2 A3 Y
  5.    TIM3->ARR=arr;    //设定计数器自动重装值
    5 C, B0 P9 ]* x+ a
  6.   TIM3->PSC=psc;    //预分频器设置
    3 H5 X; h! j: P) E; h6 O
  7.   TIM3->DIER|=1<<0;   //允许更新中断        
    + Y1 L5 l8 D0 x' G& b
  8.   TIM3->CR1|=0x01;    //使能定时器3( A: }& n( Y3 N) L$ u/ c) v% M
  9.     MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2                   6 P/ E0 e/ i$ u' }
  10. }
复制代码
  1. RCC->APB1ENR|=1<<1
复制代码
解释一下上面这行代码,由于定时器3(TIM3)是挂在APB1上的外设,所以要打开APB1,这里的预分频器值psc是来设置TIM3的时钟频率的,如果系统时钟(SYSTICK)频率为72MHz、psc为7199,则TIM3的时钟频率就为:( S) P, R7 p# C: W) ~8 i
  1. 72MHz/(7199+1)Hz = 10KHz    //这里的“+1”是手册中规定的。
复制代码
10KHz是什 么意思呢?就是一秒钟会产生10K个周期,那么一个周期的时间长度就是1/10KHz,如果你想将定时器中断的时间间隔设置为0.5秒,那么你将arr设置为5000即可,因为arr每减1就需要一个周期的时间,减5000次就经过了5000*(1/10KHz)=0.5秒。
& p6 Y2 z3 ^/ W8 k7 B5 i  T
  1. TIM3->DIER|=1<<0
复制代码
再解释下上面这一行,设置允许更新中断,即arr减到0以后可以触发更新中断,还有其他类型的中断。
" k9 O) D3 X6 M; ~; O
  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代表的是前两位给抢占优先级,后两位给响应优先级。
' s2 D: @2 e# C7 F; D0 \; W
* L* q3 a8 C* m& w+ h! Y1 w

; J9 d* b: [) x3 k& I: ePWM模式、有效电平! @  V, I/ F4 e4 j- O
! ^8 N" s7 V* v9 C

, a( a" I! L% j, p2 d4 P$ S7 D' v4 N    前面介绍完中断,再说一下PWM工作原理。" g0 K; N1 |2 S3 Y; x1 v9 q5 [

# N5 e/ f/ H4 U9 V: ?4 L8 j
5 {( Q. G4 U) t" @' q
    假设上图中ARR大于CCRx时输出为高电平,ARR小于CCRx时输出为低电平,但在实际运用中可能并非如此,有可能是相反的情况——ARR大于CCRx时输出为低电平,ARR小于CCRx时输出为高电平,至于到底是哪种情况,还要看PWM是哪种模式、有效电平又设置的是何种极性了。  Z, \( f5 Y2 p9 d* w' c) q1 P

3 o7 t' @% I/ e/ @' k0 J

, h  C: d$ a% W! d模式1:ARR小于CCRx时输出为“有效”电平,ARR大于CCRx时输出为“无效”电平。
! e$ |5 p, Q1 W, \9 n: Z4 a& O; H' b$ o) I" k5 i8 L! V

# b  z& V) r9 n1 x/ r: ~2 A模式2:ARR小于CCRx时输出为“无效”电平,ARR大于CCRx时输出为“有效”电平。
4 F/ {! s4 I! B2 e/ y) b
. O( h) e% o- t1 N/ @

1 r6 G  i6 U" f9 I7 E3 m    这里说的是“有效”和“无效”,而不是“高”和“低”,也就是说有效电平可高可低,并非一定就是高电平。PWM模式、效电平极性,需要程序员自己配置相关的寄存器来实现。通过下面的代码来讲解。
( ?5 y  e2 f' O! f8 w2 J
  1. TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
复制代码
上一小节讲过关于定时器参数的设置。使用定时器1的通道1来输出一路PWM波,这里的899设置的就是ARR的值,至于那个0是用来设置TIM1的频率的,不分频就代表TIM1的时钟频率和系统时钟相同,这里假设为72MHz。
& n0 P- u8 n5 I; ]& V
  1. 7 {/ S- b5 i! n8 p7 i/ Q: W9 n
  2. void TIM1_PWM_Init(u16 arr,u16 psc)
    9 H. H# m  w" P% c
  3. {                4 ~# i: v3 D5 M7 ]
  4.   //此部分需手动修改IO口设置
    ( D* W; [+ A  A; m
  5.   RCC->APB2ENR|=1<<11;   //TIM1时钟使能    ; x9 W; D9 v5 D9 f* ]7 F. V
  6.   GPIOA->CRH&=0XFFFFFFF0;  //PA8清除之前的设置- y' l# J; Q- ?. N4 l4 [: [  Q
  7.   GPIOA->CRH|=0X0000000B;  //复用功能输出
    0 U- p- N' b- F$ u$ T
  8.   . V& c- Z; w4 ~/ D8 B6 g( O$ k5 e
  9.   TIM1->ARR=arr;      //设定计数器自动重装值 , \% E" }* {& _) ^9 F2 Z
  10.   TIM1->PSC=psc;      //预分频器设置
    " s2 f; n) j# ]) Z1 m* p9 H
  11.   
    / c0 B- D) |5 X1 O/ j
  12.   TIM1->CCMR1|=7<<4;    //CH1 PWM2模式     
    7 Q# i8 G  w+ }' g8 @
  13.   TIM1->CCMR1|=1<<3;     //CH1预装载使能   
    - I& }% u$ l  Y# V5 [/ K
  14.    TIM1->CCER|=0<<1;     //OC1 输出使能     
      D  t$ `, \7 [* U& C# a+ e' Y/ s8 Q1 f
  15.   //TIM1->CCER|=1<<1;  S: A8 a5 ~4 J2 D- J- r3 P
  16.   
    % X; \  ^6 y4 h, [
  17.   1 `( S* d; y2 x2 h3 }' P; W) C; D& ^
  18.   TIM1->BDTR|=1<<15;     //MOE 主输出使能     ) D# X, r: G" O/ C9 Z
  19. . I0 h$ T( J, B/ N' [& {
  20.   TIM1->CR1=0x0080;     //ARPE使能
    & q: J/ {4 r! |) e; q2 L8 ^
  21.   TIM1->CR1|=0x01;      //使能定时器1                       + u+ D" T: }) w4 w
  22. }
复制代码
下文具体分析上面的代码。
: s9 s+ p+ r: B7 B7 H8 ~% ?前面4-6行是用来配置GPIO口的。1 q6 D5 D, D9 ~) W4 S
  1. TIM1->ARR=arr; //设定计数器自动重装值+ E; `8 K( G- Y7 U8 ^
  2. TIM1->PSC=psc; //预分频器设置
复制代码
这两行就是我上门提到的设置定时器的频率和重装载值。
7 \% B* v' \; m- Q9 N9 d
  1. TIM1->CCMR1|=7<<4; //CH1 PWM2模式' A4 U: p" \$ X1 L
  2. TIM1->CCMR1|=1<<3; //CH1预装载使能# q9 @0 d+ G- R: d8 \) r5 j
  3. TIM1->CCER|=0<<1; //OC1 输出使能
复制代码
这三行是用来设置PWM输出模式和设置通道的,通道是什么呢?简单地讲就是输出PWM波的GPIO口,代码一开始不是设置了PA8这个GPIO口嘛,这个PA8就是通道1。使用通道的话要先进行输入输出方向、通道使能的设置。2 d0 m1 ~+ V, @" M8 u
  1. TIM1->CCER|=1<<1;
复制代码
这行代码是用来设置“有效电平”极性的,根据手册,当TIM1->CCER[1]这位置1时,有效电平为低电平,置0时有效电平为高电平,而默认情况下置0。
- p# n( B; c3 K9 U2 v. x* }, Y' C
  1. TIM1->BDTR|=1<<15; //MOE 主输出使能
复制代码
这行代码只要对高级定时器进行设置,普通定时器无需设置。! o) J, g  U7 c) [/ S6 e
  1. TIM1->CR1=0x0080; //ARPE使能
复制代码
这行代码是用来使能ARPE,ARPE是什么呢,就是当它被置1时,你自己设置的CCRx会立即生效,如果它被置为0,那么你自己设置的CCRx值不会立即生效(可能之前ARPE已经有值了),而是当之前设置的CCRx生效后才会使用你最新设置的CCRx值。5 q1 `9 a6 ^% s, }" z5 E
* h: U, K& m. T9 o" l$ l1 @
; `9 H& w* F; n
上面的代码里没有对CCRx进行设置,这是因为CCRx常常是一个变化的值,你可以在主函数中用一个for循环+if判断语句对它进行++或–的操作,从而达到连续改变CCRx值得目的,例如:
. ~6 R/ ^( l7 e' G: ?1 O

  1. * _  H) B8 s  C) B; A+ N, |+ k5 N: z
  2. for(i=0;i<300;i++){& P0 Q" |# M. h; A& i
  3.   TIM1->CCR1=i;
    7 P  h3 T- ?3 y1 _4 q$ ?  I+ V& e! }
  4.   if(i==300){5 O# b$ F! r% r0 l2 J
  5.     i=0;. M: P/ o9 O0 }5 v5 |! n8 r# @. A
  6.   }; e' v% T$ e; y* Q- y# k
  7. }
复制代码
PWM波的周期是由定时器时钟频率和预装载值两者决定的,预装载值就是ARR。
/ i' G% d/ @9 n
8 h+ ~# e, w3 Q& \# B
6 l2 A* I8 d) F, q
    预装载值PSC设置为899,那么,当定时器的当前值val从0增加到899时,一共经过了900个时钟周期,这900个时钟周期会产生一个PWM波形,也就是说900个定时器时钟周期才相当于一个PWM周期,那么PWM的频率就为72MHz/900=80KHz,周期为1/80KHz。
( U7 e% ^( l8 A3 L
! H' O) n  E0 A  \& X' Q4 v7 T
) x; `1 N! P$ i1 U/ c! l
" U% ?4 h. z( w3 X! K
6 B2 B6 s) y7 M. O0 e

, @0 \9 c6 o: m6 d# k1 `) K9 _
: N, w* G* s0 U9 w( Y6 `; d/ K" Q
8 j( @& c, i. c9 J
赞 收藏 1 评论0 发布时间:2020-12-7 10:50

举报

0个回答

所属标签

相似技术帖

官网相关资源

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