Arduino入门教程:11、直流步进驱动
飞书文档https://x509p6c8to.feishu.cn/docx/Plp4dyPpDoI6nvxrsx2cG62Qnac
一、步进电机与直流电机:
1-1、什么是直流电机?
直流电机是最常见的电机类型。直流电动机通常只有两个引线,一个正极和一个负极。如果将这两根引线直接连接到电池正负极,电机将旋转,如果切换引线,电机将以相反的方向旋转,通过改变提供给电机的电压,您可以改变电机的速度。
1-2、什么是步进电机?
步进电机是一种将电脉冲信号转换成相应角位移的电机,它可以实现更精准的位置控制。
现在想象一个打印机。打印机内有很多移动部件,包括电机。一个电机用作进纸,当墨水开始印在纸上时旋转滚轴移动纸张。此电机需要能够将纸张移动一个精确的距离,以便能够打印下一行文本或图像的下一行。
1-3、直流电机与步进电机的对比:
直流电机:
优点:价格低、控制方便
缺点:由于电刷和换向器的存在,有刷电机的结构复杂,可靠性差,故障多,维护工作量大,寿命短,换向火花易产生电磁干扰。
步进电机:
优点:低速扭矩大,控制更精准,成本相对低;
缺点:步进电机存在空载启动频率,所以步进电机可以低速正常运转,但若高于一定速度时就无法启动,并伴有尖锐的啸叫声,同时,步进电机是开环控制,控制精度和速度都没有伺服电机那么高。
二、思考?为什么Arduino芯片引脚不能直接接步进电机或直流电机?但可以直接接舵机?
这要从舵机的构造说起,控制芯片+电机组成,Arduino实际接的是控制芯片引脚,而不是电机本身。
而步进电机和直流电机内部是没有控制芯片的,如果使用Arduino直接接电机,因为Arduino芯片引脚驱动能力弱而驱动不起甚至损坏芯片,ESP32每个IO的最大电流为40mA,一般步进电机跑起来可能需要几百mA到几A。
驱动能力可以理解为引脚的可以输出的力气,如果力气过小,当然推不动电机运行。
三、如何提升驱动能力呢?
下图就是应用三极管的开关功能,使芯片IO的驱动能力提高。
上图可以简单理解为三极管开关电路,通过控制输入口的电平高低,就可以控制后端电路的开启关闭。
四、直流电机的控制?
4-1、控制转/停
#include <Arduino.h>int motorPin1 = 18;void setup() {pinMode(motorPin1, OUTPUT);
}void loop() {digitalWrite(motorPin1, HIGH);delay(2000);digitalWrite(motorPin1, LOW);delay(2000);
}
4-2、控制转速
直流电机的速度可以通过改变其输入电压来控制,使用单片机控制转速可以通过PWM控制。
PWM是一种通过发送一系列ON-OFF脉冲来调整输入电压平均值的技术。该平均电压与脉冲的宽度成正比,称为占空比。
占空比越高,施加到直流电机的平均电压就越高,从而导致电机速度增加。占空比越短,施加到直流电机的平均电压越低,导致电机速度降低。
下图显示了具有各种占空比和平均电压的PWM技术。
Arduino的PWM函数:
analogWrite(pin, value)
pin:引脚号码
value:0到255之间的PWM频率值, 0对应0%, 255对应100%
#include <Arduino.h>
int motorPin1 = 18;
int speed = 0;void setup() {pinMode(motorPin1, OUTPUT);Serial.begin(9600);Serial.println("Speed 0 to 255");
}void loop() {speed = speed + 10;if(speed >= 255)speed = 0;analogWrite(motorPin1, speed);delay(1000);
}
4-3、控制方向
前面我们都只是控制电机往一个方向转动,如果需要更换方向,就需要重新接线,那如果需要自动控制电机的正反转呢?这就需要升级下电路。
下面电路被称为H桥,是因为它使用四个晶体管连接,使示意图看起来像一个“H”。
为了控制直流电机的旋转方向,无需互换引线,可以使用称为H桥的电路。H桥是可以双向驱动电机的电子电路。H桥用于许多不同的应用中。最常见的应用之一是控制机器人中的电机。
| |
如果需要使用多个三极管,一个一个连接太麻烦了,有没有更好的方式呢?当然有,L293D、L298都是集成H桥的芯片。
| |
L293D是一款双桥驱动芯片,可同时驱动两路直流电机或一路步进电机,输出电流可达600mA,峰值输出电流可达1.2A,内部自带ESD保护,模块工作电压5V,电机的驱动电压范围为4.5V-36V。
L293D驱动直流电机电路:
注意:这里使用5V供电,如果是新版本的板卡,供电的TYPEC要接上,另外,要注意编译的工程是自己代码对应的工程
#include <Arduino.h>int motorPin1 = 18;
int motorPin2 = 19;void setup() {pinMode(motorPin1, OUTPUT);pinMode(motorPin2, OUTPUT);
}void loop() {digitalWrite(motorPin1, HIGH);digitalWrite(motorPin2, LOW);delay(2000);digitalWrite(motorPin1, LOW);digitalWrite(motorPin2, LOW);delay(2000);digitalWrite(motorPin1, LOW);digitalWrite(motorPin2, HIGH);delay(2000);digitalWrite(motorPin1, LOW);digitalWrite(motorPin2, LOW);delay(2000);
}
关于L298的使用,我们将在这里使用L298 H桥 IC。L298可以控制直流电机和步进电机的速度和方向,并可以同时控制两个电机。每个电机的额定电流为2A。
五、步进电机的控制?
5-1、28BYJ-48步进电机
| |
28BYJ-48步进电机为五线四相永磁式步进电机,
其名称含义为:
“28”为电机直径28mm,
B为步进电机,
Y表示电机为永磁式,
J表示内部自带减速箱,
48表示驱动方式为四相八拍;
- 四相:ABCD四相,4组线圈
- 八拍:线圈通电顺序(A-AB-B-BC-C-CD-D-DA-A),一拍转一个步距角。
| |
28BYJ48规格书
5-2、步进电机运动原理:
步进电机中间的转子是一个磁铁,周围线圈在通电时会形成磁场,然后把转子吸过来,如果周围线圈按照一定的顺序逐个通电断电时,转子就会被带动转起来。
所以,使用L293D、L298,按顺序驱动四组线圈就可以驱动步进电机啦:
但在这里还是给大家介绍另一款芯片,ULN2003A。
5-3、ULN2003A
ULN2003的每一路由两个三极管复合成的,可以把它理解为一个三极管,但比一个三极管的电流放大倍数大了很多,提高了电流驱动能力。
ULN2003A参数:
在单个 ULN2003 芯片中有 7 个驱动器,因此最多可以控制7 个负载。每个驱动器可以处理最大 500mA 的负载,而峰值为 600mA,最大输出电压为 50V。
ULN2003A原理:
有兴趣可以了解下,不看也不影响学习,就像你需要用笔写字,你不必知道笔内墨水和笔芯的材料、组成原理一样,你只需要知道这支笔可以写出黑色的文字,然后在这个基础上,去进行创作即可。
Input B:输入端可以是TTL 3.3V也可以是CMOS 5V电路(一般单片机直接输入就可以)。
Output C:开路输出,一般有感性负载和电阻负载。
COM:根据负载类型不同而决定,如果是感性负载,需要接感性负载的同一电源。如果是电阻负载,COM可以悬空不接。COM端的二极管为续流二极管,COM口主要提供保护电势作用,如接的是感性负载,用于抑制感性负载所产生的感应电势,COM口并不提供电源信号。
驱动逻辑:
当B输入高电平时,C为低电平(和E导通)。
当B输入低电平时,C为高阻态。
ULN2003应用:
整体看下来:引脚1-7是输入信号;引脚10-16是输出信号,引脚8接地,引脚9接VCC。
- 引脚1输入RL信号,相对应的输出引脚16控制的是一个继电器。当引脚1输入高电平,继电器开启;
- 引脚2-5输入D、C、B、A信号,相对应的输出引脚15、14、13、12作为四相来控制四相五线步进电机;
- 引脚6输入SPK信号,相对应的输出引脚11控制的是一个喇叭。当引脚6输入高电平,喇叭开启;
- 引脚7输入M0T信号,相对应的输出引脚10控制的是一个直流电机。当引脚6输入高电平,直流电机启动。
这个时候大概就能理解ULN2003的本质了:
由于单片机的引脚输出电流太低了,无法驱动大部分的设备。而ULN2003只相当于是一个开关,设备(负载)的供电是在外围电路上,而它能够通过微弱的单片机输出电流来控制外围电路的开闭。这某种程度上也可以说是,放大电流,增加驱动能力。
ULN2003A有四条线(A、B、C、D)用来控制电机的旋转,使用八拍方式来驱动电机的旋转,A-AB-B-BC-C-CD-D-DA,八拍驱动方式逻辑时序如下表所示。
步进 | A | B | C | D | 1/1减速比 | 1/64减速比 |
0 | ON | OFF | OFF | OFF | 步距角5.625° | 每步5.625°/64 |
1 | ON | ON | OFF | OFF | ||
2 | OFF | ON | OFF | OFF | ||
3 | OFF | ON | ON | OFF | ||
4 | OFF | OFF | ON | OFF | ||
5 | OFF | OFF | ON | ON | ||
6 | OFF | OFF | OFF | ON | ||
7 | ON | OFF | OFF | ON |
接线:
注意,这里用3V3供电,如果使用5V供电,供电的TYPEC接口要接上。
| |
参考代码:
#include <Arduino.h>// 电机引脚
#define PIN_MOTOR_AP 23
#define PIN_MOTOR_AM 22
#define PIN_MOTOR_BP 21
#define PIN_MOTOR_BM 19uint8_t motor_pos = 0;uint8_t motor_table[8][4] ={{1, 0, 0, 0},{1, 1, 0, 0},{0, 1, 0, 0},{0, 1, 1, 0},{0, 0, 1, 0},{0, 0, 1, 1},{0, 0, 0, 1},{1, 0, 0, 1},
};void motor_io_control(uint8_t motor_pos)
{digitalWrite(PIN_MOTOR_AP, motor_table[motor_pos][0]);digitalWrite(PIN_MOTOR_AM, motor_table[motor_pos][1]);digitalWrite(PIN_MOTOR_BP, motor_table[motor_pos][2]);digitalWrite(PIN_MOTOR_BM, motor_table[motor_pos][3]);
}void motor_io_control_type2(uint8_t motor_pos){if(motor_pos == 0){digitalWrite(PIN_MOTOR_AP, 1);digitalWrite(PIN_MOTOR_AM, 0);digitalWrite(PIN_MOTOR_BP, 0);digitalWrite(PIN_MOTOR_BM, 0);}else if(motor_pos == 1){digitalWrite(PIN_MOTOR_AP, 1);digitalWrite(PIN_MOTOR_AM, 1);digitalWrite(PIN_MOTOR_BP, 0);digitalWrite(PIN_MOTOR_BM, 0);}else if(motor_pos == 2){digitalWrite(PIN_MOTOR_AP, 0);digitalWrite(PIN_MOTOR_AM, 1);digitalWrite(PIN_MOTOR_BP, 0);digitalWrite(PIN_MOTOR_BM, 0);}else if(motor_pos == 3){digitalWrite(PIN_MOTOR_AP, 0);digitalWrite(PIN_MOTOR_AM, 1);digitalWrite(PIN_MOTOR_BP, 1);digitalWrite(PIN_MOTOR_BM, 0);}//TODO XXXXX 4 5 6 7
}/*** @brief 控制电机运行** @param steps 大于0正向运行,小于0反向运行*/
void motor_run_step(int steps)
{if (steps == 0)return;if (steps > 0){while (steps){motor_io_control(motor_pos);motor_pos++;if (motor_pos >= 8){motor_pos = 0;}delay(4);steps--;}}else{steps = abs(steps);while (steps){motor_io_control(motor_pos);if(motor_pos > 0){motor_pos --;}elsemotor_pos = 7;delay(4);steps--;}}
}void init_motor()
{pinMode(PIN_MOTOR_AP, OUTPUT);pinMode(PIN_MOTOR_AM, OUTPUT);pinMode(PIN_MOTOR_BP, OUTPUT);pinMode(PIN_MOTOR_BM, OUTPUT);digitalWrite(PIN_MOTOR_AP, 0);digitalWrite(PIN_MOTOR_AM, 0);digitalWrite(PIN_MOTOR_BP, 0);digitalWrite(PIN_MOTOR_BM, 0);
}void setup() {init_motor();
}void loop(){motor_run_step(800);delay(1000);motor_run_step(-800);delay(1000);
}