最近在做一个案例,要求ARDUINO板驱动两个NEMA17电机. 查了以下,有个AccelStepper.h库,用着也挺方便.但我有另一个硬性的要求,用这个库很难实现.索性自己写了个程序,完成了这一目标.
这个硬性的要求就是:两个电机要同步,即同时起步,同时停止.旋转的速度和方向可以不一样.
下面是实现的详细过程.
1.BOM
ARDUINO uno R3,1
A4988,2
5V power,1(单独给电机供电)
小面包板,1
面包线,若干
2,示意图
3,操作说明
通过ARDUINO IDE的串口监视器输入控制命令:
1,点亮LED灯
0,熄灭LED灯
4,前进200步
5,后退200步
8,先前进,再后退,即两电机先正转,再反转
9,先右旋转,再左旋转,即两电机先左正右反,再左反右正.
在电机运转时,LED等点亮.
4,指令说明
指令格式:200,400,1000000,1
200-左电机运行步数,正为前进,负为后退;
400-右电机运行步数,正为前进,负为后退;
1000000-表示在1秒内完成运行动作,单位为微秒;
1-为舵机预留的控制位.
5,源程序
// UNO + A4988 + NEMA17
//此模式两个电机可以是同步运行的,即能保持“以不同的旋转速度”同时旋转(同时开始,同时停止)。
// 逐步改进,时间、速度可输入;
// 停止是处于非激活状态
int ledpin=13 ; //定义LED灯引线。
// 步进电机
// Enable,STEP步距,DIR方,MS1/MS2
int PIN[2][3]={
{4,3,2}, //电机1 的IO引脚,
{7,6,5} //电机2 的IO引脚,
};
void setup()
{
Serial.begin(9600); //用蓝牙监视器代替
// 初始化步进电机的引脚
for(int i=0;i<2;i++)
for(int j=0;j<3;j++)
pinMode(PIN[i][j] ,OUTPUT);
pinMode(ledpin, OUTPUT); //设置管脚2为输出模式 , 板载LED
Serial.begin(9600);
digitalWrite(PIN[0][0],HIGH); // 输出高电平,关闭电机
digitalWrite(PIN[1][0],HIGH); // 输出高电平,关闭电机
}
long int num = 0;
void loop()
{
int inChar; // 接受从串口监视器传来的信息,如果是蓝牙监视器的话,则接受从蓝牙监视器传来的信息。
if (Serial.available()) {
inChar = Serial.read();
Serial.write(inChar);
switch (inChar) {
case '1':
digitalWrite(ledpin, HIGH); // 点亮LED
break;
case '0':
digitalWrite(ledpin, LOW); // 熄灭LED
break;
case '4':
CarRun("200,400,1000000,1");
break;
case '5':
CarRun("-200,-400,1000000,0");
break;
case '8':
CarRun("2000,2000,10000000,1,-2000,2000,10000000,0");
break;
case '9':
CarRun("1000,-2000,10000000,1,-1000,2000,10000000,0");
break;
default:
Serial.println(F("Wrong Input :("));
break;
}
}
}
// 步进电机的旋转,200步为一周,正值为逆时针,负值为顺时针
// step1 电机1的步进数
// step2 电机2的步进数
// msec 旋转时间,单位为微秒(us)
void Run(long int step1,long int step2,unsigned long int msec) {
if(step1>0){
digitalWrite(PIN[0][2],HIGH); // 设置高电平的方向 逆
} else {
digitalWrite(PIN[0][2],LOW); // 设置低电平的方向 顺
step1 = -step1;
}
if(step2>0){
digitalWrite(PIN[1][2],HIGH); // 设置高电平的方向 逆
} else {
digitalWrite(PIN[1][2],LOW); // 设置低电平的方向 顺
step2 = -step2;
}
unsigned long int mtime0,n1,n2;
mtime0=micros();
n1 = 0;
n2 = 0;
// 以下循环中不要出现与运转无关的语句或运算,否则可能出现较大的运行误差。
while(micros()-mtime0<msec){
if((micros()-mtime0)>=n1*(unsigned long int)(msec/step1))
{ digitalWrite(PIN[0][1],HIGH);
delayMicroseconds(10);
digitalWrite(PIN[0][1],LOW);
delayMicroseconds(10);
n1++;
}
if((micros()-mtime0)>=n2*(unsigned long int)(msec/step2))
{ digitalWrite(PIN[1][1],HIGH);
delayMicroseconds(10);
digitalWrite(PIN[1][1],LOW);
delayMicroseconds(10);
n2++;
}
}
}
//小车运动
void CarRun(String Dstr)
{
long int data1,data2,time1;
int servo;
long int dats[100];
for(int i=0;i<100;i++){
dats[i]=0;
}
int N = GetNums(Dstr,dats); //4的倍数
digitalWrite(PIN[0][0],LOW); // 输出低电平,启动电机
digitalWrite(PIN[1][0],LOW); // 输出低电平,启动电机
digitalWrite(ledpin, HIGH); // 点亮LED
for(int n=0;n<N/4;n++) {
data1 = dats[n*4];
data2 = dats[n*4+1];
time1 = dats[n*4+2];
servo = dats[n*4+3];
Serial.print(F("data:"));
Serial.print(data1); Serial.print(F(","));
Serial.print(data2); Serial.print(F(","));
Serial.print(time1); Serial.print(F(","));
Serial.print(servo); Serial.println(F("<<<"));
Run(data1,data2,time1);
}
digitalWrite(PIN[0][0],HIGH); // 输出高电平,关闭电机
digitalWrite(PIN[1][0],HIGH); // 输出高电平,关闭电机
digitalWrite(ledpin, LOW); // 熄灭LED
}
//将从串口读取的数据串str进行解析到num中
//输入:str---字符串指针,
// num---要保存数字的数组指针
//返回:数字个数
// 只取整型
int GetNums(const String str,long int* num)
{
int len=str.length(); //strlen(str);
int index=0; //数值个数
int t; //某位的数字
int p=1; //默认为正数,-1为负数
int nFlag=0; //1:表示取到一个数字
for(int i=0;i<len;i++)
{
if(str[i]=='-') {
p=-1;
continue;
}
while(!((str[i]>='0'&&str[i]<='9')||str[i]=='+'))
{
i++;
}
while(str[i]>='0'&&str[i]<='9')
{
nFlag=1;
t=str[i]-'0';
num[index]=num[index]*10+t;
i++;
if(i==len) break;
}
if(nFlag==1){
num[index] *= p;
index++;
}
p=1;
nFlag=0;
}
return index;
}
最后说明:
电机请接12V电源,5V可能运转不畅!