http://www.arduino.cn/thread-16151-1-1.html
在做arduino的步进电机实验时,很多人都是直接用IDE自带的stepper库来驱动步进电机。但是这个库只封装了2拍和4拍的步进电机驱动,而很多步进电机(如常见的28BYJ-48)是8拍驱动的。当然4拍也可以转起来,不过精度、平稳性和力矩都没有8拍好。
其实,驱动步进电机是个很简单的事情。在每种电机的资料中,都有驱动表格,如果有一定的编程能力,最好自己写个函数来驱动,可以做到最简洁而优雅,且占用最少的资源。这种简单的驱动,没有必要封装成库。
作为例子,针对上述28BYJ-48步进电机(5V,步进角度5.625,5线4相,8拍驱动,机械减速1:64),做了两个驱动函数。第一个示例函数用传统的方式,代码使用switch case结构,看起来比较清晰,可以作为思路的参考。第二个示例函数用了单片机口的概念,体现了单片机的特点,简洁而优雅。
这两个示例函数可以在1.0版以上的IDE中调用,都已测试通过。测试的最新版本是1.6.3。
只要有步进电机的驱动数据表格,这两个函数稍作修改就可以用于各种步进电机。
下面是28BYJ-48步进电机的驱动表格。
函数一测试代码:
int p = 0; // 拍计数,顺时针7-0,逆时针0-7。
int t=24; // 每拍延时,控制速度,1ms对应最高速。
// 负值为逆时针方向。
void setup() {
Serial.begin(9600); //初始化串口,作为监视。
pinMode(4,OUTPUT); //设置D4-D7脚为步进电机控制脚。
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
}
void loop() {
// Serial.println(p); // 串口输出拍数,调试用。
t = 1; // 每拍延时24ms,设置转速和方向。负值逆时针转。
one_step(t); // 驱动一拍。
}
// 此函数驱动一拍,参数控制速度与旋转方向。
void one_step(int t) {
switch(p) {
case 0: // (0001) 对应8拍不同的输出值。
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
break;
case 1: // (0011)
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
digitalWrite(7,HIGH);
break;
case 2: // (0010)
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
break;
case 3: // (0110)
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
break;
case 4: // (0100)
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
break;
case 5: // (1100)
digitalWrite(4,HIGH);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
break;
case 6: // (1000)
digitalWrite(4,HIGH);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
break;
case 7: // (1001)
digitalWrite(4,HIGH);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
break;
}
if (t < 0) { // t为负值,正向计数0-7。
p ++;
if (p > 7 ) {
p = 0; // 计数到7重新开始。
}
} else { // t为正值,逆向计数7-0。
p --;
if ( p < 0 ) { // 计数到零重新开始。
p = 7;
}
}
Serial.println(abs(t));
delay(abs(t)); // 延时,短则转速高。
}
函数one_step()可以驱动一拍,使用方法在注释中都有。速度用延时函数控制,延时越少,速度越快。延时1ms可以轻松启动。注意,使用串口调试时,每发送一条串口数据,会有5ms左右的延时(在我自己的计算机上测试的数据)。这个延时也会包括在每一拍的驱动延时中。
函数二测试代码:
[C]
纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/* 步进电机8拍驱动,对应28BYJ-48,每圈64步,减速比64,
输出轴每圈4096步。使用二进制掩码直接置位输出口。
*/
int
p = 0;
// 拍计数,顺时针0-7,逆时针7-0。
int
t;
// 每拍延时,控制速度,1ms对应最高速。负值为逆时针方向。
byte b[] = {B00010000,B00110000,B00100000,B01100000,
B01000000,B11000000,B10000000,B10010000};
// 对应每拍的D4-D7脚输出掩码。高4位有效。
void
setup() {
// Serial.begin(9600); // 初始化串口,作为监视。
DDRD = DDRD | B11110000;
// 置D4-D7脚为步进输出,其它脚不变。
}
void
loop() {
// Serial.println(p); // 串口输出拍数,调试用。
t = -24;
// 每拍延时24ms,设置转速和方向。负值逆时针转。
one_step(t);
// 驱动一拍。
}
// 此函数驱动一拍,参数控制速度与旋转方向。
void
one_step(
int
t) {
PORTD = PORTD & B00001111;
// 清除D4-D7脚,D0-D3脚不变。
PORTD = PORTD | b[p];
// 置位D4-D7脚,D0-D3脚不变。
// Serial.println(PORTD,BIN); // 串口输出掩码,调试用。
if
(t < 0) {
// t为负值,逆向计数0-7。
p --;
if
(p < 0 ) {
p = 7;
// 计数到0重新开始。
}
}
else
{
// t为正值,逆正向计数7-0。
p ++;
if
( p > 7 ) {
// 计数到7重新开始。
p = 0;
}
}
delay(
abs
(t));
// 延时,短则转速高。
}
|
函数one_step()可以驱动一拍,使用方法在注释中都有。DDRD和PORTD是IDE的内置常数,分别表示arduino板上D0-D7脚的输出方向和输出状态,用二进制数直接可以定义。具体可查阅http://wiki.geek-workshop.com/doku.php?id=arduino:arduino_language_reference。
在arduino的学习和实验中,建议还是要学一点单片机的编程知识,最好不要照搬教程或者别人的代码,至少要问一个问什么。可以打开看看自己用到的官方库或第三方库,是不是适合自己的硬件。
代码的简洁和优雅,体现了编程的教养。