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

基于STM32F1实例-步进电机的速度控制

[复制链接]
STMCU小助手 发布时间:2021-9-6 10:40
13.png
项目需求6 X% _8 P6 A; `9 m$ U* C, c
    在制作一个使用全向轮的机器人底盘,对于全向轮,电机的精度是影响效果的重要因素。所以使用了步进电机,使用步进电机的优点是可以不使用编码器,开环控制即可达到高精度的效果。
% n" s: h, s! g4 f2 o* w5 `9 \0 c% l2 p3 d2 b

" w8 B: \" c+ p1 {调整占空比或者调整周期
4 `+ S. |$ k. W4 i! V; N    众所周知,PWM有两个重要参数,周期与占空比。
2 H- O5 |  L2 x4 B    步进电机的运动方式是,每收到一个脉冲,就旋转指定的角度。因此影响电机速度的唯一参数就是PWM的频率。以下附图两张来说明调整占空比与调整周期的区别。
4 U0 q6 p, g% S% c
, z% [6 j, a) H1 b/ Y
/ `* G3 ~: ]6 H) V5 h5 V
周期固定,调整占空比8 }3 |- t6 ?: C) @# S5 S
14.png
    上图中有4个PWM,它们的周期是一样的,不同之处是拥有从80%至20%的占空比。可以看出,无论占空比为多少,在1s内,它们产生的高电平的数量是一样的,即无论占空比为多少,PWM的频率都一致。因此也就无法调整步进电机的速度。因为步进电机的速度仅与PWM的频率有关。
: V, H' o7 B( T1 {. o3 f6 o3 l; c# K4 I! \  _  Z& q

/ M0 u9 z0 m0 d0 d. Z9 h& \1 q占空比固定,调整周期
7 c+ S; \' h0 j3 F2 |8 m" q
15.png
    上图中有4个PWM,它们的占空比都固定为50%,却拥有不同的周期。可以看出,即使占空比固定,只要动态调整周期,PWM就能在相同时间内产生数量不同的脉冲。因此,固定占空比,动态调整PWM周期,即可达到控制步进电机速度的效果。
# D- h0 w; m9 Y6 W( x, P$ r
5 O) i1 P" g! ]$ V, U
# C0 d! h# ^/ P2 w* b: `
基于STM32的实现
* S9 z2 W; R, ]4 O    在STM32F1中,定时器具有PWM模式,可以用来产生PWM。但是,STM32的PWM模式,只要确定了时基单元(即确定了PWM周期),改变输出比较寄存器,仅可改变PWM的占空比。
6 O; U1 z. [# O' A8 W, J    若需要改变PWM周期,需不停地改变定时器的时基单元。但时基单元与硬件相关,不适合频繁变更。因此,步进电机的调速,不适合使用STM32下定时器的PWM模式来控制。/ D8 q1 E9 L; h7 L! z
    在多方查找资料后,确定了一种利用输出比较精确控制PWM周期的方式。
/ u( c" R" D! T  O$ O
# e. B& Y! \! X8 D; W+ p5 z* d
0 Y* w9 c# ]0 A6 I  w+ ?  e
利用输出比较产生频率可变的PWM3 c1 h! q( }) I' j8 {% w2 g- f# ?
    利用输出比较产生频率可变的PWM,原理简单介绍如下:
0 z% o& @  {4 V" n# n: \5 z    首先配置定时器时基单元,确定脉冲最小长度单位CK。
  _( c1 m, W1 t' _# i0 V% c    然后开启定时器的输出比较,设置模式为翻转模式,并开启输出比较中断。/ ], H. J5 P# O4 f+ u( _
    将定时器内计数器CNT当前值,加上脉冲长度X(单位为CK),写入输出比较寄存器。
, H6 [1 Y. i4 ~) {3 v5 o4 w    在X个CK后,将会触发输出比较中断。同时电平翻转。, s6 z2 r9 U1 ]  Z* b; w- \4 S
    在中断中再次将当前计数器CNT的值,加上脉冲长度X,写入输出比较寄存器。: a) r$ C) ?  A
    在X个CK后,将会触发输出比较中断。同时电平翻转。
. y& c8 Y; Y* J    在中断中再次将当前计数器CNT的值,加上脉冲长度X,写入输出比较寄存器。+ J2 h5 ]  I' `* B! j
    如此往复……( i7 F' I. ]+ G
    以此即可得到一个占空比为50%,周期为2X个CK的PWM。
- }/ l. R, t8 a3 K7 z) B( {% }# n' t0 d5 ]! L. R$ e4 C* s# x* P% l

) ?0 S  l4 {3 T5 t. ]9 \确定最小单位CK,配置时基单元
$ b% @- r7 s# ^+ b    首先确定一个最小的间隔CK,规定PWM的高电平长度和低电平长度的单位都是CK。
+ L0 Z0 K; R: J- Y9 _/ d    即高电平的长度一定是CK的整数倍。低电平亦然。' i$ I0 R6 r0 Z! P7 Q3 I( P) m
    然后配置定时器的时基单元,通过CK的长度确定预分频系数。
; U" ?6 \- ]! Q" ~    已知STM32F103的主频为72MHZ,则时基单元中预分频系数为- v  [' o" k8 J* `4 t; b
( b5 Y$ Y$ ?* b% D* {. `% I0 a
& @6 Z6 t# K/ k  S) q, @2 Y6 l
PSC = 72M / (1/CK)
* G7 w/ Y4 h0 O( W7 P# _* R1 ^. ?    例如,rtz所确定的CK长度为10us(0.00001s),即可得出方程。# W5 C1 s+ E+ n$ K5 }5 v8 B4 C" W
16.png
   预分频系数确定为720后,由高速晶振产生的72MHZ的时钟信号被720分频,得到100000HZ的时钟信号。即时钟信号每秒变动100000次。每次10us。同时可将重装载值设定为0XFFFF(16位定时器的最大值)。因为本次使用的输出比较模式不使用更新中断,该值可随意设置。1 C% Y# l/ z7 m5 C( j" h3 Q0 M9 L5 L
  1. TIM_TimeBaseStructure.TIM_Period = 0XFFFF;  {4 R6 X2 w6 F; [% \
  2. TIM_TimeBaseStructure.TIM_Prescaler =720;
    % J; B+ D) z3 f7 Y
  3. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    ! }3 P4 x3 S' ^- `5 t6 k7 r
  4. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;& q& p3 V$ i" O  Q0 c5 b( d
  5. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
复制代码
    开启输出比较通道,设置输出比较模式为翻转模式,并配置NVIC,开启输出比较中断,配置输出比较通道:
+ h4 B, g% p8 c+ f& W
  1. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
      x8 X7 R: o$ y0 |! E9 \+ ]
  2. TIM_OCInitStructure.TIM_Pulse = 500;0 M9 v& @1 c9 K7 A- r  k
  3. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    % j- o8 d- e4 C+ h/ s) W+ J
  4. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;/ g6 r6 I( V1 f& D" X- a
  5. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    ( G6 o8 h; w. V3 b/ [
  6. TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
    0 V  }- O  T9 t) h3 A
  7. TIM_OC1Init(TIM2, &TIM_OCInitStructure);
复制代码
   开启输出比较中断,配置NVIC优先级:
0 A. S" U* E* d/ d4 v/ t! C

  1. $ [% T1 S5 u& }4 Z) c( U) n
  2. TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);" C! C- h1 `) F( G2 p( P* u: q. [
  3. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    $ x! }7 _5 I# }( z0 u
  4. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;) L1 c( v: {7 I0 t  m" G
  5. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    0 r1 |* W. `5 ], s6 g
  6. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;5 y9 y& `& j! P
  7. NVIC_Init(&NVIC_InitStructure);
复制代码
编写中断服务函数
' K  y3 H2 d7 ^: W8 u* v* L    在输出比较中断中,唯一要做的事情就是把当前CNT的值取出,加上脉冲长度X,写入输出比较寄存器。
$ w+ q2 s; W& y; i    当计数器达到0XFFFF(之前设定的重装载值)后,再加一会自动变为0.
' s; ~( a' K. `    例如,当前CNT值为0XFFFF,脉冲长度为5,很明显,输出比较寄存器应设置为0X0004才可触发下一次中断,而不是0X10004,这样会造成溢出。
  D) e% A/ w# }6 R, L    因此将CNT的值与脉冲长度相加后,需要取0XFFFF的余数后,再写入输出比较寄存器。
- a  z7 U9 o0 i

  1. $ J; W& V& C9 W1 n* s5 s
  2. int t_m=5;//低电平和高电平的长度3 E  Q5 I& f  Y: }! n- `
  3. void TIM2_IRQHandler(void)
    4 J6 z8 p* S) o
  4. {
    2 L/ S; w: y; i
  5.   if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {. g; c# @+ ]) }
  6.     TIM_SetCompare1(TIM2,(TIM2->CNT+t_m)%0XFFFF);
    . i% D8 Q7 T: m1 v1 y
  7.     TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
    : D' R2 i% B, e* @
  8.   }
    1 ^  I4 w- `2 a* ?  _9 p6 a
  9. }
复制代码

2 U" L# l1 n# P4 j  v
/ }& r1 i$ {0 Z" P

8 b- ^7 \7 [8 d% _( N3 I
! P& }# z" R% B/ S$ W; z
+ B- f; X2 G! P7 z0 ?
" H* l( S9 x5 I* [# J* a

7 F) v' `3 R8 S! H$ P% \1 ~: S1 v! Q
赞 收藏 评论0 发布时间:2021-9-6 10:40

举报

0个回答

所属标签

相似技术帖

官网相关资源

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