|
基于STM32的步进电机实验步进电机介绍 步进电机是将电脉冲信号转变为角位移或线位移的开环控制元步进电机件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为“步距角”,它的旋转是以固定的角度一步一步运行的。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。 % Z" @3 G9 m* m( v( C
步进电机基础知识步进电机参数说明
. {. d/ g" o! K {* i4 U( `四相步进电机有两种运行方式 1.四相四拍;2.四相八拍。 拍数 指电机转过一个齿距角所需脉冲数,通俗的来讲拍数指的是步进电机运行时每转一个齿距所需的脉冲数。以四相电机为例,有四相单四拍运行方式即A-B-C-D-A,有四相四拍运行方式即AB-BC-CD-DA-AB,有四相八拍运行方式即 A-AB-B-BC-C-CD-D-DA-A。 转速 以基本步距角1.8°的步进电机为例(现在市场上常规的二、四相混合式步进电机基本步距角都是1.8°),四相八拍运行方式下,每接收一个脉冲信号,转过0.9°,如果每秒钟接收400个脉冲,那么转速为每秒400X0.9°=360°,相当与每秒钟转一圈,每分钟60转。 步距角 对应一个脉冲信号,电机转子转过的角位移用θ表示,即在没有减速齿轮的情况下,对于一个脉冲信号,转子所转过的机械角度。θ=360度/(转子齿数*运行拍数),以常规二、四相,转子齿为50齿电机为例。四拍运行时步距角为θ=360度/(50*4)=1.8度(俗称整步),八拍运行时步距角为θ=360度/(50*8)=0.9度(俗称半步)。 连续运行的最高工作频率fmax 步进电机连续运行时,它所能接受的,即保证不丢步运行的极限频率,称为最高工作频率。它是决定定子绕组通电状态最高变化频率的参数,它决定了步进电机的最高转速。 传动比 我们知道主从齿轮之间有传动关系,如下图所示:
- Z: M) @9 o- R1 O8 [& x" `
如果让齿轮1的齿数为:Z1,转速为:n1,齿轮2的齿数为:Z2,转速为:n2,则两啮合齿轮转速和齿数间的关系为:n1/n2=Z2/Z1。 减速比 减速装置的传动比,是传动比的一种,是指减速机构中瞬时输入速度zhi与输出速度的比值,用符号“i”表示减速比的意思:比如减速比1/64,:如果步进电机输出1N.m的转矩的话,通过减速箱转换后的输出力矩64N.m,当然转速降低为原转速的1/64 6 K* ?# [ w. [2 q' f# f+ C
例题说明3 [5 L3 j/ o8 o9 N/ z2 f
例如:2相4线步进电机57BYG250-56,它的相数是2,转子齿数是50,步距角是1.8° 则它的每一个转子齿距为:360°/50=7.2°, 拍数为:7.2°/1.8°=4(拍) 也就是说,步进电机57BYG250-56每转一个齿距需要4个脉冲。 ( F$ G0 |7 H( |. R
基于28BYJ步进电机的介绍4 k# H4 h; f: w6 o0 L! Z. n/ z/ t! Q
 3 Q4 b0 h: z/ x- }4 ]/ m
7 q$ ?, ^" J# v' ~, n" S
- u# r9 m; d: g# q
以双四拍为例: 1 Y( Q4 r' n) ^0 s
当28BYJ步进电机的转子转动5.625°时,最外面齿轮的转速由于经过了齿轮的传动转速变为了原来的1/64。 这里要注意减速比的概念,1/64并不是指电机的转子减速1圈最外面齿轮减速64圈,这里的指的是电机的转子输出1N.m的扭矩,由于传动比,最外面的齿轮会输出64N.m的扭矩进行减速。 其次,这里“起动频率>=550Hz”很有迷惑性,这里他应该表示的意思是ABCD四个引脚的电平变化频率小于550Hz,28BYJ电机可以按照指定参数正常工作。 ; V& d9 x$ g _, Z3 F" J
28BYJ步进电机的配置流程电机工作状态与引脚的关系
) d3 l7 T; P3 F) ?) P: e
" D8 P* @3 z% U" j1 z+ X( o* |. q$ H# F
四相八拍的正向旋转工作方式
( {, M" w0 `/ G7 a0 I2 f t9 ^
/ P6 i. \* `" F$ f
于是得到双相8拍正向旋转码为:{0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09},如果想要反转只需将顺序颠倒即可。 1 [6 T8 h0 i1 y& P
STM32的PWM控制步进电机运转的实质% M+ s9 v4 R0 o1 W
① 不是说可以通过调节频率来调节步进电机的转速吗,可是现在只有这么窄的范围,可以实现转速调节吗?而且我发现在这些频率内,电机转速都差不多,是不是我理解错了?
# G/ H, O k/ {' m# u" e4 i8 S& N- o
转速和PWM的频率没关系,和绕线的通电方向的切换速度有关。
/ B4 S3 U9 r$ o
② 当我调节PWM占空比的时候,发现也没有什么实际作用,电机转速也不会改变,那么占空比对于步进电机有什么意义呢?
( k( |: K; H, H9 c6 q8 H
PWM占空比会影响步进电机的力矩但不会影响速度,占空比太小了其力矩无法推动自身的惯性就会出现转不动的现象。 5 \( R. q5 a6 @! O
③ 我该如何利用PWM模块来调节步进电机不同的转速? 8 i0 Q0 w$ i4 K# D( p
以4节拍为例 A+:A线组正向通电 B+:B线组正向通电 A+ -> B+ -> A- -> B- ->A+ ->… 该循环越快电机转速越快,但注意是有上限的 对于直流电机:影响速度的是占空比,频率与电机转速无关,相对而言,频率越高,电流纹波越小,但是,电源的损耗越高,因此,调节频率的主要原则是电流纹波满足要求的情况下,开关频率适当低. 占空比可改变输出电压的平均值,从而改变电机的电流和转速.这是一种数字脉冲技术,来达到改变送到电机的平均电压来调速。还有一种模拟技术:电压控制技术。 对于步进电机:采用脉冲频率控制。不能用占空比控制,也不能用电压控制。影响速度的是脉冲频率,影响位置的是脉冲个数。 以4节拍为例 A+:A线组正向通电 B+:B线组正向通电 A+ -> B+ -> A- -> B- ->A+ ->… 该循环越快电机转速越快,但注意是有上限的。 回到前面的频率问题,就如刚才说的,1秒内,0.5秒开,0.5秒灭,占空比是50%对吧?那么,1毫秒内,0.5毫秒开,0.5毫秒灭,占空比也是50%,对吧?如果是1秒呢,频率就是1HZ,如果是1毫秒,频率就是1KHZ,显然,同样是50%占空比,如果频率是1HZ,那电机肯定是跳着走的,灯光肯定闪得可以跳舞,不具有调速和调光的意义。 2 Y$ n, ]5 N" F8 R
STM32库函数配置(以PWM调节直流电机速度为例)
6 ?$ p- _7 W* \* f2 J0 |7 S
! M3 _2 {9 X& [2 r
7 y8 b$ K6 e& l9 U; v2 g+ B4 e- `" |: o2 H9 J+ n
Main.c
+ I) x9 G1 ^. N
* I8 X% X# w' |# o: j- #include "timer.h" 6 I2 u3 u% R$ _7 O1 Z6 G
- #include "delay.h" 4 @. v& l0 }0 h' c6 A$ {
- #include "key.h"
, I- z3 l" A, z) c* t - #include "led.h"
. l4 n; E+ @: e6 h+ P; Z# I - 1 s( x, K& u/ _0 x
- int main() 1 b/ P! J J5 u
- {
$ |+ w" O' k( d- f - u16 ARR = 5000, PR = 7200, CompareValue = 0; : _1 C- V2 h i- b
- 0 t! }: ], }7 H0 O
- LED_InitConfig();
9 b0 D; }( ]3 D- B' | - delay_init(); " C& T) H, Z% A0 d8 K0 @
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ; j& Q6 S0 Q" N. u/ j
- TIMER_InitConfig(ARR, PR); // 周期:0.01秒,占空比:0%-31% - ]3 R$ p! |1 R/ r% u/ s
- KEY_InitConfig(); ( n9 A+ c4 l/ p" [3 _
-
3 t) M# l. ?; p8 \( p- U1 ] - while(1) % V% a" S: d4 p# F* w! Y1 x9 O
- { . O A9 ]4 m3 A$ }, M+ A6 J) @
- CompareValue += 5;
1 Q: M- a4 g; P; O - TIM_SetCompare1(TIM1, CompareValue); // 修改比较值
4 O8 [4 f& A0 l' l4 ] - CompareValue &= 0xFFF;
& m, F, i9 R& Q! i8 K- N3 s+ P) H! S -
- {; U6 Z6 V# X - delay_ms(100); // 延迟100ms
& N. Y( l3 g) r# w m3 u1 G! T - }
9 v T% U. Y5 b; o; K - }
复制代码 7 N$ r5 ^( Z0 F/ E/ E1 `- f, l
) s4 _7 T& E5 Q3 qLed.h
6 R. }3 l) I8 C. a. T) B
$ x" n v6 U7 Y- #ifndef _LED_H ( d7 b: L- L7 l% o
- #define _LED_H
" E0 L8 f& s+ `9 c - 7 c9 L% {- ^1 r& E
- #include "sys.h"
5 A2 w" b' s2 o: T( Y6 T7 Y: W! K - ! @$ I8 ^9 N$ f, l
- void LED_InitConfig();
* B. i: ^2 v' c$ e& ?8 D7 P. C -
( \) ^3 x8 y; ?3 h$ D5 @" Y. K - #define LED0 PBout(5)
5 l4 }" e6 ^0 Q$ X3 V4 ` - #define LED1 PEout(5)
5 f( ^& A0 ?& m' y$ Y -
, d2 G: u4 B1 d1 ^# ^- x9 Q8 U - #endif # u: { L _- g7 _4 D
-
复制代码 8 k5 w8 p% N- {" n. x1 S
* o* K: e2 A2 Y$ L' `* xTimer.c
! q) V9 T! k/ {: ]
# d' L! `+ }3 m) ?& u- #include "timer.h"
8 _6 R* z9 n. u J# D# g' A' s; ~ - #include "stm32f10x.h" , N; j% C( E% X3 i. E
- #include "sys.h" 1 g; u! ?- L$ p( ~# Q1 h' x
- #include "led.h" 5 q- i- g' W/ L* ^8 x' N, i6 w6 q
-
3 I& H% [/ E6 k+ m& g - void TIMER_InitConfig(u16 ARR,u16 PR) * b4 x5 x% J0 p$ o6 Q# w, B: b8 ?+ x. d
- { ( d; {8 q1 ^/ l3 t! o
- GPIO_InitTypeDef GPIO_InitStructure;
& K5 C0 }' v/ H+ J& k. G - TIM_OCInitTypeDef TIM_OCInitStruct;
0 i% I d9 _$ g: N7 J2 t - TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
8 U' l* [4 n4 K: O+ F/ J9 p& X - NVIC_InitTypeDef NVIC_InitStructure; * P6 {$ S2 L: k5 M; }& I% l4 v2 I# N
-
2 a( @% Z, K& a% }, A: a# u - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_TIM1, ENABLE); // 使能GPIOA与TIMER1的总线时钟 : P/ x* q6 A+ w$ N# n9 g3 O0 g1 Q' I
- - l7 Y2 v1 e6 J2 J" P9 ]
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- B/ T0 _& |( j" `+ k$ K - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
6 _8 z% D/ T4 E2 ~; W4 z2 H - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 6 C5 a* Z7 Z' H9 [( H+ i6 }. l) S
- GPIO_Init(GPIOA, &GPIO_InitStructure); // PA8设置为复用推挽输出 ( O' j) u* \1 X; @
- b# v( k6 K; o
- NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
2 ?3 Q3 s5 _* l' Q/ u+ } - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
' l* w+ I: Y* h( C1 } - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
3 T' ^5 ?( s; o9 c! I. a - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
5 Q3 w4 `3 Z6 @/ \, k& s - NVIC_Init(&NVIC_InitStructure); // 配置NVIC的TIM1定时器溢出中断通道使能 ) r$ E! t3 O) K# j6 p( O
-
S6 G- ]0 L: w W4 N - NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; - G7 h" f: Z$ [% p3 l" e
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; : j, p: x$ ? w, @
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
& p, p% s& l6 }' @ v5 u7 G - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 7 {9 K* b* I6 \. p
- NVIC_Init(&NVIC_InitStructure); // 配置NVIC的TIM1比较中断通道使能
3 K! ^6 k! |" t -
! Y9 D* _7 W6 v4 U( R - TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
' k( k" ^$ h$ g - TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
- |7 H, q" z! @/ A5 i - TIM_TimeBaseInitStructure.TIM_Period = ARR;
# p# S: x x" J8 F% d - TIM_TimeBaseInitStructure.TIM_Prescaler = PR; " N3 P" ?. F6 l" C5 ?8 c
- TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure); // 配置TIM1的计数器
- `+ H! o+ T. B- e) K$ S2 a! p -
$ s5 ^2 e0 u: J) U - TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
' E+ p* g- P- H( r5 r - TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效 ) O4 o3 W7 P8 V+ A6 ~; p
- TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Disable;
0 V* R% x+ f& u& T- ?) M2 s - TIM_OC1Init(TIM1, &TIM_OCInitStruct); // 配置TIM1_CH1为PWM2输出模式 ) r( l# x: k- K/ F
- $ I% s) A' X& X8 {
- TIM_ITConfig(TIM1, TIM_IT_CC1|TIM_IT_Update, ENABLE); // TIM1捕获比较/更新中断配置 ' X0 q6 O, G. a8 z* `& K: K
-
4 i+ u+ V$ L/ c& E- t9 z- O - TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); // 使能TIM1预加载寄存器 1 {9 J+ l r8 X1 m9 {7 S
- 6 g# J/ @+ D- a3 Y9 W3 U1 L
- TIM_Cmd(TIM1, ENABLE); // TIM1使能
) U K8 Z @4 T- X - }
4 F- `" A7 _2 N% K+ g3 {" M2 M - ! y9 y+ b3 l- M- m4 M) v7 t; F
- void TIM1_CC_IRQHandler()
3 k% Z7 }0 j% d4 S+ R8 f7 ]) G0 m# f - {
( H6 j! _' Y X! R - if(TIM_GetITStatus(TIM1,TIM_IT_CC1) == SET) // 中断标志位被捕获
6 |5 I9 S7 q5 A3 e3 G6 y - {
5 w- @5 I! R7 k3 X4 F5 y$ e# I* S - LED0 = !LED0;
/ t4 m7 E1 j8 `5 [/ ^- H% A - }
5 y* N9 Q6 d- S/ c$ x: s - TIM_ClearITPendingBit(TIM1,TIM_IT_CC1); // 清除中断标志位 % n( k. W# N5 A8 C5 Z1 m
- } . K1 p) w( r: W5 ^
-
" J/ H" |: M# B - void TIM1_UP_IRQHandler() ! d, ]/ p- s9 ^; [2 u& s' R) W
- { - e* B. Q- X$ U3 F7 L, R
- if(TIM_GetITStatus(TIM1, TIM_IT_Update) == SET) ! u& P ?' d5 D. a* u$ N' j& K
- {
' d/ L' h0 a: B9 L - LED1 = !LED1;
0 e; v2 J+ p @ - } * ^" r8 h' Y" S* G
- TIM_ClearITPendingBit(TIM1,TIM_IT_Update); // 清除中断标志位
0 O' o. b( D- A5 X - }
: n# m) \4 Z9 E) E& [7 D1 L, y/ C -
复制代码 & }9 P3 }1 g1 a! K
1 z+ V3 G7 |8 X5 l
2 e/ {" u& F: r6 G) c- g8 G
Timer.h: }) L [0 F8 q; h) o3 H
- #ifndef _TIMER_H % s8 x0 W) Y0 s" W
- #define _TIMER_H 5 ~/ E8 k* r. S s% ], z5 _
- * c% r4 c$ P+ W( P! }( e. K, Q
- #include "sys.h" " V2 |) X9 r$ N( A
-
" L" j u; p2 E7 R - void TIMER_InitConfig(u16 ARR,u16 PR);
& ~* Q; \4 j N1 T9 j; } - - W7 C- T" n. P9 K( s2 H/ H1 S
- #endif
复制代码 注:这里的LED0,LED1的工作状态是否反转标志着是否进入相应的中断。
6 I- K1 K3 v2 |! E9 V
* t4 t! B( d! j6 j v$ N: h
9 v5 \' W9 B1 j
3 \' _6 w; I5 @! P+ y4 S( {- @+ N! n
|