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

STM32通过PWM控制电机速度

[复制链接]
STMCU-管管 发布时间:2020-12-7 10:50
STM32通过PWM控制电机速度
1 D' {; p0 A/ D- L: H

! s, m: z) D% E+ p+ e做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速。分享本文了解如何通过PWM实现对电机速度的控制。* I6 ^* m, B! D& {6 C( T" X
4 K! I$ @) X$ q- t3 U

( i. c5 S6 _  v1 c8 l  QPWM控制电机速度的基本原理
3 Z2 ^: u9 R0 _    PWM(Pulse Width Modulation),也就是脉冲宽度调制。
1 t  M7 }8 A1 W" f. b    PWM中有一个比较重要的概念,占空比:是一个脉冲周期内有效电平在整个周期所占的比例。% \: O2 j, n4 s) ]. Z* }( Q* b

7 |! w" `) v3 ^$ t( E8 W3 ?( |& F
$ [: A" i4 V8 d% s, U! c
    为了实现IO口上电压的持续性变化,可以调节PWM的占空比。这也能够使外设的功率进行持续性变化,最终控制直流电机转速的快慢。如何调节PWM波形的输出就是重点。  R+ p$ ?% a+ O" f& S8 S4 ]
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这两个寄存器的值了。
' X$ }  X( @' s5 z
+ x  }$ f' a$ D! Y) g: |

+ K' h1 D6 c/ I7 ~STM32定时器中断
8 k, u" R4 j2 g$ x  V6 x    为了便于理解接下来关于PWM应用的内容,先插一段定时器中断的知识。: S/ B- \$ P% n, j- y. j

0 K+ h8 M0 `6 _

+ m& ], U+ O; N. m    产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解、掌握。6 D" Q& U; H1 H
原理简介
3 L) b' e2 ^3 T# U& y9 K% O, ]9 u    使用通用定时器进行中断的原理,其实和开发板Systick定时器进行中断延时很相似(Stm32入门——Systick定时器),即:用psc(预分频系数)设置好定时器时钟后,arr(预装载值)在每个时钟周期内减1,当arr减为0时触发中断然后进入中断处理程序进行中断处理。以下代码为例:( G: b% ~) V9 Q" n; ~8 _+ i
  1. / x2 v, s5 ]/ k. O& z
  2. void TIM3_Int_Init(u16 arr,u16 psc)+ R  ?; ]" ~& A5 h1 s. Z9 ~6 F: r
  3. {( s, v2 J% f: A- T! P( J- o
  4.   RCC->APB1ENR|=1<<1;  //TIM3时钟使能   
    5 X; T* \' t+ j+ W* v1 v. \
  5.    TIM3->ARR=arr;    //设定计数器自动重装值 " f. M( o% r5 O- @. f# t* p
  6.   TIM3->PSC=psc;    //预分频器设置
    / K3 M7 W$ v: }# E
  7.   TIM3->DIER|=1<<0;   //允许更新中断        
    4 O9 D6 N2 S( ^  {) ]
  8.   TIM3->CR1|=0x01;    //使能定时器3' d' {' e5 q$ e# `2 @: j+ [
  9.     MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2                     I1 m. A+ t- r" O4 ]
  10. }
复制代码
  1. RCC->APB1ENR|=1<<1
复制代码
解释一下上面这行代码,由于定时器3(TIM3)是挂在APB1上的外设,所以要打开APB1,这里的预分频器值psc是来设置TIM3的时钟频率的,如果系统时钟(SYSTICK)频率为72MHz、psc为7199,则TIM3的时钟频率就为:+ T9 A) D$ ?8 z1 ~( X. S  u9 F) \
  1. 72MHz/(7199+1)Hz = 10KHz    //这里的“+1”是手册中规定的。
复制代码
10KHz是什 么意思呢?就是一秒钟会产生10K个周期,那么一个周期的时间长度就是1/10KHz,如果你想将定时器中断的时间间隔设置为0.5秒,那么你将arr设置为5000即可,因为arr每减1就需要一个周期的时间,减5000次就经过了5000*(1/10KHz)=0.5秒。
) K/ i1 ?) T; c: g! R3 p  }
  1. TIM3->DIER|=1<<0
复制代码
再解释下上面这一行,设置允许更新中断,即arr减到0以后可以触发更新中断,还有其他类型的中断。
. `, }- @& c+ O2 U! C
  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代表的是前两位给抢占优先级,后两位给响应优先级。) g! X, I' z) u0 M4 t

& ?# i% P( q5 X# I! O

6 O1 a+ A/ o5 u' \PWM模式、有效电平
. `! K1 q$ K6 f3 V3 `$ `. B3 k' L3 W: A" P* N8 Q) X

/ Z, h, s, Y6 c4 K) {6 q; Q! }    前面介绍完中断,再说一下PWM工作原理。& R) z7 z% l6 M0 B/ ]9 x3 ^

4 r7 l# I9 O9 r6 X" A' a
" R" n/ L2 I+ `1 r$ j4 ]* y; N
    假设上图中ARR大于CCRx时输出为高电平,ARR小于CCRx时输出为低电平,但在实际运用中可能并非如此,有可能是相反的情况——ARR大于CCRx时输出为低电平,ARR小于CCRx时输出为高电平,至于到底是哪种情况,还要看PWM是哪种模式、有效电平又设置的是何种极性了。: n0 G6 A( p* k- ?; ]4 d

2 q# m$ Q. n1 k+ a1 _3 Q. ?1 a

* L2 G. G% B. a- Y: l2 J3 |模式1:ARR小于CCRx时输出为“有效”电平,ARR大于CCRx时输出为“无效”电平。
9 x2 B, X( T( L/ `' I- _3 j( R  B+ T* H5 s$ K5 u! z

2 |4 y% M/ x; D模式2:ARR小于CCRx时输出为“无效”电平,ARR大于CCRx时输出为“有效”电平。' q5 v" u' w- ?/ Z( r
1 T( z5 H2 \6 q$ b; ~

9 o5 i/ s9 Y- n9 x9 ^    这里说的是“有效”和“无效”,而不是“高”和“低”,也就是说有效电平可高可低,并非一定就是高电平。PWM模式、效电平极性,需要程序员自己配置相关的寄存器来实现。通过下面的代码来讲解。
# _' M/ I1 O1 t5 Y  X
  1. TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
复制代码
上一小节讲过关于定时器参数的设置。使用定时器1的通道1来输出一路PWM波,这里的899设置的就是ARR的值,至于那个0是用来设置TIM1的频率的,不分频就代表TIM1的时钟频率和系统时钟相同,这里假设为72MHz。
/ Q- w8 [- H$ p! J; s7 _- A

  1. $ R# Z& j6 Q4 A& j1 w2 J$ v
  2. void TIM1_PWM_Init(u16 arr,u16 psc)
    ! y! i1 j+ e* P' x
  3. {               
    9 c1 a; n, M4 ]2 V8 E! J
  4.   //此部分需手动修改IO口设置
    2 M" i9 K7 ~; E0 x
  5.   RCC->APB2ENR|=1<<11;   //TIM1时钟使能    0 q$ ~1 q" `  L* O
  6.   GPIOA->CRH&=0XFFFFFFF0;  //PA8清除之前的设置2 u/ i* u4 ]* y
  7.   GPIOA->CRH|=0X0000000B;  //复用功能输出
    9 L! H# o& N3 }  n8 t% h
  8.   / m  _# ?/ z$ {5 G' ^
  9.   TIM1->ARR=arr;      //设定计数器自动重装值 ' _$ r2 m0 e1 M' `0 p; ]7 F
  10.   TIM1->PSC=psc;      //预分频器设置) W% P7 _7 h( ?: p* o: t% S$ H
  11.   
    8 [; x* }3 j% C7 r9 M7 M
  12.   TIM1->CCMR1|=7<<4;    //CH1 PWM2模式       K0 l2 E$ S: s. Z$ I
  13.   TIM1->CCMR1|=1<<3;     //CH1预装载使能     c( J9 L6 N8 i' g4 j
  14.    TIM1->CCER|=0<<1;     //OC1 输出使能     ( e6 J, i9 {# X. _
  15.   //TIM1->CCER|=1<<1;7 i- h# E$ u& Z1 y2 ~* R: K* S
  16.   
    % Z, N1 t* `; g5 C6 _+ f$ X1 r
  17.   
    8 l, g' {6 Q9 \# P
  18.   TIM1->BDTR|=1<<15;     //MOE 主输出使能     & w9 X1 R& T; o# L

  19. ! }. k' l- }) i8 t
  20.   TIM1->CR1=0x0080;     //ARPE使能
    $ E1 `: V- k" a: ~5 {0 c. y7 m
  21.   TIM1->CR1|=0x01;      //使能定时器1                       $ F( s' w  {% i7 Y9 t
  22. }
复制代码
下文具体分析上面的代码。8 g. e. W' U3 @. P) R! S1 G, n
前面4-6行是用来配置GPIO口的。9 X3 G- ]6 X' a5 u4 n6 k3 ~- [3 F
  1. TIM1->ARR=arr; //设定计数器自动重装值/ q; ~$ s% Y# r! M* Z: L
  2. TIM1->PSC=psc; //预分频器设置
复制代码
这两行就是我上门提到的设置定时器的频率和重装载值。1 o- \2 P, r5 ?
  1. TIM1->CCMR1|=7<<4; //CH1 PWM2模式
    * t$ W# t8 j$ H, a, j
  2. TIM1->CCMR1|=1<<3; //CH1预装载使能
    4 |- x  T% A7 R! h9 ^4 A# W
  3. TIM1->CCER|=0<<1; //OC1 输出使能
复制代码
这三行是用来设置PWM输出模式和设置通道的,通道是什么呢?简单地讲就是输出PWM波的GPIO口,代码一开始不是设置了PA8这个GPIO口嘛,这个PA8就是通道1。使用通道的话要先进行输入输出方向、通道使能的设置。& @$ c) B6 R& C; Q% f
  1. TIM1->CCER|=1<<1;
复制代码
这行代码是用来设置“有效电平”极性的,根据手册,当TIM1->CCER[1]这位置1时,有效电平为低电平,置0时有效电平为高电平,而默认情况下置0。
7 x& j% r$ W5 B! l
  1. TIM1->BDTR|=1<<15; //MOE 主输出使能
复制代码
这行代码只要对高级定时器进行设置,普通定时器无需设置。& [8 H, [$ S! S- j6 A3 P
  1. TIM1->CR1=0x0080; //ARPE使能
复制代码
这行代码是用来使能ARPE,ARPE是什么呢,就是当它被置1时,你自己设置的CCRx会立即生效,如果它被置为0,那么你自己设置的CCRx值不会立即生效(可能之前ARPE已经有值了),而是当之前设置的CCRx生效后才会使用你最新设置的CCRx值。1 y! y" w* X5 \( Y9 `

7 F* V/ e4 r8 E/ m
. C5 B7 N5 z; m* M8 ^. ~7 j  V
上面的代码里没有对CCRx进行设置,这是因为CCRx常常是一个变化的值,你可以在主函数中用一个for循环+if判断语句对它进行++或–的操作,从而达到连续改变CCRx值得目的,例如:4 d+ K9 g3 E9 u$ Y; X4 q* u# E% B) h6 e

  1. . C! n* l" n& r" _4 y: d
  2. for(i=0;i<300;i++){
    ; w; o# a; D9 O% ]
  3.   TIM1->CCR1=i;
    % J: [* J8 D) q5 k' z
  4.   if(i==300){3 D$ U6 a- T  x1 U* C
  5.     i=0;
    $ T( F& {  D, H3 R) W0 b6 E  q
  6.   }* Q0 y' c- b' n1 a4 M2 N
  7. }
复制代码
PWM波的周期是由定时器时钟频率和预装载值两者决定的,预装载值就是ARR。
  c% y7 k/ m. o  y' k- E" P& A7 @& F% m! l% h
0 j! B0 R7 y; C; ^
    预装载值PSC设置为899,那么,当定时器的当前值val从0增加到899时,一共经过了900个时钟周期,这900个时钟周期会产生一个PWM波形,也就是说900个定时器时钟周期才相当于一个PWM周期,那么PWM的频率就为72MHz/900=80KHz,周期为1/80KHz。
7 t" B* u. m, a4 S
* O2 b4 z& g0 R) }

+ u5 I( p( _( i2 v, g' o0 f
( j* X( p1 Q; f. m" C0 i. J5 H
( l) l2 E" u. C$ _2 x) D1 G# O% e

+ {; N. d1 _8 X  w6 w

+ C0 M# B( F6 }; Y
/ o  C0 E% Q8 }, {% v
收藏 1 评论0 发布时间:2020-12-7 10:50

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版