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

STM32通过PWM控制电机速度

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

, M* G. q/ l- [. |7 g

6 U  S0 I! L5 p. b% |做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速。分享本文了解如何通过PWM实现对电机速度的控制。; B. |- F* Y7 |

7 ]' e2 g4 G- R, _$ q7 D
3 g7 }7 \0 }' i, m, O
PWM控制电机速度的基本原理% G6 t$ w  T5 Z! M
    PWM(Pulse Width Modulation),也就是脉冲宽度调制。
3 T6 `! ~1 l2 l/ ~9 @/ W7 d    PWM中有一个比较重要的概念,占空比:是一个脉冲周期内有效电平在整个周期所占的比例。; S/ s6 ]" \( V& R8 }
' O: N4 q+ G1 ?2 J

5 Y9 Y" y- [8 M6 f( w    为了实现IO口上电压的持续性变化,可以调节PWM的占空比。这也能够使外设的功率进行持续性变化,最终控制直流电机转速的快慢。如何调节PWM波形的输出就是重点。. `2 {4 v: j# w+ P2 \! ~
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这两个寄存器的值了。
- P- C  f0 X+ A2 H. r
" H4 z6 s9 G& \" j/ X

, e. K* P2 U1 I: B2 o9 Z7 uSTM32定时器中断& w9 U" f0 j; z. q
    为了便于理解接下来关于PWM应用的内容,先插一段定时器中断的知识。
: t2 q: d# m3 j! L  `
1 k) t1 m# {7 L3 l0 s# J! N/ M* F
: S" n+ h; R1 e! Z9 [& `. q
    产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解、掌握。
5 Q" B+ K" W7 I* M$ \, K$ w* z: J原理简介( s$ J0 [: U( ]( j3 E
    使用通用定时器进行中断的原理,其实和开发板Systick定时器进行中断延时很相似(Stm32入门——Systick定时器),即:用psc(预分频系数)设置好定时器时钟后,arr(预装载值)在每个时钟周期内减1,当arr减为0时触发中断然后进入中断处理程序进行中断处理。以下代码为例:2 B; e- N7 f/ a- [$ p' F; `+ K
  1. 6 K9 Y5 P! x# `
  2. void TIM3_Int_Init(u16 arr,u16 psc)
    / R6 U2 D8 c4 n2 U+ O3 r, Q
  3. {
    7 [! V8 B7 }2 V6 P3 f
  4.   RCC->APB1ENR|=1<<1;  //TIM3时钟使能   
    8 O+ z9 V( v: J; U' p3 `  Y* S8 K
  5.    TIM3->ARR=arr;    //设定计数器自动重装值 ' k0 N: F0 m1 \+ C! l5 H
  6.   TIM3->PSC=psc;    //预分频器设置1 i3 C* p5 `0 ]! A7 Y" H+ |) ?
  7.   TIM3->DIER|=1<<0;   //允许更新中断        1 `5 ~2 z" x; H. i8 l0 X0 [" j
  8.   TIM3->CR1|=0x01;    //使能定时器30 b& E& v; T" w/ g4 }* H
  9.     MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2                     S9 p( S7 w: _5 H- u" J
  10. }
复制代码
  1. RCC->APB1ENR|=1<<1
复制代码
解释一下上面这行代码,由于定时器3(TIM3)是挂在APB1上的外设,所以要打开APB1,这里的预分频器值psc是来设置TIM3的时钟频率的,如果系统时钟(SYSTICK)频率为72MHz、psc为7199,则TIM3的时钟频率就为:
& K+ c& ~# S5 P
  1. 72MHz/(7199+1)Hz = 10KHz    //这里的“+1”是手册中规定的。
复制代码
10KHz是什 么意思呢?就是一秒钟会产生10K个周期,那么一个周期的时间长度就是1/10KHz,如果你想将定时器中断的时间间隔设置为0.5秒,那么你将arr设置为5000即可,因为arr每减1就需要一个周期的时间,减5000次就经过了5000*(1/10KHz)=0.5秒。
$ Z3 `, B; a2 K  d, D6 D8 D9 H
  1. TIM3->DIER|=1<<0
复制代码
再解释下上面这一行,设置允许更新中断,即arr减到0以后可以触发更新中断,还有其他类型的中断。- s. N/ \+ D* B; m
  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代表的是前两位给抢占优先级,后两位给响应优先级。
  e% u* G8 R7 C! Q; z5 X$ l: t% M
$ E' E: A, W6 ~! R. e8 E

0 T% K$ m5 N8 C2 E" VPWM模式、有效电平
# c" g! k- Z/ `- M; u% E5 t% `- o4 b6 O1 |

0 ]- \: G! E) i2 [8 L    前面介绍完中断,再说一下PWM工作原理。
4 b% }1 m6 D& t" Z' }
. @5 o! D9 D# E! a
' C& ]# l, U+ X4 I2 P
    假设上图中ARR大于CCRx时输出为高电平,ARR小于CCRx时输出为低电平,但在实际运用中可能并非如此,有可能是相反的情况——ARR大于CCRx时输出为低电平,ARR小于CCRx时输出为高电平,至于到底是哪种情况,还要看PWM是哪种模式、有效电平又设置的是何种极性了。* d' R0 G  J$ S* C; b6 r: B

  G2 m. ^, y' p

9 ]0 S( f) w3 {4 k+ l, J模式1:ARR小于CCRx时输出为“有效”电平,ARR大于CCRx时输出为“无效”电平。+ w2 E2 u5 [1 |& s
  q9 V/ n1 g9 w0 r+ x, ^4 u

* o  J! |6 A  s; R模式2:ARR小于CCRx时输出为“无效”电平,ARR大于CCRx时输出为“有效”电平。
! A( g/ }3 W) y9 S4 K5 B# E% [( j+ T9 V

, C8 `0 Y: P8 |1 R8 t    这里说的是“有效”和“无效”,而不是“高”和“低”,也就是说有效电平可高可低,并非一定就是高电平。PWM模式、效电平极性,需要程序员自己配置相关的寄存器来实现。通过下面的代码来讲解。
6 `6 Z0 f, _( V8 m' z9 H& e
  1. TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
复制代码
上一小节讲过关于定时器参数的设置。使用定时器1的通道1来输出一路PWM波,这里的899设置的就是ARR的值,至于那个0是用来设置TIM1的频率的,不分频就代表TIM1的时钟频率和系统时钟相同,这里假设为72MHz。- D# b! d* j+ i5 E- q7 z+ `3 O
  1. % ~9 w, D; m, f$ |2 [$ e4 o
  2. void TIM1_PWM_Init(u16 arr,u16 psc); N! |- H7 a( W. F- ~6 i
  3. {               
    9 u& F2 `: b! y; f+ `0 }
  4.   //此部分需手动修改IO口设置9 R" ?) l# ?2 G5 i! ?+ x1 D4 ^& X
  5.   RCC->APB2ENR|=1<<11;   //TIM1时钟使能    4 Z2 R: X# [: K/ x( K
  6.   GPIOA->CRH&=0XFFFFFFF0;  //PA8清除之前的设置
    4 x9 N) i; A$ D+ ~
  7.   GPIOA->CRH|=0X0000000B;  //复用功能输出
    1 i3 M) @5 N0 `6 j# b9 I
  8.   9 i! n) X$ T5 ?+ ?7 \* j
  9.   TIM1->ARR=arr;      //设定计数器自动重装值
    8 H. @( R1 [7 {! O+ [* d( Q- D
  10.   TIM1->PSC=psc;      //预分频器设置
    9 u; h. _/ r9 g6 X$ K8 p: Q
  11.   & U1 H! d' |" {! N0 k2 ~3 V6 `3 |
  12.   TIM1->CCMR1|=7<<4;    //CH1 PWM2模式     
    ) r6 l/ e! b! b/ c. t& ]
  13.   TIM1->CCMR1|=1<<3;     //CH1预装载使能   
    - Q' w. S) F  u7 G, ?. S) _
  14.    TIM1->CCER|=0<<1;     //OC1 输出使能     / w/ p, r7 s1 p, T$ C
  15.   //TIM1->CCER|=1<<1;
    % `2 C3 o" X0 T5 C6 d6 y
  16.   & M# W4 V8 T! c; Y
  17.   / W, W: t( p$ U: O. s+ e
  18.   TIM1->BDTR|=1<<15;     //MOE 主输出使能     $ U9 D2 I- @) ^4 |2 t/ M. T5 j
  19. 0 o4 t2 _$ e  q" X5 q
  20.   TIM1->CR1=0x0080;     //ARPE使能 8 T& L6 u7 u! C8 t+ B
  21.   TIM1->CR1|=0x01;      //使能定时器1                       # {: Y- {3 T+ n0 u8 A% O0 U+ c
  22. }
复制代码
下文具体分析上面的代码。
2 a0 x# G; \0 {* K- e' A' D前面4-6行是用来配置GPIO口的。: y1 I: h* H9 n# @6 l
  1. TIM1->ARR=arr; //设定计数器自动重装值
    - K( L. A. D1 S! b% y5 p) L
  2. TIM1->PSC=psc; //预分频器设置
复制代码
这两行就是我上门提到的设置定时器的频率和重装载值。
: S$ G+ u* z4 o7 F/ \7 O  w, h2 o
  1. TIM1->CCMR1|=7<<4; //CH1 PWM2模式- ?+ c: Q# R- p
  2. TIM1->CCMR1|=1<<3; //CH1预装载使能" x9 f+ S) S$ ^1 \$ A4 Z5 B! e8 L
  3. TIM1->CCER|=0<<1; //OC1 输出使能
复制代码
这三行是用来设置PWM输出模式和设置通道的,通道是什么呢?简单地讲就是输出PWM波的GPIO口,代码一开始不是设置了PA8这个GPIO口嘛,这个PA8就是通道1。使用通道的话要先进行输入输出方向、通道使能的设置。0 w7 q# z& v( E
  1. TIM1->CCER|=1<<1;
复制代码
这行代码是用来设置“有效电平”极性的,根据手册,当TIM1->CCER[1]这位置1时,有效电平为低电平,置0时有效电平为高电平,而默认情况下置0。8 n+ N  D! x- k  \
  1. TIM1->BDTR|=1<<15; //MOE 主输出使能
复制代码
这行代码只要对高级定时器进行设置,普通定时器无需设置。
% P: f- [% a. @5 S9 \% S
  1. TIM1->CR1=0x0080; //ARPE使能
复制代码
这行代码是用来使能ARPE,ARPE是什么呢,就是当它被置1时,你自己设置的CCRx会立即生效,如果它被置为0,那么你自己设置的CCRx值不会立即生效(可能之前ARPE已经有值了),而是当之前设置的CCRx生效后才会使用你最新设置的CCRx值。
- p2 G( Y4 c6 l7 I5 |
, C4 @7 Z# D  G# u
. o5 i% g- t. ?7 e" O
上面的代码里没有对CCRx进行设置,这是因为CCRx常常是一个变化的值,你可以在主函数中用一个for循环+if判断语句对它进行++或–的操作,从而达到连续改变CCRx值得目的,例如:( l0 f# f# U* o% w

  1. # [6 m, p" O. A  I$ B
  2. for(i=0;i<300;i++){
    5 Q* V( T2 ?( \. A( k
  3.   TIM1->CCR1=i;0 X' H  t2 b+ ^5 O
  4.   if(i==300){/ ]" e, D- u* s: E. }
  5.     i=0;
    , V' x6 o, q: w% m# e
  6.   }: n: D" S" \* `5 h! z" L0 L
  7. }
复制代码
PWM波的周期是由定时器时钟频率和预装载值两者决定的,预装载值就是ARR。, `4 ^9 ^% T4 y3 ?

6 m. b6 O1 N/ q: o6 V, }
  [" c. x4 b2 Q& @2 h
    预装载值PSC设置为899,那么,当定时器的当前值val从0增加到899时,一共经过了900个时钟周期,这900个时钟周期会产生一个PWM波形,也就是说900个定时器时钟周期才相当于一个PWM周期,那么PWM的频率就为72MHz/900=80KHz,周期为1/80KHz。2 D( w# y4 y5 V" z% w

; F( ?' y4 J* {: B
8 O4 T$ H7 h  N1 e$ R
# f. H; ?0 r0 K0 _8 _% h
$ @: S! R. [" m. b! i9 F% \
1 w+ I: Z. h; ~1 j) s! O" W

5 d6 M# K6 n5 _' h" V2 Z  U7 T% @6 j( P' t6 I4 Y
收藏 1 评论0 发布时间:2020-12-7 10:50

举报

0个回答

所属标签

相似分享

官网相关资源

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