当前位置: 首页 > news >正文

零基础入门学用Arduino 第四部分(三)

重要的内容写在前面:

  1. 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。
  2. 个人把这个教程学完之后,整体感觉是很好的,如果有条件的可以先学习一些相关课程,学起来会更加轻松,相关课程有数字电路(强烈推荐先学数电,不然可能会有一些地方理解起来很困难)、模拟电路等,然后就是C++(注意C++是必学的)
  3. 文章中的代码都是跟着老师边学边敲的,不过比起老师的版本我还把注释写得详细了些,并且个人认为重要的地方都有详细的分析。
  4. 一些函数的介绍有参考太极创客官网给出的中文翻译,为了便于现查现用,把个人认为重要的部分粘贴了过来并做了一些修改。
  5. 如有错漏欢迎指正。

视频链接:4-1-1 电机基本结构与工作原理_哔哩哔哩_bilibili

太极创客官网:太极创客 – Arduino, ESP8266物联网的应用、开发和学习资料

四、Arduino AFMotor电机扩展板

1、Arduino AFMotor电机扩展板概述

(1)Arduino AFMotor电机扩展板专门与Arduino开发板配合使用,如下图所示,它是直接插在Arduino开发板上的。

(2)AFMOTOR电机扩展板主要功能特点:

①最多可驱动4个模型直流电机。

②最多可驱动2个28BYJ-48步进电机。

③最多可驱动2个舵机(伺服电机)。

④板载两块L293D芯片负责电机驱动的核心工作

⑤可配合Arduino Uno/Mega开发板使用(这里主要针对Uno开发板进行介绍)。

(3)Arduino AFMotor电机扩展板的各个端口如下所示。

①AFMotor电机扩展板上配有外接电源接口,该接口所连接的直流电源可以为电机和Arduino开发板供电。

[1]使用AFMotor电机扩展板驱动电机时,要考虑的问题就是电源的输出功率需要达到驱动电机的要求(对于工作电压低于4.5V的直流电机,不建议使用AFMotor驱动板来驱动),并且不宜过大。

[2]AFMotor扩展板中起关键作用的芯片是L293D,该芯片所允许的直流电源电压范围是4.5V ~25V,因此AFMotor扩展板外接电源接口允许连接的电源也是4.5V~25V。

[3]通常我们使用AFMotor电机扩展板所驱动的电机就是普通的模型电机,对于这一类型的电机,它们的工作电流大约是500mA左右,因此只要为扩展板配一个500 mA~1000 mA的外接电源就足够了;假如电机工作电流超过500mA,那么就要考虑为扩展板上的L293D加装芯片。

[4]外接电源极性千万不要接反,否则会对扩展板造成损坏。

②Arduino开发板的模拟输入输出引脚(A0~A5)没有被AFMotor扩展板所占用,模拟输入输出引脚被AFMotor扩展板延申至板上以便使用。模拟引脚旁的另外两排引脚分别是Arduino的+5V引脚和接地引脚。

③Arduino引脚2和引脚13都没有被AFMotor电机扩展板所占用。

2、AFMotor库

(1)使用AFMotor电机扩展板驱动电机以前,需要先将AFMotor库(属于第三方库)安装到Arduino IDE中。

(2)AFMotor库函数:

①AF_DCMotor.setSpeed(speed):将电机AF_DCMotor的运行速度设置为speed(取值范围为0-255)。

②AF_DCMotor.run(mode):mode的可选值为RELEASE、FORWARD、BACKWARD。

[1]RELEASE:让扩展板停止为电机AF_DCMotor提供运转动力,电机AF_DCMotor一旦失去动力就会自然的停止转动

[2]FORWARD:设置电机AF_DCMotor的运动方向为正向。

[3]BACKWARD:设置电机AF_DCMotor的运动方向为反向。

③AF_DCMotor.step(steps, mode1, mode2):该函数针对步进电机,其中steps为控制步进电机运动的步数,mode1的可选值为FORWARD、BACKWARD,即选择运动方向为正向或反向,mode2的可选值为SINGLE、DOUBLE、INTERLEAVE、NICROSTEP,其意义分别为全步进模式(单线圈)、全步进模式(双线圈)、半步进模式、微步进模式。

④AF_DCMotor.onestep(mode1, mode2):该函数针对步进电机,其中mode1的可选值为FORWARD、BACKWARD,即选择运动方向为正向或反向,mode2的可选值为SINGLE、DOUBLE、INTERLEAVE、NICROSTEP,即选择运动方式。

(3)借助AF_Stepper类,可以建立AccelStepper库能使用的步进电机对象。根据之前的经验,AccelStepper类的对象的构造函数参数可以是步进模式以及4个控制引脚编号,在这里可以将构造函数的参数替换为两个自定义函数的函数名,两个函数均封装一个AF_Stepper类的onestep函数,分别控制AF_Stepper对象的电机在正反方向上各走一步,根据这两个函数,Arduino可得到AF_Stepper对象的电机的相关信息,用于初始化AccelStepper类的对象。

3、Arduino驱动直流电机

(1)在AFMotor电机扩展板的两侧共有4个直流电机端口,每一个端口都有独立的编号,分别为M1、M2、M3、M4,每一个电机端口都是由两个接线端子所构成,如下图所示。如果只是单纯的想要让电机转起来,那么这两根引线连接到扩展板端口上是没有顺序的;但如果对电机的旋转方向有所要求,而电机旋转的方向与用户所期待的相反,那么可以将这两根电机引线从扩展板上断开,然后交换顺序再接到扩展板端子上,这时会看到电机旋转的方向就反过来了。

(2)驱动直流电机电路的连接:

①项目开发时驱动直流电机电路的连接:(下图红色箭头指示的跳线一定要移除,该跳线的作用是控制Arduino开发板由外接电源供电,而项目开发时Arduino开发板由电脑供电)

②工作运行时驱动直流电机电路的连接:(下图红色箭头指示的跳线要安置好,工作运行时Arduino开发板由外接电源供电)

(3)示例程序:

#include <AFMotor.h>
AF_DCMotor motor1(1); //为1号电机建立对象,1号电机连接AFMotor扩展板的电机端口号码为1
AF_DCMotor motor2(2); //为2号电机建立对象,2号电机连接AFMotor扩展板的电机端口号码为2
AF_DCMotor motor3(3); //为3号电机建立对象,3号电机连接AFMotor扩展板的电机端口号码为3
AF_DCMotor motor4(4); //为4号电机建立对象,4号电机连接AFMotor扩展板的电机端口号码为4void setup() 
{//4个电机的转速均设置为200motor1.setSpeed(200);motor2.setSpeed(200);motor3.setSpeed(200);motor4.setSpeed(200);//初始时电机全部不转动motor1.run(RELEASE);motor2.run(RELEASE);motor3.run(RELEASE);motor4.run(RELEASE);
}void loop() 
{//将4个电机的旋转方向均设置为正向motor1.run(FORWARD);motor2.run(FORWARD);motor3.run(FORWARD);motor4.run(FORWARD);for (int i=0; i<=255; i++){   //从0开始,4个电机的转速每隔10ms增加1,直至增加到255motor1.setSpeed(i);motor2.setSpeed(i);motor3.setSpeed(i);motor4.setSpeed(i);delay(10);}                             for (int i=255; i>=0; i--){  //从255开始,4个电机的转速每隔10ms减小1,直至减小到0motor1.setSpeed(i);motor2.setSpeed(i);motor3.setSpeed(i);motor4.setSpeed(i); delay(10);} //对于一些模型电机来说,当速度参数小于一定数值以后就不能转动了,这属于正常现象//将4个电机的旋转方向均设置为反向motor1.run(BACKWARD);motor2.run(BACKWARD);motor3.run(BACKWARD);motor4.run(BACKWARD);for (int i=0; i<=255; i++){   //从0开始,4个电机的转速每隔10ms增加1,直至增加到255 motor1.setSpeed(i);motor2.setSpeed(i);motor3.setSpeed(i);motor4.setSpeed(i); delay(10);}for (int i=255; i>=0; i--){  //从255开始,4个电机的转速每隔10ms减小1,直至减小到0  motor1.setSpeed(i);motor2.setSpeed(i); motor3.setSpeed(i);motor4.setSpeed(i); delay(10);} //对于一些模型电机来说,当速度参数小于一定数值以后就不能转动了,这属于正常现象//停止为4个电机提供运转动力motor1.run(RELEASE);motor2.run(RELEASE);motor3.run(RELEASE);motor4.run(RELEASE);delay(1000);  //让4个电机保持无旋转动力状态1秒钟
}

4、Arduino驱动28BYJ-48步进电机

(1)在AFMotor电机扩展板的两侧共有两个步进电机端口,每一个电机端口都是由五个接线端子所构成。

(2)驱动28BYJ-48步进电机电路的连接:

①项目开发时驱动28BYJ-48步进电机电路的连接:(下图红色箭头指示的跳线一定要移除,该跳线的作用是控制Arduino开发板由外接电源供电,而项目开发时Arduino开发板由电脑供电)

②工作运行时驱动28BYJ-48步进电机电路的连接:(下图红色箭头指示的跳线要安置好,工作运行时Arduino开发板由外接电源供电)

(3)示例程序:

①示例程序1:

#include <AFMotor.h>AF_Stepper motor1(2048, 1);  //为步进电机1建立步进电机对象,它旋转一周的步数为2048,连接在扩展板上的端口号为1
AF_Stepper motor2(2048, 2);  //为步进电机2建立步进电机对象,它旋转一周的步数为2048,连接在扩展板上的端口号为2void setup() 
{Serial.begin(9600);      //启动串口通讯motor1.setSpeed(10);     //设置电机1的运行速度参数为10motor2.setSpeed(10);     //设置电机2的运行速度参数为10
}void loop() 
{Serial.println("Single Mode");motor1.step(2048, FORWARD, SINGLE); //步进电机1以全步进模式(单线圈)"正转"2048步motor1.step(2048, BACKWARD, SINGLE);//步进电机2以全步进模式(单线圈)"反转"2048步Serial.println("Double Mode");motor2.step(2048, FORWARD, DOUBLE); //步进电机1以全步进模式(双线圈)"正转"2048步motor2.step(2048, BACKWARD, DOUBLE);//步进电机2以全步进模式(双线圈)"反转"2048步Serial.println("Interleave Mode");motor1.step(2048, FORWARD, INTERLEAVE);    //步进电机1以半步进模式"正转"2048步motor1.step(2048, BACKWARD, INTERLEAVE);   //步进电机2以半步进模式"反转"2048步Serial.println("Micrsostep Mode");motor2.step(2048, FORWARD, MICROSTEP);      //步进电机1以微步进模式"正转"2048步motor2.step(2048, BACKWARD, MICROSTEP);     //步进电机2以微步进模式"反转"2048步
}

②示例程序2:

#include <AFMotor.h>
#include <AccelStepper.h>AF_Stepper motor1(2048, 1);  //为步进电机1建立步进电机对象,它旋转一周的步数为2048,连接在扩展板上的端口号为1
AF_Stepper motor2(2048, 2);  //为步进电机2建立步进电机对象,它旋转一周的步数为2048,连接在扩展板上的端口号为2void forwardstep1() {                motor1.onestep(FORWARD, SINGLE);    //电机1正向旋转1步
}                                     
void backwardstep1() {  motor1.onestep(BACKWARD, SINGLE);   //电机1反向旋转1步
}
void forwardstep2() {  motor2.onestep(FORWARD, SINGLE);    //电机2正向旋转1步
}
void backwardstep2() {  motor2.onestep(BACKWARD, SINGLE);   //电机2反向旋转1步
}//借助AF_Stepper类,建立AccelStepper库能使用的步进电机对象
AccelStepper stepper1(forwardstep1, backwardstep1);  //根据让电机1在正反向各旋转1步的自定义函数,Arduino可得到电机1的相关信息,用于初始化stepper1
AccelStepper stepper2(forwardstep2, backwardstep2);  //根据让电机2在正反向各旋转1步的自定义函数,Arduino可得到电机2的相关信息,用于初始化stepper2void setup()
{        stepper1.setMaxSpeed(500);  //设置电机1的最大运行速度为500stepper1.setSpeed(300);     //设置电机1在匀速模式下的运行速度为300stepper2.setMaxSpeed(500);  //设置电机2的最大运行速度为500stepper2.setSpeed(300);     //设置电机2在匀速模式下的运行速度为300
}void loop()
{  stepper1.runSpeed();  //电机1匀速旋转stepper2.runSpeed();  //电机2匀速旋转
}

③示例程序3:

[1]全局变量、宏定义、包含头文件及初始化操作:

#include <AccelStepper.h>
#include <AFMotor.h>#define stepperSpeed 300    //匀速模式下电机的运动速度
AF_Stepper motor1(2048, 1);  //为步进电机1建立步进电机对象,它旋转一周的步数为2048,连接在扩展板上的端口号为1
AF_Stepper motor2(2048, 2);  //为步进电机2建立步进电机对象,它旋转一周的步数为2048,连接在扩展板上的端口号为2
char cmd;        //存储电机指令字符
int data;        //存储电机指令参数
int stepperNum;  //存储当前控制电机的编号void forwardstep1() {                motor1.onestep(FORWARD, SINGLE);    //电机1正向旋转1步
}                                     
void backwardstep1() {  motor1.onestep(BACKWARD, SINGLE);   //电机1反向旋转1步
}
void forwardstep2() {  motor2.onestep(FORWARD, SINGLE);    //电机2正向旋转1步
}
void backwardstep2() {  motor2.onestep(BACKWARD, SINGLE);   //电机2反向旋转1步
}
//借助AF_Stepper类,建立AccelStepper库能使用的步进电机对象
AccelStepper stepper1(forwardstep1, backwardstep1);  //根据让电机1在正反向各旋转1步的自定义函数,Arduino可得到电机1的相关信息,用于初始化stepper1
AccelStepper stepper2(forwardstep2, backwardstep2);  //根据让电机2在正反向各旋转1步的自定义函数,Arduino可得到电机2的相关信息,用于初始化stepper2void setup()
{    stepper1.setMaxSpeed(stepperSpeed); //设置1号电机匀速模式下的运动速度为300stepper1.setAcceleration(100.0);    //设置1号电机的加速度为50.0stepper2.setMaxSpeed(stepperSpeed); //设置2号电机匀速模式下的运动速度为300stepper2.setAcceleration(100.0);    //设置2号电机的加速度为50.0 Serial.begin(9600);Serial.println(F("++++++++++++++++++++++++++++++++++"));     Serial.println(F("+Taichi-Maker AFMotor Shield Demo+"));   Serial.println(F("+     www.taichi-maker.com       +"));  Serial.println(F("++++++++++++++++++++++++++++++++++"));  Serial.println(F(""));Serial.println(F("Please input motor command:"));    
}

[2]主循环部分:

void loop()
{  if (Serial.available())  //检查串口缓存是否有数据等待传输 {     cmd = Serial.read();        //获取电机指令中指令信息    Serial.print(F("cmd = "));Serial.print(cmd);    Serial.print(F(" , ")); data = Serial.parseInt();   //获取电机指令中参数信息  Serial.print(F("data = "));Serial.print(data);   Serial.println(F(""));    runUsrCmd();   //用户命令处理}stepper1.run();  //设置电机1为先加速后减速模式stepper2.run();  //设置电机2为先加速后减速模式
}

[3]用户命令处理部分:

void runUsrCmd()
{switch(cmd){ case 'o':  //获取当前电机输出轴位置Serial.print(F("stepper1 Position: ")); Serial.println(stepper1.currentPosition());  //获取当前电机1的输出轴位置  Serial.print(F("stepper2 Position: ")); Serial.println(stepper2.currentPosition());  //获取当前电机2的输出轴位置Serial.print(F("Current Running Motor: "));  //输出当前受控制的电机编号if (stepperNum == 1 || stepperNum == 2){  //只有一个电机受控制Serial.print(F("Motor# "));Serial.println(stepperNum); } else if (stepperNum == 0 ){   //两个电机同时受控制Serial.println(F("Both Motors")); }break;    case 'v':  //使电机运行到用户指定的坐标位置if (stepperNum == 1){Serial.print(F("Motor1 'moveTo' "));Serial.println(data); stepper1.moveTo(data);  //控制电机1运行到data对应的绝对位置}else if (stepperNum == 2){Serial.print(F("Motor2 'moveTo' "));Serial.println(data); stepper2.moveTo(data);  //控制电机2运行到data对应的绝对位置 }else if (stepperNum == 0){    //两个电机可以同时运行Serial.print(F("Both Motors 'moveTo' "));Serial.println(data); stepper1.moveTo(data);  //控制电机1运行到data对应的绝对位置stepper2.moveTo(data);  //控制电机2运行到data对应的绝对位置 }break;case 'm':   //使电机运行相应步数(可顺时针也可逆时针)if (stepperNum == 1){Serial.print(F("Motor1 'move'  "));Serial.println(data); stepper1.move(data);  //以当前位置为参照点,控制电机1运行到data对应的相对位置}else if (stepperNum == 2){Serial.print(F("Motor2 'move'  "));Serial.println(data);stepper2.move(data);  //以当前位置为参照点,控制电机2运行到data对应的相对位置}else if (stepperNum == 0){    //两个电机可以同时运行Serial.print(F("Both Motors 'move'  "));Serial.println(data);stepper1.move(data);  //以当前位置为参照点,控制电机1运行到data对应的相对位置stepper2.move(data);  //以当前位置为参照点,控制电机2运行到data对应的相对位置}break;case 'r':  //让电机运行到用户指定的位置 if (stepperNum == 1){Serial.print(F("Motor1 'runToNewPosition' "));Serial.println(data);stepper1.runToNewPosition(data);  //控制电机1运行到data对应的绝对位置}else if (stepperNum == 2){Serial.print(F("Motor2 'runToNewPosition' "));Serial.println(data);stepper2.runToNewPosition(data);  //控制电机2运行到data对应的绝对位置}else if (stepperNum == 0){         //电机1运行结束后,电机2才能开始运行Serial.print(F("Both Motors 'runToNewPosition' "));Serial.println(data);stepper1.runToNewPosition(data);  //控制电机1运行到data对应的绝对位置stepper2.runToNewPosition(data);  //控制电机2运行到data对应的绝对位置 }break;   case 's':   //设置当前位置为用户指定位置值if (stepperNum == 1){Serial.print(F("Set stepper1 Current Position to "));Serial.println(data);   //将电机1输出轴当前位置的数值设置为datastepper1.setCurrentPosition(data); }else if (stepperNum == 2){Serial.print(F("Set stepper2 Current Position to "));Serial.println(data);   //将电机2输出轴当前位置的数值设置为datastepper2.setCurrentPosition(data);}else if (stepperNum == 0){Serial.print(F("Set both steppers' Current Position to "));Serial.println(data);stepper1.setCurrentPosition(data);  //将电机1输出轴当前位置的数值设置为datastepper2.setCurrentPosition(data);  //将电机2输出轴当前位置的数值设置为data}break;case 'a':   //设置电机在先加速后减速模式下运行的加速度 if (stepperNum == 1){Serial.print(F("Motor1 'setAcceleration' "));Serial.println(data);stepper1.setAcceleration(data);   //将电机1的加速度设置为data  }else if (stepperNum == 2){Serial.print(F("Motor2 'setAcceleration' "));Serial.println(data);stepper2.setAcceleration(data);   //将电机2的加速度设置为data   }else if (stepperNum == 0){Serial.print(F("Both Motors 'setAcceleration' "));Serial.println(data);stepper1.setAcceleration(data);   //将电机1的加速度设置为data  stepper2.setAcceleration(data);   //将电机2的加速度设置为data}break;   case 'x':  //设置电机在先加速后减速模式下运行的最大速度   if (stepperNum == 1){Serial.print(F("Motor1 'setMaxSpeed' "));Serial.println(data);stepper1.setMaxSpeed(data);   //将电机1的最大速度设置为data }else if (stepperNum == 2){Serial.print(F("Motor2 'setMaxSpeed' "));Serial.println(data);stepper2.setMaxSpeed(data);   //将电机2的最大速度设置为data  }else if (stepperNum == 0){Serial.print(F("Both Motors 'setMaxSpeed' "));Serial.println(data);stepper1.setMaxSpeed(data);   //将电机1的最大速度设置为data  stepper2.setMaxSpeed(data);   //将电机2的最大速度设置为data  }break;  case 'd':  //用户通过此指令可指定哪一个电机进行工作  if (data == 1 || data == 2){   //指定仅控制电机1或电机2stepperNum = data;Serial.print(F("Running Motor "));Serial.println(stepperNum); }else if (data == 0 ){   //同时控制两个电机工作stepperNum = data;Serial.println(F("Running Both Motors "));  }else {   //参数有误Serial.print(F("Motor Number Wrong.")); }break;         default:  //未知指令Serial.println(F("Unknown Command"));}
}

5、Arduino驱动伺服电机

(1)AFMotor扩展板驱动舵机实际上就是通过Arduino的9号和10号引脚来驱动舵机,10号引脚对应的是扩展板上的servo1端口,9号引脚对应的是servo2端口,如下图所示(直流电源的连接这里不再赘述)。

(2)驱动舵机(伺服电机)示例程序:

#include <Servo.h>Servo servo1;   //建立舵机对象servo1
Servo servo2;   //建立舵机对象servo2
int pos = 0;    //记录舵机轴的当前角度  void setup() 
{servo1.attach(10);  //舵机1接在扩展板servo1端口,servo1端口是由Arduino的10号引脚来控制的servo2.attach(9);   //舵机2接在扩展板servo2端口,servo2端口是由Arduino的9号引脚来控制的
}void loop() 
{for (pos = 0; pos <= 180; pos += 1){   //舵机1从0°旋转至180° servo1.write(pos);delay(15);                       }for (pos = 180; pos >= 0; pos -= 1){   //舵机1从180°旋转至0° servo1.write(pos);delay(15);       }for (pos = 0; pos <= 180; pos += 1){   //舵机2从0°旋转至180°servo2.write(pos);delay(15);                       }for (pos = 180; pos >= 0; pos -= 1){   //舵机2从180°旋转至0° servo2.write(pos);delay(15);       }  
}

五、Arduino CNC电机扩展板

1、Arduino CNC电机扩展板概述

(1)Arduino CNC电机扩展板专门与Arduino开发板配合使用,如下图所示,它是直接插在Arduino开发板上的。

(2)CNC扩展板可以支持A4988、DRV8825等步进电机驱动板,这里主要介绍如何使用A4988驱动板来配合CNC扩展板使用。下图中CNC电机扩展板装配有3个A4988驱动板,实际上最多可以装配4个,具体安装多少个A4988是根据需要驱动步进电机数量来决定的,一台步进电机需要一个A4988。(安装A4988驱动板的时候注意驱动板安装方向不要搞反)

(3)每一个A4988接口上都有三组步进设置插针,这三组插针旁的电路板上印刷有M0/M1/M2,可以(且仅可以)通过在上面安置跳线帽设置电机的步进模式,如下图所示。

(4)Arduino CNC电机扩展板上配有外接直流电源接口,该接口允许接入的电压范围是12V~36V,具体应该连接多大的电源电压是根据被驱动的电机工作电压所决定的,如果使用的电机是NEMA17步进电机(42步进电机),通常该电机的工作电压是12伏特,那么可以为扩展板配一个12伏特的外接电源。

(5)用于控制电机的Arduino引脚与CNC扩展板上印刷的标识的对应关系如下所示,需要注意的是A端口比较特殊。

①Arduino引脚8 —– CNC扩展板EN(所有电机驱动板的使能引脚,低电平有效)。

②Arduino引脚5 —– CNC扩展板X.DIR(X端口方向控制引脚)。

③Arduino引脚2 —– CNC扩展板X.STEP(X端口步进控制引脚)。

④Arduino引脚6 —– CNC扩展板Y.DIR(Y端口方向控制引脚)。

⑤Arduino引脚3 —– CNC扩展板Y.STEP(Y端口步进控制引脚)。

⑥Arduino引脚7 —– CNC扩展板Z.DIR(Z端口方向控制引脚)。

⑦Arduino引脚4 —– CNC扩展板Z.STEP(Z端口步进控制引脚)。

⑧Arduino引脚13—– CNC扩展板A.DIR(A端口方向控制引脚)。

⑨Arduino引脚12—– CNC扩展板A.STEP(A端口步进控制引脚)。

(6)CNC扩展板的端口A比其它三个端口的功能要更丰富一些,它有两种工作模式。

①第一种模式是复制X、Y、Z中任意一个端口上的电机运行情况(以下简称复制模式),所谓复制模式就是端口A所接的电机完全复制其它端口上的电机运行状态,比如将端口A设置为复制端口X,那么端口A电机的运行状况将是完全复制端口X上的电机运行状况,在复制模式下,端口A电机不受Arduino开发板的程序控制而只是单纯地复制端口X电机运行。

②第二种是独立模式来控制电机,这时端口A上的电机会根据Arduino的程序控制运行,在独立模式下,端口A上安装的A4988驱动板的step引脚受Arduino的12号引脚控制,dir引脚受Arduino的13号引脚控制。

③以上两种模式的设置是通过扩展板上专门用于设置端口A工作模式的一系列插针来完成的,如下图所示。

(7)CNC扩展板的其它引脚功能介绍:

①步进电机控制插针共有两排,在插针旁印有各个引脚的名称标识,每行插针标识都使用“/”作为分割,“/”左侧的文字是图中蓝色插针的引脚标识,“/”右侧的文字是图中黄色插针的引脚标识,这些引脚的作用是便于使用Arduino开发板以外的开发板来控制CNC扩展板。

②CNC扩展板右下部分还配有两排很长的引脚插针,其中黑色的引脚全都是GND引脚,白色引脚插针旁的文字标识是这些引脚的名称,它们与Arduino的引脚是联通的,具体如下:

[1]CNC扩展板Z+引脚——Arduino引脚11。

[2]CNC扩展板Z-引脚——Arduino引脚11。

[3]CNC扩展板Y+引脚——Arduino引脚10。

[4]CNC扩展板Y-引脚——Arduino引脚10。

[5]CNC扩展板X+引脚——Arduino引脚9。

[6]CNC扩展板X-引脚——Arduino引脚9。

[7]CNC扩展板SpnEN引脚——Arduino引脚12。

[8]CNC扩展板SpnDir引脚——Arduino引脚13。

[9]CNC扩展板CoolEn引脚——Arduino引脚A3。

[10]CNC扩展板Abort引脚——Arduino引脚A0。

[11]CNC扩展板Hold引脚——Arduino引脚A1。

[12]CNC扩展板Resume引脚——Arduino引脚A2。

[13]CNC扩展板E-STOP引脚——Arduino引脚Reset。

2、Arduino CNC扩展板驱动NEMA步进电机

(1)Arduino CNC扩展板驱动1个NEMA步进电机:

①电路连接:

②示例程序:

#include <AccelStepper.h> const int xdirPin = 5;     //X端口方向控制引脚连接Arduino的引脚号为5
const int xstepPin = 2;    //X端口步进控制引脚连接Arduino的引脚号为2
const int xenablePin = 8;  //使能控制引脚连接Arduino的引脚号为8const int moveSteps = 200;    //对于NEMA 17来说,全步进模式下200步转子旋转一周AccelStepper stepper1(1,xstepPin,xdirPin);  //建立步进电机对象
//“1”表示该电机使用A4988电机驱动板驱动void setup() 
{pinMode(xstepPin,OUTPUT);     //Arduino控制A4988步进引脚为输出模式pinMode(xdirPin,OUTPUT);      //Arduino控制A4988方向引脚为输出模式pinMode(xenablePin,OUTPUT);   //Arduino控制A4988使能引脚为输出模式digitalWrite(xenablePin,LOW); //将使能控制引脚设置为低电平,从而让电机驱动板进入工作状态stepper1.setMaxSpeed(300.0);     //设置电机运行的最大速度300 stepper1.setAcceleration(20.0);  //设置电机的加速度20.0  
}void loop() 
{if (stepper1.currentPosition() == 0){ stepper1.moveTo(moveStep);  //stepper1控制电机正向旋转1周(针对全步进模式)  } else if (stepper1.currentPosition() == moveSteps){stepper1.moveTo(0);          //stepper1控制电机反向旋转1周(针对全步进模式)}         stepper1.run();   //1号电机以先加速后减速的模式运行
}

(2)Arduino CNC扩展板驱动3个NEMA步进电机:

①电路连接:

②示例程序:

#include <AccelStepper.h>const int xenablePin = 8;  //使能控制引脚连接Arduino的引脚号为8
const int xdirPin = 5;     //X端口方向控制引脚连接Arduino的引脚号为5
const int xstepPin = 2;    //X端口步进控制引脚连接Arduino的引脚号为2
const int ydirPin = 6;     //Y端口方向控制引脚连接Arduino的引脚号为6
const int ystepPin = 3;    //Y端口步进控制引脚连接Arduino的引脚号为3
const int zdirPin = 7;     //Z端口方向控制引脚连接Arduino的引脚号为7
const int zstepPin = 4;    //Z端口步进控制引脚连接Arduino的引脚号为4
const int moveSteps = 200;    //测试电机运行使用的运行步数AccelStepper stepper1(1,xstepPin,xdirPin);  //建立步进电机对象1
AccelStepper stepper2(1,ystepPin,ydirPin);  //建立步进电机对象2
AccelStepper stepper3(1,zstepPin,zdirPin);  //建立步进电机对象3void setup() 
{pinMode(xstepPin,OUTPUT);pinMode(xdirPin,OUTPUT);pinMode(ystepPin,OUTPUT);pinMode(ydirPin,OUTPUT);pinMode(zstepPin,OUTPUT);pinMode(zdirPin,OUTPUT);pinMode(enablePin,OUTPUT);digitalWrite(enablePin,LOW);  //将使能控制引脚设置为低电平,从而让电机驱动板进入工作状态stepper1.setMaxSpeed(300.0);stepper1.setAcceleration(20.0);stepper2.setMaxSpeed(300.0);stepper2.setAcceleration(20.0);stepper3.setMaxSpeed(300.0);stepper3.setAcceleration(20.0);
}void loop() 
{if (stepper1.currentPosition() == 0) stepper1.moveTo(moveSteps);    //电机1正向旋转1周(针对全步进模式)        else if (stepper1.currentPosition() == moveSteps)stepper1.moveTo(0);            //电机1反向旋转1周(针对全步进模式)        if (stepper2.currentPosition() == 0)stepper2.moveTo(moveSteps/2);  //电机2正向旋转半周(针对全步进模式)      else if (stepper2.currentPosition() == moveSteps/2)stepper2.moveTo(0);            //电机2反向旋转半周(针对全步进模式)       if (stepper3.currentPosition() == 0)stepper3.moveTo(moveSteps/4); //电机3正向旋转0.25周(针对全步进模式)      else if (stepper3.currentPosition() == moveSteps/4)stepper3.moveTo(0);           //电机3反向旋转0.25周(针对全步进模式)  stepper1.run();stepper2.run();stepper3.run();
}

(3)Arduino CNC扩展板驱动4个NEMA步进电机:

①电路连接:

②示例程序:

#include <AccelStepper.h>const int xenablePin = 8;  //使能控制引脚连接Arduino的引脚号为8
const int xdirPin = 5;     //X端口方向控制引脚连接Arduino的引脚号为5
const int xstepPin = 2;    //X端口步进控制引脚连接Arduino的引脚号为2
const int ydirPin = 6;     //Y端口方向控制引脚连接Arduino的引脚号为6
const int ystepPin = 3;    //Y端口步进控制引脚连接Arduino的引脚号为3
const int zdirPin = 7;     //Z端口方向控制引脚连接Arduino的引脚号为7
const int zstepPin = 4;    //Z端口步进控制引脚连接Arduino的引脚号为4
const int adirPin = 13;    //A端口方向控制引脚连接Arduino的引脚号为13
const int astepPin = 12;   //A端口步进控制引脚连接Arduino的引脚号为12
const int moveSteps = 200;AccelStepper stepper1(1,xstepPin,xdirPin); //建立步进电机对象1
AccelStepper stepper2(1,ystepPin,ydirPin); //建立步进电机对象2
AccelStepper stepper3(1,zstepPin,zdirPin); //建立步进电机对象3
AccelStepper stepper4(1,astepPin,adirPin); //建立步进电机对象4void setup() 
{pinMode(xstepPin,OUTPUT);pinMode(xdirPin,OUTPUT);pinMode(ystepPin,OUTPUT);pinMode(ydirPin,OUTPUT);pinMode(zstepPin,OUTPUT);pinMode(zdirPin,OUTPUT);pinMode(astepPin,OUTPUT);pinMode(adirPin,OUTPUT);pinMode(enablePin,OUTPUT);digitalWrite(enablePin,LOW);stepper1.setMaxSpeed(300.0);stepper1.setAcceleration(20.0);stepper2.setMaxSpeed(300.0);stepper2.setAcceleration(20.0);stepper3.setMaxSpeed(300.0);stepper3.setAcceleration(20.0);stepper4.setMaxSpeed(300.0);stepper4.setAcceleration(20.0); 
}void loop() 
{if (stepper1.currentPosition() == 0) stepper1.moveTo(moveSteps);              else if (stepper1.currentPosition() == moveSteps) stepper1.moveTo(0);       if (stepper2.currentPosition() == 0) stepper2.moveTo(moveSteps/2);              else if (stepper2.currentPosition() == moveSteps/2) stepper2.moveTo(0);  if (stepper3.currentPosition() == 0) stepper3.moveTo(moveSteps/4);              else if (stepper3.currentPosition() == moveSteps/4) stepper3.moveTo(0);  if (stepper4.currentPosition() == 0) stepper4.moveTo(moveSteps/8);              else if (stepper4.currentPosition() == moveSteps/8) stepper4.moveTo(0); stepper1.run();stepper2.run();stepper3.run();stepper4.run();
}

相关文章:

零基础入门学用Arduino 第四部分(三)

重要的内容写在前面&#xff1a; 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。个人把这个教程学完之后&#xff0c;整体感觉是很好的&#xff0c;如果有条件的可以先学习一些相关课程&#xff0c;学起来会更加轻松&#xff0c;相关课程有数字电路…...

Mp3文件结构全解析(一)

Mp3文件结构全解析(一) MP3 文件是由帧(frame)构成的&#xff0c;帧是MP3 文件最小的组成单位。MP3的全称应为MPEG1 Layer-3 音频 文件&#xff0c;MPEG(Moving Picture Experts Group) 在汉语中译为活动图像专家组&#xff0c;特指活动影音压缩标准&#xff0c;MPEG 音频文件…...

ES 8.14 Java 代码调用,增加knnSearch 和 混合检索 mixSearch

1、pom依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>8.14.0</version></dependency><dependency><groupId>co.elastic.clients<…...

被腰斩的颍川郡守赵广汉

在颍川&#xff0c;他发明了举报箱&#xff0c;铁腕扫黑除恶。因为曾经在郡府所在地阳翟&#xff08;禹州&#xff09;当过县令&#xff0c;熟悉颍川社情民意&#xff0c;所以&#xff0c;任职郡守后雷厉风行&#xff0c;才不到一年&#xff0c;不但制服了骄横的豪门大族&#…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 目录管理器(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 目录管理器(200分) 🌍 评测功能需要订阅专栏后私信联系清隆…...

关于自学\跳槽\转行做网络安全行业的一些建议

很好&#xff0c;如果你是被题目吸引过来的&#xff0c;那请看完再走&#xff0c;还是有的~ 为什么写这篇文章 如何自学入行&#xff1f;如何小白跳槽&#xff0c;年纪大了如何转行等类似问题 &#xff0c;发现很多人都有这样的困惑。下面的文字其实是我以前的一个回答&#…...

计算机网络(1) OSI七层模型与TCP/IP四层模型

一.OSI七层模型 OSI 七层模型是国际标准化组织ISO提出的一个网络分层模型&#xff0c;它的目的是使各种不同的计算机和网络在世界范围内按照相同的标准框架实现互联。OSI 模型把网络通信的工作分为 7 层&#xff0c;从下到上分别是物理层、数据链路层、网络层、传输层、会话层、…...

认识QML

为什么使用Qt Quick&#xff1f; Qt4的设计用于满足开发者在主流桌面操作系统上有一套表现一致的窗口组件可以 使用。如今Qt的使用者面临了新的问题&#xff0c;他们需要提供可触碰交互的用户界面以满 足软件界面需求&#xff0c;并在主流桌面操作系统和移动操作系统上实现这些…...

llama-factory微调chatglm3

一、定义 案例/多卡 二、实现 案例 1. 下载chatglm3-6b-32k模型 2. 配置数据集微调指令 CUDA_VISIBLE_DEVICES0,1 llamafactory-cli train \--stage sft \--do_train True \--model_name_or_path /home/chatglm3-6b-32k \--finetuning_type lora \--template chatglm3 \--d…...

大文件上传实现

分片上传 将大文件分割成多个小片&#xff08;chunk&#xff09;&#xff0c;逐个上传。每个片上传成功后&#xff0c;服务器可以返回确认信息。所有片上传完成后&#xff0c;服务器端将这些片重新组合成原始文件。 以下是一个简单的分片上传的前端实现示例&#xff1a; func…...

为何Proteus用户争相拥抱SmartEDA?揭秘背后的强大吸引力!

在电路设计与仿真领域&#xff0c;Proteus一度以其稳定性能和丰富功能赢得了众多用户的青睐。然而&#xff0c;近年来&#xff0c;越来越多的Proteus用户开始转向SmartEDA&#xff0c;这一新兴电路仿真软件正迅速崭露头角&#xff0c;成为行业内的翘楚。那么&#xff0c;究竟是…...

万界星空科技QMS质量管理介绍

产品的生产质量是企业发展之根本&#xff0c;对所有企业来说&#xff0c;建立完善质量控制体系&#xff0c;对企业生产经营以及发展竞争具有至关重要的影响&#xff0c;可以说是企业质量保证的防火墙。QMS质量管理系统对任何一家企业都具有重要意义&#xff0c;可帮助企业提高生…...

神经网络 torch.nn---nn.LSTM()

torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) LSTM — PyTorch 2.3 documentation LSTM层的作用 LSTM层:长短时记忆网络层&#xff0c;它的主要作用是对输入序列进行处理&#xff0c;对序列中的每个元素进行编码并保存它们的状态&#xff0c;以便后续的处理。 …...

Web前端JSP软件:深度解析与探索之旅

Web前端JSP软件&#xff1a;深度解析与探索之旅 在当今数字化时代&#xff0c;Web前端技术日新月异&#xff0c;JSP&#xff08;Java Server Pages&#xff09;软件作为其中的佼佼者&#xff0c;扮演着举足轻重的角色。本文将从四个方面、五个方面、六个方面和七个方面&#x…...

人生的乐趣,在于对真知的追求

子曰&#xff1a;朝闻道&#xff0c;夕死可矣&#xff01; 孔子说&#xff1a;早上听到关于世界的真理&#xff0c;哪怕晚上就die了都可以。 这句话很有力量而经常被人引用&#xff0c;表达出我们如何看待沉重的肉身和精神世界。 我们的生活目的&#xff1a;道。 —— 要了解…...

IPython大揭秘:神奇技巧让你掌握无敌编程力量!

IPython技巧 基础技巧文件操作技巧输入输出技巧魔术命令技巧调试技巧程序性能优化技巧输入输出重定向技巧魔术命令控制技巧自定义显示格式技巧多线程多进程技巧异常处理技巧数据可视化技巧自定义魔术命令技巧安装扩展包技巧Jupyter Notebook集成技巧文档显示技巧代码块执行技巧…...

逻辑卷管理器 (LVM) 简介

古老的 e5 主机目前有这些存储设备 (硬盘): 系统盘 (M.2 NVMe SSD 480GB), 数据盘 (3.5 英寸 SATA 硬盘 4TB x2). 窝决定使用 LVM 对数据盘进行管理. 逻辑卷管理器 (LVM) 可以认为是一种 (单机) 存储虚拟化 技术. 多个物理存储设备 (PV) 组成一个存储池 (VG), 然后划分虚拟分区…...

Swift开发——弱占用

自动引用计数(Automatic Reference Counting&#xff0c;ARC)&#xff0c;是Swift语言管理类的实例的方式。当创建某个类的一个新实例后&#xff0c;ARC自动为新实例分配内存空间&#xff0c;用于保存实例的类型和存储属性&#xff0c;当将该实例赋给常量、变量或其他实例的属性…...

化工电力系统RFID无线测温技术的重要性。

在现代工业体系中&#xff0c;化工电力系统的安全与效率对于整个生产链的顺畅运行至关重要。在日常工作中,由于设备制造的原因,设备受环境污染的原因、设备长期运行、严重超载运行、触点氧化、电弧冲击等原因造接触电阻增大,因此在运行时往往不断发热,温度不断上升,给设备安全运…...

Linux系统:线程互斥

Linux系统&#xff1a;线程互斥 线程互斥互斥锁 mutex互斥锁原理 常见的锁死锁自旋锁 spinlock其它锁 线程互斥 讲解线程互斥前&#xff0c;先看到一个抢票案例&#xff1a; class customer { public:int _ticket_num 0;pthread_t _tid;string _name; };int g_ticket 10000…...

【网络协议栈】TCP/IP相关知识点收集

TCP/IP知识点收集 1 TCP分段 在TCP/IP协议栈中&#xff0c;“MSS”&#xff08;Maximum Segment Size&#xff09;是一个关键参数&#xff0c;它指定了TCP协议在发送数据时可以使用的最大数据段&#xff08;segment&#xff09;的大小。这个参数是TCP连接建立时通过三次握手&…...

Java开发中的常用字段校验注解

在 Java 开发中&#xff0c;数据校验是确保应用程序的数据完整性和一致性的重要步骤。Java 提供了一系列注解来简化数据校验的过程&#xff0c;以下是一些常用的字段校验注解及其示例代码&#xff1a; NotNull NotNull 用于确保字段不为 null&#xff0c;适用于任何类型的字段…...

面试经验分享 | 24年6月某安全厂商HW面试经验

所面试的公司&#xff1a;某安全厂商 所在城市&#xff1a;安徽省 面试职位&#xff1a;蓝初 面试过程&#xff1a; 腾讯会议&#xff08;语音&#xff09; 面试过程&#xff1a;整体流程就是自我介绍加上一些问题问题balabalabala。。。由于面的是蓝队所以渗透部分不会太多…...

JSON学习

一、JSON 1.1 简介 JSON&#xff1a;JavaScript Object Notation是一种表示对象的方式 基于JavaScript语言的轻量级的数据交换格式;&#xff08;即:用来传输数据的一种格式&#xff09; 现在传输数据的方式更多是采用json的格式&#xff0c;渐渐代替了XML 1.2 JSON的数据表示 …...

LabVIEW在中国航天中的应用

​LabVIEW是一种系统设计平台及开发环境&#xff0c;由美国国家仪器公司&#xff08;NI&#xff09;开发。它在中国航天领域的应用非常广泛&#xff0c;涵盖了测试与测量、数据采集、控制系统设计等多个方面。以下是LabVIEW在中国航天中的几个主要应用实例&#xff1a; 1. 测试…...

编程思维的培养

培养编程思维是成为一名优秀程序员的重要步骤。编程思维不仅仅是写代码的能力&#xff0c;还包括解决问题的思维方式、对复杂系统的理解、代码优化的意识、团队合作的能力等。以下是一些培养编程思维的方法和建议。 1. 学习基础知识 1.1 掌握编程语言 从一门编程语言开始&am…...

Docker笔记-Debian容器内搭建ssh服务

登陆容器之后修改密码&#xff1a; passwd 密码设置完成后安装openssh-server apt-get install openssh-server 修改端口号为50022并添加配置 vim /etc/ssh/sshd_config 修改成 Port 50022 PasswordAuthentication yes PermitRootLogin yes 启动 rootlinux:~# /etc/in…...

爬虫的法律风险是什么?以及合法使用爬虫技术的建议。

爬虫的法律风险是什么&#xff1f; 网络爬虫技术&#xff0c;虽然在数据获取方面具有巨大优势&#xff0c;但其使用过程中可能引发的法律风险也不容忽视。这些风险主要包括违反数据保护法规、侵犯知识产权、构成不正当竞争等。下面将详细探讨网络爬虫的法律风险&#xff0c;并在…...

微信小程序允许相机访问相册

// 允许从相机和相册扫码 // uni.scanCode({ // success: function(res) { // console.log(条码类型&#xff1a; res.scanType); // console.log(条码内容&#xff1a; res.result); …...

AMEYA360 | 江苏润石最新发布12颗车规级模拟芯片

日前江苏润石再度新增12颗通过AEC-Q100 Grade1&#xff0c;满足MSL 1湿敏等级认证的车规级芯片。截止目前&#xff0c;润石科技总计有70颗Grade1 & MSL1的车规级芯片通过认证并进入量产。凭借卓越的产品技术指标和稳定的品质性能不仅展示了公司在车规级模拟芯片领域的技术积…...

免费做字体的网站/网页设计模板网站免费

原创 不测神灵 2020-06-09 01:44:51福彩双色球第2020047期奖号为&#xff1a;04、10、17、19、28、32 01&#xff0c;红球号码和值为110&#xff0c;首尾间距为28&#xff0c;奇偶比为2&#xff1a;4&#xff0c;大小比为4&#xff1a;2&#xff0c;012路比为0&#xff1a;4&a…...

网站设计编程有哪些/网络营销教案ppt

先来思考这样一个问题如果有两个变量需要互换其值&#xff0c;应该如何处理&#xff1f;答案非常简单&#xff1a;#include int main(int argc, char **args){int i 3;int j 5;int t;t i;i j;j t;printf("i %d\nj %d\n", i, j);return 0;}运行结果&#xff1a…...

app开发公司历程概述/北京专业seo公司

找到ecshop的includes/lib_goods.php&#xff0c;修改方法如下 以把SQL语句改一下&#xff0c;与category表关联即可将 $sql SELECT g.goods_id,g.goods_name, g.goods_name_style, g.market_price, g.shop_price AS org_price, g.promote_price, . 复制代码改为 $sql SE…...

学习java可以自己做网站吗/免费行情软件网站下载大全

使用官方的docker启用mysql56后&#xff0c;在进行汉字操作时&#xff0c;会出现Incorrect string value: &#xff0c;原因是由于官方的docker镜像&#xff0c;默认采用latin1编码。本文将阐述如何在官方docker的基础上&#xff0c;使其支持utf8编码&#xff0c;进而支持汉字的…...

b2b网站大全黄页电商/市场营销十大经典案例

/* 1008. 数组元素循环右移问题 (20)时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard一个数组A中存有N&#xff08;N>0&#xff09;个整数&#xff0c;在不允许使用另外数组的前提下&#xff0c;将每个整数循环向右移M&#xff08;M>0&#xf…...

上线了免费建网站/360推广联盟

百度为了防止垃圾站肆虐&#xff0c;已经推出了新站观察期制度。新站被发现之后不会会立即收录首页&#xff0c;其他页面也进入了百度的检索数据库&#xff0c;只是未显示而已。等观察期新站通过自然会出现。你可以在观察期过后发现很多页面的收录日期就在观察期中&#xff0c;…...