⚙️ ESP32 Mini打印机:电机控制模块
驱动步进电机,实现打印头进退纸、走纸等精确控制
基于四相八拍驱动,支持定时器中断和步进模式
📌 为什么需要电机控制?
热敏打印机需要精确控制纸张的移动:
- 进纸:将空白纸送入打印位置
- 走纸:打印过程中逐行移动纸张
- 退纸:打印完成后吐出纸张
电机控制模块就是打印机的“双腿”,必须平稳、精确、可控。
直观理解:
就像打印机的“传送带”,电机每转一步,纸张就移动一微米。
一、硬件原理简述
电机类型
本例使用四相步进电机,驱动方式为1-2相励磁(八拍模式),可实现半步控制,提高分辨率和平稳性。
驱动电路
- 使用四个GPIO直接驱动电机驱动芯片(如ULN2003、DRV8825等)
- 每个GPIO对应电机的一相:AP、AM、BP、BM
- 输出高/低电平控制电流方向
引脚定义(示例配置)
// 请根据实际硬件连接修改以下引脚号
#define PIN_MOTOR_AP 25 // A+ 相(原为23,现改为25)
#define PIN_MOTOR_AM 26 // A- 相(原为22,现改为26)
#define PIN_MOTOR_BP 27 // B+ 相(原为21,现改为27)
#define PIN_MOTOR_BM 32 // B- 相(原为19,现改为32)
💡 提示:此处引脚号仅为示例,实际使用时请根据PCB布线或开发板连接情况修改。ESP32的GPIO需避开仅输入引脚(如34~39)和已被占用的引脚。
八拍励磁表
电机旋转一圈需要特定的相序,本例使用八拍表(8个状态,每步进一个状态):
| 步进位置 | AP | AM | BP | BM | 说明 |
|---|---|---|---|---|---|
| 0 | 0 | 1 | 1 | 0 | A相通电,B相通电 |
| 1 | 0 | 0 | 1 | 0 | 仅B相通电 |
| 2 | 1 | 0 | 1 | 0 | A相通电,B相通电 |
| 3 | 1 | 0 | 0 | 0 | 仅A相通电 |
| 4 | 1 | 0 | 0 | 1 | A相通电,B相通电 |
| 5 | 0 | 0 | 0 | 1 | 仅B相通电 |
| 6 | 0 | 1 | 0 | 1 | A相通电,B相通电 |
| 7 | 0 | 1 | 0 | 0 | 仅A相通电 |
每切换一次状态,电机前进半步。循环该表即可持续旋转。
二、代码实现
以下代码实现了基于Ticker定时器的持续旋转和基于阻塞的步进控制。
1. 引脚与定时器定义
#include "Arduino.h"
#include <Ticker.h>
// 用户可根据实际硬件连接修改此处引脚号
#define PIN_MOTOR_AP 25
#define PIN_MOTOR_AM 26
#define PIN_MOTOR_BP 27
#define PIN_MOTOR_BM 32
Ticker timer_motor; // 定时器对象,用于周期性触发电机步进
2. 八拍励磁表与当前步进位置
uint8_t motor_table[8][4] = {
{0, 1, 1, 0}, // 状态0
{0, 0, 1, 0}, // 状态1
{1, 0, 1, 0}, // 状态2
{1, 0, 0, 0}, // 状态3
{1, 0, 0, 1}, // 状态4
{0, 0, 0, 1}, // 状态5
{0, 1, 0, 1}, // 状态6
{0, 1, 0, 0} // 状态7
};
uint8_t motor_pos = 0; // 当前步进位置索引(0~7)
3. 定时器回调函数(持续旋转)
void timer_motor_callbackfun() {
// 根据当前步进位置输出相序
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]);
// 移动到下一步
motor_pos++;
if (motor_pos >= 8) {
motor_pos = 0; // 循环
}
}
4. 启动与停止电机(定时器模式)
void motor_start() {
if (!timer_motor.active()) {
timer_motor.attach_ms(2, timer_motor_callbackfun); // 每2ms触发一次,约500Hz步进频率
}
}
void motor_stop() {
timer_motor.detach(); // 停止定时器
// 所有相断电,防止电机发热
digitalWrite(PIN_MOTOR_AP, 0);
digitalWrite(PIN_MOTOR_AM, 0);
digitalWrite(PIN_MOTOR_BP, 0);
digitalWrite(PIN_MOTOR_BM, 0);
}
直观理解:
定时器就像一位严格的指挥官,每隔2ms下令电机前进一步。motor_start 就是“开始行军”,motor_stop 是“原地立正,熄灯”。
5. 步进指定步数(阻塞模式)
void motor_run_step(uint32_t steps) {
while (steps--) {
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]);
motor_pos++;
if (motor_pos >= 8) {
motor_pos = 0;
}
delay(2); // 每步延时2ms,与定时器频率一致
}
}
核心作用:
用于精确控制打印头移动指定的步数(如进纸N步),完成后自动停止。
注意:
此函数使用 delay(),会阻塞其他任务,适合短距离移动。长距离移动建议使用定时器模式。
6. 初始化函数
void motor_init() {
pinMode(PIN_MOTOR_AP, OUTPUT);
pinMode(PIN_MOTOR_AM, OUTPUT);
pinMode(PIN_MOTOR_BP, OUTPUT);
pinMode(PIN_MOTOR_BM, OUTPUT);
// 初始全部置低,确保电机静止
digitalWrite(PIN_MOTOR_AP, LOW);
digitalWrite(PIN_MOTOR_AM, LOW);
digitalWrite(PIN_MOTOR_BP, LOW);
digitalWrite(PIN_MOTOR_BM, LOW);
}
三、代码使用示例
void setup() {
Serial.begin(115200);
motor_init();
Serial.println("电机模块初始化完成(引脚已更新)");
}
void loop() {
// 示例:启动电机持续旋转
motor_start();
delay(5000); // 旋转5秒
motor_stop();
delay(1000);
// 示例:步进200步(约多少圈?取决于电机步距角)
motor_run_step(200);
delay(2000);
}
四、代码分析
1. 优点
- 双模式支持:定时器模式用于持续旋转,步进模式用于精确控制,灵活应对不同场景。
- 相序表清晰:八拍励磁表用二维数组表示,易于修改和调试。
- 定时器非阻塞:定时器模式下,电机旋转不占用主循环,可并行处理其他任务。
- 停止时断电:
motor_stop将所有相置低,避免电机发热和功耗浪费。
2. 潜在问题
- 步进模式阻塞:
motor_run_step中使用delay(2),长时间运行会阻塞系统,不适合与蓝牙、WiFi等实时任务共存。 - 无加减速控制:突然启动/停止可能导致电机抖动或失步,尤其高速时。
- 步进频率固定:定时器周期固定为2ms(500Hz),无法动态调整速度。
- 无电流限制:直接驱动可能超过GPIO驱动能力,需外接驱动芯片。
3. 引脚修改说明
- 原引脚(23、22、21、19)已替换为 25、26、27、32,仅作为示例。
- 用户在实际硬件上需根据原理图或PCB设计修改这些宏定义,确保引脚未被其他外设占用(如ADC、触摸、JTAG等)。
- ESP32的引脚GPIO34~39只能用作输入,不能用于输出,因此需避开。
五、使用总结
| 关键词/技巧 | 一句话记忆 |
|---|---|
Ticker | 硬件定时器,精准触发,不占CPU |
| 八拍励磁表 | 4×8数组,相序全记录,电机旋转靠它 |
motor_start/stop | 定时器模式,持续旋转如传送带 |
motor_run_step | 步进模式,指哪打哪,精确移动 |
| 断电停止 | 停止时所有相拉低,省电又安全 |
| 引脚可配置 | 宏定义统一管理,硬件改动只需改一处 |
六、写在最后
电机控制模块是打印机的“肌肉”,负责纸张的精准移动。通过本文,就学会了:
- ✅ 四相步进电机的八拍驱动原理
- ✅ 使用ESP32的Ticker定时器实现非阻塞旋转
- ✅ 实现精确步进的阻塞函数
- ✅ 完整的代码结构与使用方法
- ✅ 如何灵活配置引脚以适应不同硬件