STM32驱动步进电机 ! d7 Z% Y( l) G7 S
. ?( \. ^* L2 G% S" m9 t
步进电机是将电脉冲信号转变为角位移或线位移,可以通过控制脉冲来控制,因此比一般的电机更精准。这篇文章将会讲述我对四线两项步进电机的调试经验。
/ E6 p7 m; B( @' Q- d/ j3 r6 i$ ?6 B3 y) R% a, o* `
z8 w5 Y D: C5 M; i
1.步进电机以及THB7128的接线
1 C- c! ]5 J' J/ h7 z1 B9 DTHB7128步进电机驱动有两个接线口,J4口与stm32的IO口相接,J2口与步进电机和电源相接。5 b$ C6 t' v; b! J5 u
2 w u7 T+ ^& N: \: r+ c/ U" T$ N$ ]
8 ~. ?- E. z) Q3 P( r6 M+ }
J2口有6个端子,从两个端口旁的接口定义可以看出,接口分别为B-,B+,A-,A+,V-,V+。其中V+与9~32V的电源相接,V-接电源地,其余的接口B+,B-一组,A+,A-一组与步进电机的两组同相线相接(注:想要判断步进电机哪两根线同相,只需用万用表测量,短接的即为同相)。
' Q& a8 c* v% T/ n0 n; B( z4 D
j; ?* {- O! J, |5 j% E X
- e/ Z% k: v" _3 _J4口同样可以从端口定义看出,分别有CP+,CP-,DIR+,DIR-,EN+,EN-6个端子。CP为脉冲信号输入端,DIR为电机正反转控制端,EN为电机脱机控制端。在J4端口有共阳极和共阴极两种接线方法。9 J! p* c X. x% N- P8 u; J
共阳极接法:分别将CP+,DIR+,EN+连接到STM32板子的输出电压上,脉冲输入信号通过CP-接入;此时,DIR,EN-在低电平有效。8 y% x1 T) T) M% ~1 {- I
共阴极接法:分别将CP-,DIR-,EN-连接到控制系统的地端(与电源地隔离);此时脉冲输入信号通过CP+加入,U/D+,EN+在高电平有效。, G( F: a$ q; z
(注:我采用的是共阴极接法,所以之后只介绍共阴极的程序)
7 \/ ^+ K1 d# e! C5 F+ IJ4端口共阴极接线) d/ ?, d2 r! k" c) i8 }. ]
2. THB7128设置& R$ H# n1 _. w/ E) d* n9 }( ^% W
TBH7128有6个拨盘开关(S1~S6),前3个开关控制细分设置,即控制电机每一步转动多少度,步距角=电机固有步距角/细分数。后三个S3~S6设置电流大小,设置的电流不要超过电机的额定电流。具体如何设置根据自己实际情况参考驱动芯片背后的说明表进行调节。说明表所示:
6 X3 h& U4 R a6 y3.程序设计6 {' ?+ C1 |2 ~" V# W4 u! I
(1)使步进电机稳定转动
: m2 Q: E2 f9 D/ ]* }) }6 H2 z: o驱动接收到一个脉冲步进电机就动一步,所以我们可以用定时器中断将脉冲按一定的频率从STM32的IO口输入到驱动中,这样就可以使步进电机稳定转动起来
* W& q4 M' l5 Q& c& n; f(2)步进电机的开启、截止以及变向2 ^. w0 T! S7 D8 [
当THB7128使能端EN+接收到高电平时步进电机停止运转,接收到低电平时正常运转。因此改变与EN+相接的IO口的电平高低就可以控制电机的开启与截止。2 P6 y* ^! ?" A5 r0 Q
当正反控制端DIR+接收到高电平时步进电机改变转动方向,改变相应的IO口电平即可让步进电机变向。4 ]6 k2 d5 I6 I* S
(3)步进电机变速
1 X0 K+ H% i- G% W4 X! A- u我用的定时器中断来驱动电机转动,所以只要想办法改变定时器中断的参数就可以让电机改变速度
# K9 k' N4 J! y6 {* k& |% |0 b, ?- @
2 ^9 w; Z0 `! D! k# B S, X3 D* t) N
具体程序如下:
" w* \8 p8 T9 x
# y; g/ N& v5 ^( Z
5 h( ]' D' l8 D0 V0 c9 f4 A, V4 X7 ?% l1 K7 A4 j0 X6 a9 }- g
①定时器设置及IO口初始化, d/ m. B6 L G0 O& q& c9 n5 @
- #include "dianji.h"! K1 W5 |1 p7 ^! `) o% s# p8 }, w
- #include "led.h"
. `" ?* [9 I% A
* r5 P) |: f- [- l2 P: x" T- void TIM3_Int_Init(u16 arr,u16 psc)" B) H( i: a0 ?
- {
9 {! G, k, k0 p5 n - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
$ T* y4 j) q0 V - NVIC_InitTypeDef NVIC_InitStructure;% A6 S# {0 Z2 Q; o* C% ?
5 b+ p) ]' {) ~% R2 H6 a- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能- A0 }* ~. L* b8 F4 u1 _+ w4 T
) Z/ s0 o$ P- @( Q; ~( f- W- //定时器TIM3初始化& ~$ Q3 _ K0 J5 C1 w
- TIM_TimeBaseStructure.TIM_Period = arr;//自动重装载寄存器周期的值( n" B G; x; V4 a7 u2 H* q+ B
- TIM_TimeBaseStructure.TIM_Prescaler = psc;//预分频值6 F* b2 e- T+ A: D9 y. Q0 v$ D
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分割' _) u5 g0 Q5 }8 I1 P, @5 t1 E0 t
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式- d. g$ |% u* k8 d
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
+ ]: ]6 Q4 |. b$ T - ; S$ V. @9 F' K) K% w3 n* D
- TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //使能指定的TIM3中断,允许更新中断$ d) _% v: [( _$ \& W
* m7 |% l2 l* t' r- //中断优先级NVIC设置% y l% B$ l3 E: A3 E
- NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;//TIM3中断
: o! I, @ H+ S& s+ U; l - NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
% H0 g; p5 `6 \2 b- \6 ^3 ] - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级
+ q M0 N+ q! o$ f! I, Y - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级; w+ J+ R: V; U8 f/ S& _0 m
- NVIC_Init(&NVIC_InitStructure); k3 Q- ?- ^( s# d# q% E
2 B+ L1 X: \. v8 o# W1 U- TIM_Cmd(TIM3,ENABLE);//使能TIMx
7 {* J! f& ~2 i, y, m1 m# W1 Q! T - }
8 P& ^5 b* B# D# N- i$ w0 s3 z - . j" X% s) ~) X, P* Q2 C
- void TIM3_IRQHandler(void)//TIM3中断函数
# I" j2 A3 Z* a& s - {5 _7 O4 n7 l N5 l+ ]' h* t
- if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)//检查TIM3更新中断发生与否
; n$ ~( i% D/ L; E" g - {/ Z( K0 s0 D- n6 w1 c3 R1 o
- TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除TIMx更新中断标志
+ }/ N' x' p; z) P5 H1 C - LED0=!LED0;8 O3 o% o( m$ r
- }8 n$ M0 H. `* V# L4 b
- }
) N; h* v: H8 D) t- m7 w
2 a+ U. @* h1 S8 L* _' \- Q
% G* n. @3 C/ w7 b/ g4 O0 Q- void DJ_Init(void)6 _3 O& c' W8 a
- {
* C8 J) x0 e& k8 j$ c4 ? o+ N - GPIO_InitTypeDef GPIO_InitStruct;$ F# b0 E1 O9 |9 P: C! }" t
/ | {0 q5 \$ k ?" g- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB* H3 Z! v3 I7 B# s: I' C5 }' X
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);//使能GPIOG
4 Q1 I) a* a. v9 p8 H( ^
& y0 \4 Z. u9 r/ f% Y/ b5 Q- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 ( V9 J3 U2 r- d& o9 U I8 j
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_4;+ Z$ D+ Z6 H4 Z
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
5 }& w& {* T2 I5 g8 n) l - GPIO_Init(GPIOB,&GPIO_InitStruct);$ E) f& }, f) z
- GPIO_SetBits(GPIOB,GPIO_Pin_6);
( T$ v D. l/ L - + x4 `3 O8 N# }
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 - X& @. O i, f9 D' S% z
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
% `6 |7 g4 L2 ~: a - GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;, i. J! i! b' V
- GPIO_Init(GPIOG,&GPIO_InitStruct);( ?7 T, O, A7 v( _5 Q. h+ m
- GPIO_SetBits(GPIOG,GPIO_Pin_9);
: K+ D9 i0 {. e2 {% [) Q" ^9 O, l - }
复制代码 ②主函数(具体操作控制)2 v2 N0 h7 d! b
- #include "stm32f10x.h"- P/ v- \% y; e
- #include "usart.h": f. F& L; h$ [$ Y$ V2 x
- #include "led.h"9 I% x! L. \9 G1 I) j
- #include "delay.h"' r5 Z5 |. y5 L+ J+ d" ?+ U
- #include "sys.h"
% Q, H9 j+ r7 L: X4 O - #include "timer.h"( n$ s; H' @' E: z* i
- #include "key.h"
2 L1 m, x) X# R, M* l - #include "dianji.h"
: |' M* o: y# C) w( }3 K - : R* Q( S5 M$ a' a4 p& o K
- #define up 1
+ X2 h% v6 H2 W8 ]" s: { - #define down 01 q& z q. `+ r2 K2 D |% r
; Q/ u% Y* G. I( T5 p5 M( c* ^- # w6 A/ m2 ?7 u' }6 w% M
- int main(void)9 F& X/ F0 P$ K& Q# T
- {1 V F- C# v0 K2 c) [9 q/ V& ^
- vu8 key = 0; \; _. w3 C" v$ X0 a* J
- vu8 key1 = 0;) I1 T0 B _3 P% c# Q2 g7 L
- vu8 num0 = 0;
, b' Q+ y+ b) d6 E8 G7 d5 T3 u8 q7 M0 } - vu8 num1 = 0;1 ]7 @9 s" a( r# G8 u C+ d8 M
- vu8 num2 = 0;
& x+ N' x9 O) S1 t' L: o - vu8 speed = 1; p! {6 [5 J; n4 S) H8 ~
- vu16 arrLowest = 189;* q8 v! m. N6 J# ~: N
- vu16 arrMax= 409;2 w- P7 j) p: F' s
- vu16 arr =299;7 O& V0 a. `8 e! M
- vu16 psc = 359;+ u+ r4 f6 r. ~9 O2 Z3 `
- LED_Init();3 v% \1 e% k3 a5 i K
- delay_init();
2 n9 D8 v/ {4 X! A. V - KEY_Init();
- D) ^$ Y q8 l1 C A7 B9 ~ - DJ_Init();/ l* a' G( U! a. Z
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
3 W) l4 I, |9 i& K) g# _ - uart_init(115200); //串口初始化为1152004 F8 i& y# R* y0 O( c n, M
- 3 Z3 q% ?- V, c7 a
- TIM3_Int_Init(arr,psc);//10Khz的计数频率,计数到100为10ms (arr+1)*(psc+1)/72
' \% L. j, G. }4 B* R. R: B - while(1)
( i8 Z7 d: G3 Z& [5 _ - { ' |. \& B/ o. S" ^) ^
- key = KEY_Scan(0);" `5 j* }; {, }' ^" i' X
- if(key == KEY0_PRES)2 e% s: U) i$ n6 H
- {$ d, v* q6 A% |
- if(num0 == 0)4 r, D6 F# h( z
- { L2 C" z( q6 _. S
- num0 = 1;
. ~$ m. z: ~; c) A - LED1=0;
' ]- @! a) u5 n& k" p0 ? - GPIO_ResetBits(GPIOB,GPIO_Pin_6);
7 M( T; a! n2 y4 z5 W; ? - }
- k! H0 Q# i3 f& c$ F3 M, w - else6 j( a z: F; W8 E5 Z U, D& W
- {
( m; q" d: ` R1 V: w' r - num0 = 0;+ m# {1 H8 q* v
- LED1=1;
+ b9 j6 J! p9 V- o6 J3 z - GPIO_SetBits(GPIOB,GPIO_Pin_6);. J7 e2 O, m1 I N+ m
- }+ @& m' Y1 M Z8 \! _" ]- ?
- } ( K" W( j* ~! a1 j
- if(key == KEY1_PRES)
' V7 e% F% ~1 o - {
8 W# P F, A# N: R9 \ - if(num2 == 0). [. P3 ?! \: Y% k, O
- {, k% Y! J1 ] v' ^
- GPIO_SetBits(GPIOG,GPIO_Pin_9);; j) N* o+ {! v3 A* w
- num2 = 1;
/ j; D. ]4 p/ r7 G4 ?2 [% f - }! q: h% z6 g* B% N5 a
- else
4 ]' V8 F1 c( F8 ~9 [0 P" ^ - {
9 b5 S3 m' e6 B5 _ - GPIO_ResetBits(GPIOG,GPIO_Pin_9);
+ G0 ]* H4 K5 E4 i - num2 = 0;8 b) A$ F3 q5 S' U1 \
- }
% e* y. B# a x* F p+ H - }) k P' E& N3 o) k$ L5 d" g4 }
- while(key == WKUP_PRES)
; M# F3 m: l$ I7 _ n* G9 m - {
6 f( H' U* |+ d; P. c& C - if(speed == down)" R* M9 `9 s8 e! Y# n+ e
- {
2 ~* i$ Y6 r. z+ c - arr+=2;
# z* H! }$ `5 K6 o1 u5 o4 i - TIM3_Int_Init(arr,psc); % R: N6 J2 F: Z3 @& I# k4 R
- delay_ms(50);
; ?/ Q6 s. M7 h+ i/ y- x - key1 = KEY_Scan(0);4 ?& E* P. X! i
- if(arr > arrMax)
$ ~3 q$ m- `+ j. ?; r |0 n; |. a4 G, ^) y - {" l" E- a: G1 B) s0 Q$ S* r9 p- p: G
- speed = up;+ Y/ y, ]- |; |& d
- }
; F4 B5 @1 K* I$ @% Z/ h+ P - if(key1 == WKUP_PRES)//关闭变速. u. e9 `6 |% I y5 t7 Q4 T
- {! e P4 _# }8 N" l$ ?+ ]
- LED1 = 0;
8 v& x4 z" r0 i3 O - key = 0;
% U" a7 x1 d4 g& O - }
9 Z* r6 B: z. g; h+ z! ]( E - }. N) E" G. M4 A5 O4 {, u* K; S+ |
- if(speed == up)
8 s# N' n; b: D# F. N - {
+ t7 f1 n- L- \8 | - arr-=2;
& P, P- V) u; B. ^3 c+ s2 [ { - TIM3_Int_Init(arr,psc);
% @8 \( @2 K: f9 f - delay_ms(50);
: |9 j' | X- W$ _/ O' |) i' s, Z - if(arr < arrLowest)3 b1 ?, N1 E' X% U9 d
- {
) g& W8 M" P4 |: B6 h5 \5 V - speed = down;/ R( p7 L+ b& c" h8 q1 q& m3 x0 _
- }
2 O7 U4 M. N3 |4 t8 c9 c+ @ - key1 = KEY_Scan(0);$ \) x' M- o0 G
- if(key1 == WKUP_PRES)
% ` P, C- k; ^1 W* C - {
( p8 J$ U; `" K) t - LED1 = 0;
3 A! `* f. v- W# O$ t5 c - key = 0;
; L' A6 Q, J! s8 {5 V( Y+ b4 I* X - } " U2 U- K3 \" v5 O2 l" {
- }
3 ]/ G) A, G9 [! L! B) M7 p/ ], r- P! F - } : z# D( o( ^& C8 b$ M
- }
3 j8 W. u0 z. f2 |2 X - }
复制代码 4.总结
( x& P) W4 v" V' Q M通过以上过程的调试,我实现了用按键控制步进电机的启动、截止、变向以及加减速这些功能。3 M. d: i3 J6 U/ Q
可能我的电机驱动和大家的不一样, 希望能让读者起到参考作用。4 C9 H! u, y3 }. o& f0 A: |0 ^9 T
$ p h5 S) w) k! n |