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

STM32通过PWM控制电机速度

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

- w  j/ k) A# g

' l' v8 ]6 p' S" ]/ I- q做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速。分享本文了解如何通过PWM实现对电机速度的控制。- m9 e0 d$ B' N' \! M; q  \

/ Z8 v) q% S7 z
, s" t3 q$ p6 ^8 z
PWM控制电机速度的基本原理
9 p' }$ H& o/ C4 F( v    PWM(Pulse Width Modulation),也就是脉冲宽度调制。
; }# d6 }  r% g% S; [    PWM中有一个比较重要的概念,占空比:是一个脉冲周期内有效电平在整个周期所占的比例。
: @0 _' S+ L0 v. Q7 E( s' Q0 E2 U% N8 Y1 f7 f; |$ u( k8 D

1 v1 ]1 k; n' d    为了实现IO口上电压的持续性变化,可以调节PWM的占空比。这也能够使外设的功率进行持续性变化,最终控制直流电机转速的快慢。如何调节PWM波形的输出就是重点。
& O' f3 |' `5 a2 C' f0 t; @. K: p
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 q% U2 W  A; y5 C
! A$ `' h: [- @5 e- C# t7 s
& L+ m5 E3 Q! v3 G5 Z) w) u" }
STM32定时器中断8 t. z+ r/ u1 ?$ ^; E
    为了便于理解接下来关于PWM应用的内容,先插一段定时器中断的知识。
0 A6 ^$ t% R* C) R' O  A- n0 q4 q1 m, q
; L3 B9 }8 O. z. x0 {3 C8 p
    产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解、掌握。
$ P2 n% l3 k) q9 D. W  M; p* R原理简介
/ q  M& b3 r2 J4 x* Y# \1 u, X    使用通用定时器进行中断的原理,其实和开发板Systick定时器进行中断延时很相似(Stm32入门——Systick定时器),即:用psc(预分频系数)设置好定时器时钟后,arr(预装载值)在每个时钟周期内减1,当arr减为0时触发中断然后进入中断处理程序进行中断处理。以下代码为例:
! k* a) h( `2 G, F/ s' y) Q

  1. : u! S3 h! e0 [
  2. void TIM3_Int_Init(u16 arr,u16 psc)
    * X/ w; G, O, X9 O; s) b1 X
  3. {
    ! Z  [9 W7 Z; r# r  S7 z/ j
  4.   RCC->APB1ENR|=1<<1;  //TIM3时钟使能   
    4 W" k" w/ T; o7 r. t' A
  5.    TIM3->ARR=arr;    //设定计数器自动重装值 ; K  n# N* X4 j/ r4 A
  6.   TIM3->PSC=psc;    //预分频器设置
    + U$ \" a) A* j2 o% ?/ z' ]3 q. \
  7.   TIM3->DIER|=1<<0;   //允许更新中断        
    - |. E+ r, I1 ^7 |; _7 W
  8.   TIM3->CR1|=0x01;    //使能定时器3
    ) `+ H' D  H9 \" {/ P* ]- P
  9.     MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2                   0 s  K5 W4 o# H, G/ X! D0 t
  10. }
复制代码
  1. RCC->APB1ENR|=1<<1
复制代码
解释一下上面这行代码,由于定时器3(TIM3)是挂在APB1上的外设,所以要打开APB1,这里的预分频器值psc是来设置TIM3的时钟频率的,如果系统时钟(SYSTICK)频率为72MHz、psc为7199,则TIM3的时钟频率就为:, m) K# V1 w/ b: f' ?0 I
  1. 72MHz/(7199+1)Hz = 10KHz    //这里的“+1”是手册中规定的。
复制代码
10KHz是什 么意思呢?就是一秒钟会产生10K个周期,那么一个周期的时间长度就是1/10KHz,如果你想将定时器中断的时间间隔设置为0.5秒,那么你将arr设置为5000即可,因为arr每减1就需要一个周期的时间,减5000次就经过了5000*(1/10KHz)=0.5秒。. x+ t9 w8 D* @
  1. TIM3->DIER|=1<<0
复制代码
再解释下上面这一行,设置允许更新中断,即arr减到0以后可以触发更新中断,还有其他类型的中断。
3 ^( g2 z# q1 g1 a) `+ X9 |' r
  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代表的是前两位给抢占优先级,后两位给响应优先级。
4 g! {7 b2 _$ A7 z& q' E) P4 \% e1 n7 [1 W' B  f! s
8 G( T* S. _, N* }/ Y" Z' o$ e/ f1 e5 T
PWM模式、有效电平
5 e4 x7 I2 ?0 X$ Q
' w) f& M! W+ c- N  k0 R

' z3 ?5 ?4 c) _7 ?3 ~    前面介绍完中断,再说一下PWM工作原理。
; _$ m  f3 k# D5 ~; d: p9 ]8 n
5 e" T( V+ G) {6 y
: R  B' ~9 Q3 C) r1 q' t
    假设上图中ARR大于CCRx时输出为高电平,ARR小于CCRx时输出为低电平,但在实际运用中可能并非如此,有可能是相反的情况——ARR大于CCRx时输出为低电平,ARR小于CCRx时输出为高电平,至于到底是哪种情况,还要看PWM是哪种模式、有效电平又设置的是何种极性了。
4 p8 U( P. ]9 R) p1 A
; x% r9 R3 W3 S
) r) _. o' y8 U
模式1:ARR小于CCRx时输出为“有效”电平,ARR大于CCRx时输出为“无效”电平。
( G9 D+ p/ h5 h7 Q% Q5 K4 P: q8 z$ e- v# E3 {. U  Y; i# a! |' A

' W0 T3 x# ]" T6 d1 h& M9 C/ h' A+ i模式2:ARR小于CCRx时输出为“无效”电平,ARR大于CCRx时输出为“有效”电平。& z' d- F! C% s; [

! _% n2 ^# L, B6 Y9 f+ @  R0 h
& F) O( Z+ d9 P% ^. F
    这里说的是“有效”和“无效”,而不是“高”和“低”,也就是说有效电平可高可低,并非一定就是高电平。PWM模式、效电平极性,需要程序员自己配置相关的寄存器来实现。通过下面的代码来讲解。
# l3 r2 @# F9 X6 X( ^! {$ \
  1. TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
复制代码
上一小节讲过关于定时器参数的设置。使用定时器1的通道1来输出一路PWM波,这里的899设置的就是ARR的值,至于那个0是用来设置TIM1的频率的,不分频就代表TIM1的时钟频率和系统时钟相同,这里假设为72MHz。! F1 w* X$ b  u+ W; \

  1. 2 _. }$ ]8 r- Q' d3 ^
  2. void TIM1_PWM_Init(u16 arr,u16 psc)# e  s) {1 I$ x, m
  3. {                / j2 ^$ r1 H% a3 M
  4.   //此部分需手动修改IO口设置
    & [2 c, m' q, T: n- {
  5.   RCC->APB2ENR|=1<<11;   //TIM1时钟使能    9 Z% ^7 L8 U8 \- T! n9 M9 s5 B
  6.   GPIOA->CRH&=0XFFFFFFF0;  //PA8清除之前的设置7 l& l$ ?+ F6 J" g% R+ d
  7.   GPIOA->CRH|=0X0000000B;  //复用功能输出
    9 v4 N: X6 E: t1 \5 J! v. ?
  8.   $ p; o0 e6 O5 h' W* `. q- e" {
  9.   TIM1->ARR=arr;      //设定计数器自动重装值
    ! P' Y! {' A- B
  10.   TIM1->PSC=psc;      //预分频器设置
    ! u2 b, ?# H5 Q1 h4 C6 p
  11.   
    0 }! L2 J" S6 a- R6 e4 F$ K- P# D
  12.   TIM1->CCMR1|=7<<4;    //CH1 PWM2模式     
    # y  N( g- x) [7 e. m
  13.   TIM1->CCMR1|=1<<3;     //CH1预装载使能   
    & `$ `$ S; n9 j+ B; B# S, O
  14.    TIM1->CCER|=0<<1;     //OC1 输出使能     
    , d: z* p) G3 i* p, R3 I# m
  15.   //TIM1->CCER|=1<<1;! `, s5 K+ t  ^* A( K
  16.   ( Q6 R1 a% C7 m
  17.   
    5 {, p+ D2 V! C" b% F$ _+ K0 m/ G
  18.   TIM1->BDTR|=1<<15;     //MOE 主输出使能     % ^* p* m0 E' h5 Z- V2 P# B; a

  19. ' c5 n7 C4 s. z/ K3 i9 q, I  M. C
  20.   TIM1->CR1=0x0080;     //ARPE使能 , T! e7 B' z8 `' S9 M
  21.   TIM1->CR1|=0x01;      //使能定时器1                       : \3 d! i9 I3 l6 Q; `" @' |# z. l
  22. }
复制代码
下文具体分析上面的代码。: j: Q5 ]+ _. ~5 k6 `# M* E
前面4-6行是用来配置GPIO口的。& ]6 x  o& G; R" H$ h
  1. TIM1->ARR=arr; //设定计数器自动重装值
    + E, m" x5 X+ b/ \/ `* F/ {! Y
  2. TIM1->PSC=psc; //预分频器设置
复制代码
这两行就是我上门提到的设置定时器的频率和重装载值。. m2 l4 K3 z! i$ k# S4 C& ]) j: I
  1. TIM1->CCMR1|=7<<4; //CH1 PWM2模式5 @$ Z. R8 U6 r* c
  2. TIM1->CCMR1|=1<<3; //CH1预装载使能
    : ~! R5 P* s/ Y: N& Q; I: `
  3. TIM1->CCER|=0<<1; //OC1 输出使能
复制代码
这三行是用来设置PWM输出模式和设置通道的,通道是什么呢?简单地讲就是输出PWM波的GPIO口,代码一开始不是设置了PA8这个GPIO口嘛,这个PA8就是通道1。使用通道的话要先进行输入输出方向、通道使能的设置。8 H; l. n8 }  n# |4 T, _. |! X
  1. TIM1->CCER|=1<<1;
复制代码
这行代码是用来设置“有效电平”极性的,根据手册,当TIM1->CCER[1]这位置1时,有效电平为低电平,置0时有效电平为高电平,而默认情况下置0。, m4 O% U6 \" t
  1. TIM1->BDTR|=1<<15; //MOE 主输出使能
复制代码
这行代码只要对高级定时器进行设置,普通定时器无需设置。9 q) X& D9 {6 \/ w' y
  1. TIM1->CR1=0x0080; //ARPE使能
复制代码
这行代码是用来使能ARPE,ARPE是什么呢,就是当它被置1时,你自己设置的CCRx会立即生效,如果它被置为0,那么你自己设置的CCRx值不会立即生效(可能之前ARPE已经有值了),而是当之前设置的CCRx生效后才会使用你最新设置的CCRx值。
6 g, J+ S) T% t+ `2 D6 O, m
8 Z$ {! U; x0 J$ v
$ Q! x9 ~2 C" P8 n; M4 x; b0 Y
上面的代码里没有对CCRx进行设置,这是因为CCRx常常是一个变化的值,你可以在主函数中用一个for循环+if判断语句对它进行++或–的操作,从而达到连续改变CCRx值得目的,例如:% _9 {* g5 k8 ]' R% c/ F# l

  1. & M- H3 G( j6 K5 }0 y& ?
  2. for(i=0;i<300;i++){
    4 q" W- N8 s- q" W% s4 e
  3.   TIM1->CCR1=i;
    ! Q, w1 `" F/ N
  4.   if(i==300){
    - N! F. J  E, g5 K2 o4 b
  5.     i=0;
    & @6 H  x  ?1 F5 u# H8 z
  6.   }2 o0 s$ A1 c" g  H) B
  7. }
复制代码
PWM波的周期是由定时器时钟频率和预装载值两者决定的,预装载值就是ARR。$ U0 w  ~$ d3 }$ c" i- H& Y' p
% W* I, {' B8 o" L0 y9 ]. v

6 m1 _, N! ?8 [5 |& y9 |    预装载值PSC设置为899,那么,当定时器的当前值val从0增加到899时,一共经过了900个时钟周期,这900个时钟周期会产生一个PWM波形,也就是说900个定时器时钟周期才相当于一个PWM周期,那么PWM的频率就为72MHz/900=80KHz,周期为1/80KHz。
) h/ c; t" ?% b7 k  ^9 ?3 C6 C9 n1 z  j6 j
4 T; N. X" Z# X' @
- ~' |% w0 Y- _) E) e" U

! o# v3 q( U; {, R: d/ X
, j) q1 B2 i& z2 h
  U$ f: R5 C$ s2 G8 u' z
+ h2 C3 ?- _0 q  c0 I) U% c. X
收藏 1 评论0 发布时间:2020-12-7 10:50

举报

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