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

STM32通过PWM控制电机速度

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

- @- J: ]* V! X$ |4 ?( s1 Z1 `3 _% V3 x' b

5 R7 i7 `9 f8 ?5 |做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速。分享本文了解如何通过PWM实现对电机速度的控制。
- g0 b; V8 X3 _0 v- ~- T4 L
0 T' d* Z6 Y" `4 }9 |  Y
- C5 l( K, a" g- t4 H$ M# f/ |
PWM控制电机速度的基本原理) O' e4 l3 s4 m# u1 y( f) I
    PWM(Pulse Width Modulation),也就是脉冲宽度调制。
( q7 o& P$ q* y; \/ z( U0 L0 v    PWM中有一个比较重要的概念,占空比:是一个脉冲周期内有效电平在整个周期所占的比例。
, W+ e& l( k# ]/ L
3 e0 j4 V4 O/ ?. `0 V4 }7 y3 g

7 }( W" w- x6 _    为了实现IO口上电压的持续性变化,可以调节PWM的占空比。这也能够使外设的功率进行持续性变化,最终控制直流电机转速的快慢。如何调节PWM波形的输出就是重点。% i; k. n/ T% k' q7 z
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这两个寄存器的值了。( \2 @4 @" u% ~

5 z& `& L1 M$ [
* |  w+ H$ T4 T* }- ^/ s
STM32定时器中断
/ {6 K2 g/ B; a- T/ Z    为了便于理解接下来关于PWM应用的内容,先插一段定时器中断的知识。6 ^. u- y3 w8 O% t" f# s3 s
; s( v6 Z  R7 z& F6 R
% G6 I" w. p6 T+ T1 n
    产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解、掌握。
$ F) H, F* V7 e+ o原理简介
/ w0 E# l  ]: ?2 W8 F9 v    使用通用定时器进行中断的原理,其实和开发板Systick定时器进行中断延时很相似(Stm32入门——Systick定时器),即:用psc(预分频系数)设置好定时器时钟后,arr(预装载值)在每个时钟周期内减1,当arr减为0时触发中断然后进入中断处理程序进行中断处理。以下代码为例:- ?' {& K" G  f2 T5 X9 a, W- B

  1. ' t6 J! y; K; X2 `. F1 f: o& X2 a
  2. void TIM3_Int_Init(u16 arr,u16 psc)
    - a( y6 V6 M( [
  3. {7 n7 r  @# z0 A, I$ D
  4.   RCC->APB1ENR|=1<<1;  //TIM3时钟使能    0 L+ k, l& I% d; t% W* D8 e& X
  5.    TIM3->ARR=arr;    //设定计数器自动重装值 : E' ~( e* K3 {: B
  6.   TIM3->PSC=psc;    //预分频器设置
    * j6 T& j7 I6 c$ ]) B
  7.   TIM3->DIER|=1<<0;   //允许更新中断        7 I2 D5 ^1 Z; M5 t+ M1 d
  8.   TIM3->CR1|=0x01;    //使能定时器3* d0 r1 A/ U' L3 {+ {9 q
  9.     MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2                  
    8 |- j9 X! M# i0 _. r% M$ U4 C
  10. }
复制代码
  1. RCC->APB1ENR|=1<<1
复制代码
解释一下上面这行代码,由于定时器3(TIM3)是挂在APB1上的外设,所以要打开APB1,这里的预分频器值psc是来设置TIM3的时钟频率的,如果系统时钟(SYSTICK)频率为72MHz、psc为7199,则TIM3的时钟频率就为:
0 n- j+ P* G' u/ {! u; m
  1. 72MHz/(7199+1)Hz = 10KHz    //这里的“+1”是手册中规定的。
复制代码
10KHz是什 么意思呢?就是一秒钟会产生10K个周期,那么一个周期的时间长度就是1/10KHz,如果你想将定时器中断的时间间隔设置为0.5秒,那么你将arr设置为5000即可,因为arr每减1就需要一个周期的时间,减5000次就经过了5000*(1/10KHz)=0.5秒。6 ^  i7 H: t, S  W8 w1 V
  1. TIM3->DIER|=1<<0
复制代码
再解释下上面这一行,设置允许更新中断,即arr减到0以后可以触发更新中断,还有其他类型的中断。
( ~* `3 o6 L& p" k) D% }
  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代表的是前两位给抢占优先级,后两位给响应优先级。% j8 [) T* H) l; l$ Q/ c# h* i) {* Z1 \

! B: ^( t+ D0 G: N0 D  s

3 y- {8 E, ^4 r: [+ _# Y4 LPWM模式、有效电平
( i$ u4 Q$ T6 D
# r. J( @) X) D" I' Q6 \& X! ~1 U

' Z7 q- h" P, H; B8 a# x+ M    前面介绍完中断,再说一下PWM工作原理。+ i: ~6 |1 e: Y1 p' `
8 N9 ^( }5 p0 `* m4 f

8 f" S& |% u2 N: f$ e    假设上图中ARR大于CCRx时输出为高电平,ARR小于CCRx时输出为低电平,但在实际运用中可能并非如此,有可能是相反的情况——ARR大于CCRx时输出为低电平,ARR小于CCRx时输出为高电平,至于到底是哪种情况,还要看PWM是哪种模式、有效电平又设置的是何种极性了。5 w9 h! Y: n0 m* R
8 L/ j8 i) K: n6 P3 ~4 _
* L+ `* H7 e- H! I% L5 |& f) \
模式1:ARR小于CCRx时输出为“有效”电平,ARR大于CCRx时输出为“无效”电平。0 O/ h) Z# `, d' l+ I* E3 q9 ^
; W' K- ^+ P/ j5 ]& h

3 A3 l) d0 Q+ Z模式2:ARR小于CCRx时输出为“无效”电平,ARR大于CCRx时输出为“有效”电平。
2 f+ i" T- p, ^! l/ [* C! x, V
4 m1 u0 G/ r% P

" l# |" b. P. a9 j  |9 C8 W4 [  ~9 f    这里说的是“有效”和“无效”,而不是“高”和“低”,也就是说有效电平可高可低,并非一定就是高电平。PWM模式、效电平极性,需要程序员自己配置相关的寄存器来实现。通过下面的代码来讲解。. ]8 y: C% v0 G8 L
  1. TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
复制代码
上一小节讲过关于定时器参数的设置。使用定时器1的通道1来输出一路PWM波,这里的899设置的就是ARR的值,至于那个0是用来设置TIM1的频率的,不分频就代表TIM1的时钟频率和系统时钟相同,这里假设为72MHz。. d+ O( ^( R2 F

  1. ! }& d! n- E2 L
  2. void TIM1_PWM_Init(u16 arr,u16 psc)7 M  M4 _' ~9 i5 m2 W
  3. {                " f! I+ W, y) n% ?" u
  4.   //此部分需手动修改IO口设置
    8 v( G. r. I- u+ K( A6 o" e
  5.   RCC->APB2ENR|=1<<11;   //TIM1时钟使能   
    1 T" b, _& s7 ?7 n2 C6 t. K
  6.   GPIOA->CRH&=0XFFFFFFF0;  //PA8清除之前的设置- _; k: z, ?9 Q8 L# I
  7.   GPIOA->CRH|=0X0000000B;  //复用功能输出
    - j+ K' x( h& D7 j. _
  8.   
    + k% x- [" A7 b' n- h# V- a0 i9 p" Y8 S
  9.   TIM1->ARR=arr;      //设定计数器自动重装值
    - ^* t! W* W% [+ w2 N5 \
  10.   TIM1->PSC=psc;      //预分频器设置
    9 D' h* O) b# r& R
  11.   
    2 O+ R  a: z4 z' c, R0 v6 B
  12.   TIM1->CCMR1|=7<<4;    //CH1 PWM2模式     
    0 u8 `) B  X1 h/ F, C' D
  13.   TIM1->CCMR1|=1<<3;     //CH1预装载使能   
    ( l, h9 T: b* ^5 [5 L1 V, W
  14.    TIM1->CCER|=0<<1;     //OC1 输出使能     
    & x: j# g+ |3 K  i& O6 [- N6 e
  15.   //TIM1->CCER|=1<<1;
    8 F$ I; X+ x, f
  16.   
    6 W* d, H' ~) N& g! j" F) d, J
  17.   
      k! v7 a4 B! M: I+ c
  18.   TIM1->BDTR|=1<<15;     //MOE 主输出使能     0 c4 u. L6 {2 m* R0 f+ A8 {; ^; I

  19. " M) c+ L; G  n2 W3 B4 F& q
  20.   TIM1->CR1=0x0080;     //ARPE使能
    : O3 k6 H/ L: f
  21.   TIM1->CR1|=0x01;      //使能定时器1                       
    - a- z0 k* H; q6 O3 F
  22. }
复制代码
下文具体分析上面的代码。
( c: {  F7 c# h% U( _3 r前面4-6行是用来配置GPIO口的。
/ X1 V: q" O) N2 ]# r* ~
  1. TIM1->ARR=arr; //设定计数器自动重装值
    ( A1 V+ n& \2 M" L3 _
  2. TIM1->PSC=psc; //预分频器设置
复制代码
这两行就是我上门提到的设置定时器的频率和重装载值。7 Y, o4 d+ B% a7 a7 s, i& [" u  H
  1. TIM1->CCMR1|=7<<4; //CH1 PWM2模式
    9 ], Q( [/ w& ^/ b
  2. TIM1->CCMR1|=1<<3; //CH1预装载使能
    4 D. E0 o% l8 `. Q2 f
  3. TIM1->CCER|=0<<1; //OC1 输出使能
复制代码
这三行是用来设置PWM输出模式和设置通道的,通道是什么呢?简单地讲就是输出PWM波的GPIO口,代码一开始不是设置了PA8这个GPIO口嘛,这个PA8就是通道1。使用通道的话要先进行输入输出方向、通道使能的设置。# S5 l* w$ ]4 C6 X8 ?0 N( g
  1. TIM1->CCER|=1<<1;
复制代码
这行代码是用来设置“有效电平”极性的,根据手册,当TIM1->CCER[1]这位置1时,有效电平为低电平,置0时有效电平为高电平,而默认情况下置0。4 q& o5 `2 i7 Q
  1. TIM1->BDTR|=1<<15; //MOE 主输出使能
复制代码
这行代码只要对高级定时器进行设置,普通定时器无需设置。
; P; j3 M1 }6 l4 A" G* {
  1. TIM1->CR1=0x0080; //ARPE使能
复制代码
这行代码是用来使能ARPE,ARPE是什么呢,就是当它被置1时,你自己设置的CCRx会立即生效,如果它被置为0,那么你自己设置的CCRx值不会立即生效(可能之前ARPE已经有值了),而是当之前设置的CCRx生效后才会使用你最新设置的CCRx值。
* ~( e. O. o7 @8 G, S, F0 C
, j5 Z5 I8 ^+ F# ]
' c/ u- [0 {% s8 v" ^2 {/ G
上面的代码里没有对CCRx进行设置,这是因为CCRx常常是一个变化的值,你可以在主函数中用一个for循环+if判断语句对它进行++或–的操作,从而达到连续改变CCRx值得目的,例如:4 U: f" y% w# a+ }, @/ u
  1. ) Q0 o2 e% j: C+ q# F; c( m
  2. for(i=0;i<300;i++){
    6 b( T4 ?3 U+ r* |8 p
  3.   TIM1->CCR1=i;6 G6 d) h2 a9 K0 v* y
  4.   if(i==300){  h! D8 A5 ~8 l" j0 I! Y/ C/ _
  5.     i=0;, K. R! e, }5 m  B6 v1 {+ _& ~# G
  6.   }
    " n8 s+ p' m% A5 W
  7. }
复制代码
PWM波的周期是由定时器时钟频率和预装载值两者决定的,预装载值就是ARR。
, }4 ]6 x  Y9 [4 `
6 f/ s) d+ f& N0 P, f1 s
. H- D. B" Y! ?& ^9 z( M: m. d
    预装载值PSC设置为899,那么,当定时器的当前值val从0增加到899时,一共经过了900个时钟周期,这900个时钟周期会产生一个PWM波形,也就是说900个定时器时钟周期才相当于一个PWM周期,那么PWM的频率就为72MHz/900=80KHz,周期为1/80KHz。
, g. i  k" o7 }/ h8 a
2 z- W6 h0 `1 Y. f+ ]3 n+ r
% f( y" I$ j. }1 n* `
5 d- f% X+ I, q! [! k, ~

9 Q5 y) b  w; {2 [+ M; `
& _" e) _- U5 {* I% T- X6 Y

6 {8 Z4 }# O8 g6 \6 P
1 A+ B; |/ s3 x+ B
收藏 1 评论0 发布时间:2020-12-7 10:50

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版