Động cơ bước Arduino: đấu driver A4988, DRV8825, TMC2209, chỉnh Vref và lập trình AccelStepper
Điều khiển động cơ bước Arduino là nền tảng của máy in 3D, máy khắc laser mini, CNC để bàn hay bàn trượt camera. Arduino chỉ phát chuỗi xung STEP và mức logic DIR; phần công suất, giới hạn dòng và chia vi bước do driver đảm nhận. Vì vậy động cơ chạy êm hay rung giật, mạnh hay mất bước phụ thuộc chủ yếu vào việc chọn driver, chỉnh Vref và cách viết chương trình phát xung. Nội dung dưới đây đi từ đấu nối, chỉnh dòng, lập trình AccelStepper, homing, GRBL đến 28BYJ-48, ESP32 và cách xử lý lỗi.
Nội dung
- 1. Hệ động cơ bước Arduino gồm những gì
- 2. Chọn driver cho động cơ bước Arduino
- 3. Đấu nối Arduino với driver: STEP, DIR, EN, MS1–MS3
- 4. Chỉnh Vref: đặt dòng cho từng driver
- 5. Lập trình động cơ bước Arduino với AccelStepper
- 6. Tính số bước trên mm cho vít me T8 và dây đai GT2
- 7. Homing bằng công tắc hành trình
- 8. CNC Shield V3 và GRBL
- 9. Động cơ 28BYJ-48 với mạch ULN2003
- 10. ESP32 điều khiển động cơ bước
- 11. Tiếng ồn, StealthChop và SpreadCycle
- 12. Lỗi thường gặp khi chạy động cơ bước Arduino
- 13. Câu hỏi thường gặp về động cơ bước Arduino
- 14. Kết luận
1. Hệ động cơ bước Arduino gồm những gì
Một hệ gồm bốn khối: bộ điều khiển (Arduino Uno, Nano, Mega, ESP32) phát xung và đọc công tắc; driver (A4988, DRV8825, TMC2208, TMC2209) đóng cắt cầu H, giới hạn dòng, chia vi bước; động cơ bước lưỡng cực 2 pha 1,8°; nguồn 12–24 V DC cho driver và 5 V cho Arduino.
Quy tắc cốt lõi: mỗi cạnh lên của xung STEP làm động cơ tiến một vi bước. Động cơ 1,8° có 200 bước đủ mỗi vòng; ở vi bước 1/16, một vòng cần 3.200 xung. Tần số xung quyết định tốc độ, tổng số xung quyết định quãng đường, mức DIR quyết định chiều quay.
Động cơ bước hai pha 1,8° như hình dưới là loại thường ghép với Arduino. Loại 4 dây đấu thẳng vào driver; loại 6 dây dùng như lưỡng cực bằng cách bỏ trống hai dây giữa cuộn.

Để tìm hai dây cùng cuộn, đo điện trở: hai dây thông nhau (vài ohm) là một cuộn, cắm vào 1A–1B; cặp còn lại vào 2A–2B. Đảo hai dây trong cùng một cuộn chỉ làm đổi chiều quay.
2. Chọn driver cho động cơ bước Arduino
Bốn driver dạng module StepStick dùng chung kiểu chân 16 pin, thay cho nhau được trên cùng board.
| Driver | Điện áp động cơ | Dòng dùng thực tế | Vi bước bằng chân | Điểm nổi bật |
| A4988 | 8–35 V | ~1 A/pha không tản; tối đa 2 A khi làm mát tốt | 1/16 | Rẻ, dễ dùng, kêu rõ ở tốc độ thấp |
| DRV8825 | 8,2–45 V | ~1,5 A/pha không tản; tối đa 2,2 A | 1/32 | Chịu điện áp cao hơn |
| TMC2208 | 5,5–35 V | ~0,85 A RMS với tản nhỏ | 1/2 đến 1/16, nội suy 1/256 | Rất êm nhờ StealthChop |
| TMC2209 | 4,75–29 V | ~1 A RMS với tản nhỏ; 2 A RMS, 2,8 A đỉnh khi làm mát tốt | 1/8 đến 1/64, nội suy 1/256 | Êm, có UART, phát hiện kẹt StallGuard |
Dòng "2 A" của A4988 chỉ đạt khi có tản nhiệt và quạt; module trần thường quá nhiệt quanh 1 A. TMC2209 chịu điện áp thấp hơn hai loại kia, dùng 24 V được nhưng không dùng 36 V.
a. A4988 và DRV8825: bảng vi bước MS1–MS3 (M0–M2)
| MS1/M0 | MS2/M1 | MS3/M2 | A4988 | DRV8825 |
| L | L | L | Đủ bước | Đủ bước |
| H | L | L | 1/2 | 1/2 |
| L | H | L | 1/4 | 1/4 |
| H | H | L | 1/8 | 1/8 |
| L | L | H | Không dùng | 1/16 |
| H | H | H | 1/16 | 1/32 |
Các chân có điện trở kéo xuống bên trong, bỏ trống là chạy đủ bước. A4988 cần xung STEP mức cao và mức thấp tối thiểu 1 µs mỗi phía; DRV8825 cần 1,9 µs, nên trong chương trình đặt 2–3 µs cho chắc. Chân SLEEP của DRV8825 bị kéo xuống bên trong, phải nối lên mức cao thì driver mới chạy.
b. TMC2208 và TMC2209: bảng vi bước MS1–MS2
| MS2 | MS1 | TMC2208 | TMC2209 |
| GND | GND | 1/8 | 1/8 |
| GND | VIO | 1/2 | 1/32 |
| VIO | GND | 1/4 | 1/64 |
| VIO | VIO | 1/16 | 1/16 |
Cả hai nội suy lên 1/256 bên trong: dù Arduino chỉ phát xung 1/16, dòng trong cuộn vẫn thay đổi mịn như 1/256, nên êm hơn hẳn với cùng tần số xung. Trên TMC2209, MS1/MS2 còn đặt địa chỉ UART khi nối nhiều driver chung đường truyền.
3. Đấu nối Arduino với driver: STEP, DIR, EN, MS1–MS3
Bảng dưới dùng chân của CNC Shield V3 cho trục X, nhờ đó cùng một chương trình chạy được trên breadboard lẫn trên shield.
| Chân driver | Nối tới | Ghi chú |
| VMOT, GND | Nguồn động cơ 12–24 V | Tụ hóa 100 µF sát chân, đúng cực |
| 1A, 1B / 2A, 2B | Cuộn 1 / cuộn 2 | Mỗi cặp là hai dây thông nhau |
| VDD, GND | 5V và GND Arduino (3,3V nếu là ESP32) | GND logic chung với GND nguồn |
| STEP / DIR | D2 / D5 | Cạnh lên là một vi bước; mức DIR đổi chiều |
| EN | D8 | Tích cực mức thấp: LOW là chạy, HIGH là thả trục |
| MS1, MS2, MS3 | 5V hoặc bỏ trống | Theo bảng vi bước |
| RESET, SLEEP | Nối tắt với nhau | RESET của A4988 thả nổi, bắt buộc nối |
Tụ 100 µF không phải tùy chọn. Module chỉ có tụ gốm ESR thấp; khi cắm nguồn, điện cảm dây nguồn cộng tụ gốm tạo gai điện áp có thể vượt 35 V, đủ làm chết A4988 dù nguồn chỉ 12 V. Cần tối thiểu 47 µF điện phân sát VMOT–GND; thực tế dùng 100 µF, điện áp định mức tối thiểu 1,5 lần điện áp nguồn (35 V cho nguồn 12 V, 50 V cho nguồn 24 V). Vai trò của điện áp nguồn với tốc độ và cách chọn nguồn được phân tích trong bài động cơ bước 24V.
Không rút cắm dây động cơ khi driver đang có điện. Ngắt mạch cuộn cảm đang có dòng tạo xung điện áp lớn trên chân ra cầu H, nguyên nhân phổ biến nhất khiến driver "chết oan".
Thứ tự cấp nguồn với TMC: cấp nguồn động cơ VM trước rồi mới cấp logic VIO, khi tắt thì ngược lại; không bật EN khi VM chưa có điện.
Video dưới đây ghi lại quá trình đấu dây pha, nguồn và tín hiệu điều khiển vào driver rồi chạy thử thực tế một động cơ bước, giúp hình dung bước đấu nối trước khi nạp code từ Arduino.
4. Chỉnh Vref: đặt dòng cho từng driver
Vref là điện áp trên con trượt biến trở của module. Driver so sánh dòng qua điện trở cảm biến Rs với Vref để ngắt cầu H khi dòng chạm ngưỡng. Vref thấp, động cơ yếu, mất vi bước; Vref cao, động cơ và driver nóng, driver tự ngắt theo chu kỳ.
| Driver | Công thức | Vref cho dòng 1 A |
| A4988, Rs = 0,068 Ω (Pololu đời mới) | Vref = 8 × I × Rs = 0,544 × I | 0,54 V |
| A4988, Rs = 0,05 Ω (đời cũ) | Vref = 0,4 × I | 0,40 V |
| A4988 bản sao, Rs = 0,1 Ω (R100) | Vref = 0,8 × I | 0,80 V |
| A4988 bản sao, Rs = 0,2 Ω (R200) | Vref = 1,6 × I | 1,60 V |
| DRV8825, Rs = 0,1 Ω | Vref = I / 2 | 0,50 V |
| TMC2209, Rs = 0,11 Ω | Irms ≈ 0,71 × Vref | 1,41 V cho 1 A RMS |
Với A4988, phải đọc mã trên hai điện trở dán cạnh chân động cơ trước khi tính, vì module trên thị trường dùng nhiều giá trị Rs. Với TMC2208, hệ số tùy nhà sản xuất module; IC này có định mức khoảng 1,4 A RMS, thấp hơn TMC2209.
Dòng định mức động cơ và dòng đặt. A4988 và DRV8825 đặt dòng đỉnh của sóng sin vi bước; ở chế độ đủ bước mỗi cuộn chỉ nhận khoảng 70% dòng đặt. Nên đặt dòng đỉnh bằng 70–90% dòng định mức động cơ, chạy thử rồi điều chỉnh. TMC dùng giá trị RMS: động cơ 1,5 A thì Irms tối đa khoảng 1,5 / 1,41 ≈ 1,06 A; nên bắt đầu từ khoảng một nửa dòng định mức, tăng từng 0,1 A khi thấy mất bước.
Ví dụ: động cơ NEMA17 1,7 A, đặt 80% tức 1,36 A. A4988 bản sao R100: Vref = 0,8 × 1,36 ≈ 1,09 V. DRV8825: Vref = 1,36 / 2 = 0,68 V. TMC2209 đặt 0,9 A RMS: Vref ≈ 1,41 × 0,9 ≈ 1,27 V.
Các bước đo Vref:
1. Cấp VDD 5 V (Arduino cắm USB) và nguồn VMOT. Vref của A4988 phụ thuộc VDD, nên đo đúng ở điện áp logic sẽ dùng.
2. Đồng hồ thang 2 V DC, que đen vào GND, que đỏ chạm thân biến trở (hoặc điểm VREF ở mặt dưới DRV8825).
3. Xoay bằng tua vít nhựa, gốm; nếu dùng tua vít kim loại thì kẹp que đỏ vào thân tua vít và tránh chạm chân bên cạnh.
4. Xoay từ từ, thường dưới nửa vòng là hết dải; nhiều biến trở không có điểm chặn.
5. Chạy thử 10–15 phút theo chu trình thực tế. Driver tự ngắt thì cần tản nhiệt, quạt hoặc giảm dòng.
5. Lập trình động cơ bước Arduino với AccelStepper
a. Chạy thử không cần thư viện
Trước khi viết chương trình phức tạp, kiểm tra đấu nối bằng code thuần. Động cơ quay đều hai chiều là phần cứng đã đúng.
const uint8_t STEP_PIN = 2;
const uint8_t DIR_PIN = 5;
const uint8_t EN_PIN = 8;
const long BUOC_MOI_VONG = 200L * 16; // 1,8 độ, vi bước 1/16
void quay(long soBuoc, bool thuan, unsigned int nuaChuKy_us) {
digitalWrite(DIR_PIN, thuan ? HIGH : LOW);
delayMicroseconds(5); // chờ DIR ổn định trước xung STEP
for (long i = 0; i < soBuoc; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(nuaChuKy_us);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(nuaChuKy_us);
}
}
void setup() {
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, LOW); // LOW = bật driver
}
void loop() {
quay(BUOC_MOI_VONG, true, 300); // ~1.667 xung/giây, khoảng 31 vòng/phút
delay(1000);
quay(BUOC_MOI_VONG, false, 300);
delay(1000);
}Code này không có tăng tốc, nên chỉ dùng ở tốc độ thấp; đặt nhanh hơn, động cơ sẽ rung tại chỗ. Thư viện Stepper.h có sẵn trong Arduino IDE được viết để đóng cắt trực tiếp cuộn dây qua cầu H, không hợp với driver STEP/DIR; trường hợp dùng cầu H được trình bày trong bài động cơ bước L298N.
b. AccelStepper: tăng giảm tốc và chạy không chặn
AccelStepper (cài trong Library Manager) tạo đường tăng tốc hình thang: tốc độ tăng dần đến setMaxSpeed() theo setAcceleration(), rồi giảm dần để dừng đúng đích.
| Hàm | Tác dụng |
| setMaxSpeed(), setAcceleration() | Tốc độ tối đa (bước/giây, mặc định chỉ 1) và gia tốc (bước/giây²) |
| moveTo() / move() | Đặt đích tuyệt đối / tương đối |
| run() | Phát tối đa một bước mỗi lần gọi, có tăng giảm tốc; phải gọi liên tục |
| runToPosition() | Chạy tới đích rồi mới thoát, chặn chương trình |
| distanceToGo() | Số bước còn lại tới đích |
| setCurrentPosition(n) | Gán vị trí hiện tại là n, đồng thời đặt tốc độ về 0 |
Chương trình sau chạy qua lại 2 vòng mà không dùng delay(), nên vẫn đọc được nút nhấn, cảm biến trong loop:
#include <AccelStepper.h>
const uint8_t STEP_PIN = 2;
const uint8_t DIR_PIN = 5;
const uint8_t EN_PIN = 8;
const long BUOC_MOI_VONG = 200L * 16;
AccelStepper motor(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
void setup() {
motor.setEnablePin(EN_PIN);
motor.setPinsInverted(false, false, true); // EN tích cực mức thấp
motor.enableOutputs();
motor.setMinPulseWidth(3); // µs, đủ cho cả DRV8825
motor.setMaxSpeed(3000); // bước/giây
motor.setAcceleration(4000); // bước/giây²
motor.moveTo(2 * BUOC_MOI_VONG);
}
void loop() {
if (motor.distanceToGo() == 0) {
motor.moveTo(-motor.currentPosition()); // đảo đích: +2 vòng <-> -2 vòng
}
motor.run();
}Giới hạn tốc độ. Trên Arduino Uno 16 MHz, AccelStepper phát tin cậy khoảng 4.000 bước/giây. Loop có Serial.print(), analogRead() hay phép tính số thực làm run() không được gọi kịp, động cơ chạy chậm hơn đặt hoặc "lục cục". Muốn nhanh hơn: giảm vi bước (1/8 cho gấp đôi tốc độ với cùng tần số xung), dùng FastAccelStepper phát xung bằng timer phần cứng (khoảng 50.000 bước/giây trên ATmega328), hoặc chuyển sang ESP32.
Chọn gia tốc: bắt đầu bằng 1–2 lần tốc độ tối đa (mất 0,5–1 giây để lên tốc), tăng dần đến khi mất bước rồi lùi lại khoảng 30%.
6. Tính số bước trên mm cho vít me T8 và dây đai GT2
Số bước/mm = (200 × vi bước) / quãng đường mỗi vòng (mm).
Với vít me, quãng đường mỗi vòng là bước tiến (lead) = bước ren × số đầu mối. Vít me T8 của máy in 3D phổ biến là loại 4 đầu mối, bước ren 2 mm, lead 8 mm; loại T8 một đầu mối lead chỉ 2 mm. Nên đếm số đầu ren hoặc quay tay một vòng đo quãng đai ốc đi được, vì nhầm hai loại làm sai số bước tới 4 lần. Với dây đai GT2 (bước răng 2 mm), puly 20 răng đi 40 mm mỗi vòng.
| Cơ cấu | Quãng đường/vòng | Vi bước 1/8 | Vi bước 1/16 | Vi bước 1/32 |
| Vít me T8, 4 đầu mối | 8 mm | 200 | 400 | 800 |
| Vít me T8, 1 đầu mối | 2 mm | 800 | 1.600 | 3.200 |
| Đai GT2 + puly 20 răng | 40 mm | 40 | 80 | 160 |
| Đai GT2 + puly 16 răng | 32 mm | 50 | 100 | 200 |
Kiểm tra tốc độ đạt được: tốc độ tối đa (mm/s) = tần số xung tối đa / số bước/mm. Với Uno và AccelStepper khoảng 4.000 bước/giây, trục đai GT2 20 răng ở 1/16 đạt 50 mm/s; trục vít me T8 lead 8 ở 1/16 chỉ đạt 10 mm/s (75 vòng/phút). Cần nhanh hơn thì giảm vi bước hoặc dùng GRBL, vốn phát xung tới khoảng 30 kHz trên cùng con chip.
Hiệu chỉnh: ra lệnh chạy 100 mm, đo quãng thực tế, rồi tính số bước/mm mới = số cũ × 100 / quãng đo được. Sai lệch vài phần trăm với dây đai thường do độ căng đai; sai đúng 2 hay 4 lần là do đặt sai vi bước hoặc nhầm vít me.
7. Homing bằng công tắc hành trình
Động cơ bước chạy vòng hở, khi bật nguồn Arduino không biết trục đang ở đâu. Homing là chạy trục về công tắc cố định để lấy gốc tọa độ, gồm ba pha: chạy nhanh tới công tắc, lùi ra vài mm, tiến chậm lại để chạm lần hai chính xác hơn.
Đấu công tắc: công tắc thường mở (NO) một đầu vào D9, đầu kia về GND, khai báo INPUT_PULLUP; chạm thì đọc LOW. Công tắc thường đóng (NC) cho logic ngược lại nhưng an toàn hơn: đứt dây được hiểu là "đã chạm" nên máy dừng thay vì đâm vào đầu hành trình. Dây công tắc dài đi cạnh dây động cơ dễ nhiễu; nên dùng dây xoắn đôi hoặc có lưới chống nhiễu và thêm tụ 100 nF từ chân tín hiệu xuống GND.
#include <AccelStepper.h>
const uint8_t STEP_PIN = 2, DIR_PIN = 5, EN_PIN = 8;
const uint8_t LIMIT_PIN = 9; // X- trên CNC Shield V3
const float BUOC_MOI_MM = 80.0; // đai GT2, puly 20 răng, 1/16
AccelStepper motor(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
bool cham() { return digitalRead(LIMIT_PIN) == LOW; }
bool homing() {
motor.setMaxSpeed(40 * BUOC_MOI_MM); // pha 1: nhanh, tối đa 400 mm
motor.setAcceleration(400 * BUOC_MOI_MM);
motor.move(-(long)(400 * BUOC_MOI_MM));
while (!cham() && motor.distanceToGo() != 0) motor.run();
if (!cham()) return false; // không gặp công tắc: lỗi
motor.setCurrentPosition(0);
motor.runToNewPosition((long)(3 * BUOC_MOI_MM)); // pha 2: lùi 3 mm
motor.setMaxSpeed(4 * BUOC_MOI_MM); // pha 3: tiến chậm
motor.move(-(long)(6 * BUOC_MOI_MM));
while (!cham() && motor.distanceToGo() != 0) motor.run();
if (!cham()) return false;
motor.setCurrentPosition(0); // gốc X = 0
motor.setMaxSpeed(50 * BUOC_MOI_MM);
return true;
}
void setup() {
pinMode(LIMIT_PIN, INPUT_PULLUP);
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, LOW);
motor.setMinPulseWidth(3);
if (homing()) motor.runToNewPosition((long)(100 * BUOC_MOI_MM)); // tới X = 100 mm
else digitalWrite(EN_PIN, HIGH); // lỗi: thả động cơ
}
void loop() {
}Vòng while kèm điều kiện distanceToGo() để chương trình không treo khi công tắc hỏng; pha 3 chạy chậm vì setCurrentPosition(0) dừng tức thời, ở tốc độ cao dễ trượt bước.
8. CNC Shield V3 và GRBL
Khi cần nội suy nhiều trục theo G-code, GRBL là firmware mã nguồn mở nạp vào Arduino Uno, nhận G-code qua USB và phát xung đồng bộ cho 3 trục tới khoảng 30 kHz. CNC Shield V3 cắm thẳng lên Uno, có 4 khe driver (X, Y, Z và A nhân bản từ một trục), cổng nguồn động cơ 12–36 V và hàng chân công tắc hành trình.
| Chức năng (GRBL 1.1) | Chân Uno |
| STEP X / Y / Z | D2 / D3 / D4 |
| DIR X / Y / Z | D5 / D6 / D7 |
| EN chung | D8 |
| Công tắc hành trình X / Y / Z | D9 / D10 / D12 |
| PWM spindle hoặc laser | D11 |
Lỗi trục Z: từ GRBL 1.1, D11 dành cho PWM spindle/laser nên công tắc Z chuyển sang D12. Nhưng trên CNC Shield V3, chân ghi "Z+/Z-" nối vào D11, còn chân "SpnEn" nối vào D12. Vì vậy công tắc Z phải cắm vào vị trí "SpnEn", dây PWM laser cắm vào "Z+/Z-". Cắm theo nhãn in trên board thì công tắc Z không tác dụng và laser không chỉnh được công suất.
Vi bước bằng jumper: dưới mỗi khe driver có 3 cặp chân MS1–MS3. Không jumper là đủ bước; cắm cả ba là 1/16 với A4988 hoặc 1/32 với DRV8825. Với TMC2209, cắm MS1 và MS2 để có 1/16.
Thông số GRBL cần đặt (gõ trong phần mềm gửi G-code như Universal G-code Sender, Candle, LaserGRBL):
| Lệnh | Ý nghĩa | Ví dụ |
| $100, $101, $102 | Số bước/mm trục X, Y, Z | 80, 80, 400 |
| $110 – $112 | Tốc độ tối đa (mm/phút) | 5000, 5000, 600 |
| $120 – $122 | Gia tốc (mm/s²) | 500, 500, 50 |
| $130 – $132 | Hành trình tối đa (mm) | 300, 200, 60 |
| $1 | Thời gian giữ dòng sau khi dừng (ms); 255 là luôn giữ | 255 |
| $5 | Đảo mức công tắc hành trình (NC thì đặt 1) | 0 |
| $21, $22 | Bật hard limit, bật homing | 1, 1 |
Đặt $1 = 255 cho trục Z và trục chịu trọng lực để trục không tự trôi khi GRBL thả động cơ sau mỗi lệnh. Để nạp GRBL, chép thư mục grbl vào thư mục libraries của Arduino IDE, mở ví dụ grblUpload và nạp cho Uno; chỉnh Vref từng driver trước khi chạy lệnh di chuyển.
9. Động cơ 28BYJ-48 với mạch ULN2003
28BYJ-48 là động cơ bước đơn cực 5 dây có hộp số nhựa, đi kèm mạch ULN2003, dùng để học lập trình, xoay rèm, mô hình. Hình dưới là cách nối điển hình: bốn chân IN1–IN4 của ULN2003 nối Arduino Uno, động cơ cắm vào giắc trắng trên mạch.

Bản 5 V có điện trở mỗi pha khoảng 50 Ω, mỗi cuộn kéo khoảng 100 mA. Động cơ có 64 nửa bước mỗi vòng trước hộp số; tỉ số hộp số danh nghĩa 1/64 nhưng thực tế xấp xỉ 1/63,68. Tốc độ thực tế chỉ khoảng 10–15 vòng/phút. ULN2003 chỉ là dãy transistor Darlington đóng cắt từng nửa cuộn, không giới hạn dòng, không có vi bước.
#include <AccelStepper.h>
// IN1..IN4 của ULN2003 nối D8, D9, D10, D11.
// Thứ tự khai báo phải là IN1, IN3, IN2, IN4 -> 8, 10, 9, 11
AccelStepper motor(AccelStepper::HALF4WIRE, 8, 10, 9, 11);
const long BUOC_MOI_VONG = 4096; // nửa bước, gần đúng
void setup() {
motor.setMaxSpeed(800); // ~11,7 vòng/phút
motor.setAcceleration(400);
motor.moveTo(BUOC_MOI_VONG);
}
void loop() {
if (motor.distanceToGo() == 0) {
motor.disableOutputs(); // ngắt cuộn dây cho đỡ nóng
delay(1000);
motor.enableOutputs();
motor.moveTo(motor.currentPosition() == 0 ? BUOC_MOI_VONG : 0);
}
motor.run();
}Khai báo chân theo thứ tự 8, 9, 10, 11 là lỗi phổ biến nhất: động cơ chỉ rung, kêu tạch tạch hoặc quay yếu một chiều. disableOutputs() khi đứng yên giúp động cơ không nóng, vì hộp số tỉ số cao đủ giữ trục với tải nhẹ. Khi chạy nhiều động cơ, cấp 5 V riêng cho ULN2003 và nối chung GND với Arduino. Nếu cần kéo tải lớn hơn mà chỉ quay liên tục, một động cơ giảm tốc mini sẽ khỏe và bền hơn nhiều.
10. ESP32 điều khiển động cơ bước
ESP32 chạy 240 MHz, có Wi-Fi, Bluetooth, hợp cho bàn trượt điều khiển qua điện thoại, rèm tự động; driver nhận trực tiếp mức 3,3 V.
Chọn chân GPIO: tránh GPIO 0, 2, 12, 15 (chân strapping, có thể làm ESP32 không khởi động khi bị driver kéo mức); GPIO 34–39 chỉ là ngõ vào; GPIO 6–11 nối bộ nhớ flash.
AccelStepper vẫn chạy trên ESP32, nhưng khi Wi-Fi hoạt động, xung có thể bị giật. FastAccelStepper phát xung bằng khối phần cứng MCPWM/PCNT hoặc RMT, đạt khoảng 200.000 bước/giây và không phụ thuộc tốc độ loop:
#include <FastAccelStepper.h>
const int STEP_PIN = 18, DIR_PIN = 19, EN_PIN = 21;
FastAccelStepperEngine engine;
FastAccelStepper *motor = nullptr;
void setup() {
engine.init();
motor = engine.stepperConnectToPin(STEP_PIN);
if (motor) {
motor->setDirectionPin(DIR_PIN);
motor->setEnablePin(EN_PIN); // mặc định EN tích cực mức thấp
motor->setAutoEnable(true); // tự bật khi chạy, tự thả khi dừng
motor->setSpeedInHz(20000); // bước/giây
motor->setAcceleration(40000); // bước/giây²
motor->moveTo(32000);
}
}
void loop() {
if (motor && !motor->isRunning()) {
delay(500);
motor->moveTo(motor->getCurrentPosition() == 0 ? 32000 : 0);
}
}Với trục đứng hoặc trục chịu lực đẩy, bỏ setAutoEnable(true) để động cơ luôn giữ vị trí.
11. Tiếng ồn, StealthChop và SpreadCycle
A4988 và DRV8825 băm dòng cố định, sinh tiếng rít và tiếng "hát" theo tốc độ, rõ nhất ở tốc độ thấp. TMC2208/TMC2209 có hai chế độ.
StealthChop gần như không ồn ở tốc độ thấp và trung bình nhưng mô-men giảm ở tốc độ cao, hợp trục X/Y máy in 3D, bàn trượt camera. SpreadCycle khỏe và cứng hơn ở tốc độ cao nhưng ồn hơn, hợp bộ đùn nhựa, trục tải nặng, CNC.
Trên TMC2209, chân SPREAD (một số module là jumper hoặc điểm hàn) để GND là StealthChop, nối VIO là SpreadCycle. TMC2208 mặc định StealthChop, muốn SpreadCycle phải cấu hình qua UART. UART không bắt buộc nhưng cho phép đặt dòng bằng phần mềm (thư viện TMCStepper), vi bước tới 1/256, tự chuyển chế độ theo tốc độ và đọc cờ quá nhiệt; chân PDN_UART là đường một dây, nối thẳng vào RX và nối TX qua điện trở 1 kΩ.
Với A4988, DRV8825: tăng vi bước lên 1/16 hoặc 1/32, quét tốc độ để tìm dải cộng hưởng rồi đặt tốc độ làm việc tránh xa, bắt động cơ qua đệm cao su giảm chấn, không đặt dòng cao hơn cần thiết. Nếu StealthChop của TMC2209 mất bước khi tăng tốc mạnh, giảm gia tốc, tăng nhẹ dòng hoặc chuyển sang SpreadCycle ở tốc độ cao.
12. Lỗi thường gặp khi chạy động cơ bước Arduino
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
| Chỉ rung, không quay | Sai cặp cuộn dây; khởi động quá nhanh, không có gia tốc; Vref quá thấp | Đo lại cặp dây; giảm setMaxSpeed, thêm gia tốc; tăng Vref |
| Không có lực giữ, quay tay tự do | EN mức cao; RESET/SLEEP thả nổi; chưa có VMOT | Kéo EN xuống LOW; nối tắt RESET–SLEEP; đo VMOT |
| Chỉ quay một chiều | DIR chưa nối hoặc sai chân; đổi DIR sát xung STEP | Kiểm tra DIR; chờ vài µs sau khi đổi DIR |
| Mất bước khi chạy nhanh | Gia tốc quá lớn; tốc độ vượt vùng mô-men; nguồn thấp; loop chậm | Giảm gia tốc, giảm vi bước, bỏ Serial.print trong loop |
| Sai vị trí dần | Nhiễu dây STEP; puly, khớp nối lỏng; driver quá nhiệt ngắt từng lúc | Dây tín hiệu ngắn, đi riêng; siết vít puly; tản nhiệt, quạt |
| Driver nóng, động cơ khựng theo chu kỳ | Driver quá nhiệt tự ngắt rồi bật lại | Giảm Vref; tản nhiệt và quạt |
| Driver chết ngay khi cắm nguồn | Thiếu tụ VMOT; cắm ngược driver trên shield; rút cắm động cơ khi có điện | Thêm tụ 100 µF; chân EN driver trùng chân EN trên shield; tắt nguồn trước khi thao tác |
Nếu đã xử lý hết mà vẫn mất bước dưới tải, tải đã vượt khả năng của động cơ ở tốc độ cần. Có thể thêm hộp giảm tốc để động cơ làm việc ở vùng mô-men cao, hoặc chuyển sang motor servo có encoder phản hồi, tự bù sai lệch và không mất bước.
13. Câu hỏi thường gặp về động cơ bước Arduino
Arduino Uno điều khiển được tối đa bao nhiêu động cơ bước?
Về số chân, 6–8 driver STEP/DIR; nhưng giới hạn thực sự là tốc độ phát xung. AccelStepper đạt khoảng 4.000 bước/giây tổng cộng trên Uno, chia cho nhiều động cơ thì mỗi động cơ còn ít hơn. Cần 4–6 động cơ độc lập tốc độ cao thì nên dùng Arduino Mega, ESP32 hoặc board 32 bit.
Driver A4988 có bắt buộc phải gắn tụ 100 µF không?
Có, gần như bắt buộc. Thiếu tụ hóa sát chân VMOT, gai điện áp lúc cắm nguồn có thể vượt 35 V và phá hỏng driver. CNC Shield V3 đã có sẵn tụ ở cổng nguồn; trên breadboard phải tự lắp.
Vì sao động cơ bước nối Arduino chỉ rung mà không quay?
Thường do sai cặp cuộn dây, khởi động quá nhanh không có gia tốc, hoặc Vref quá thấp. Đo lại cặp dây, chạy thử code không thư viện ở tốc độ thấp rồi mới tăng tốc. Với 28BYJ-48, kiểm tra thứ tự khai báo chân 8, 10, 9, 11.
Nên chọn A4988, DRV8825 hay TMC2209?
Người mới học với NEMA17 dưới 1 A dùng A4988 là đủ. DRV8825 hợp khi cần dòng cao hơn hoặc nguồn trên 24 V. TMC2209 êm hơn rõ rệt, hợp máy in 3D, thiết bị đặt trong nhà, nhưng không chịu nguồn 36 V.
Chân EN có bắt buộc nối với Arduino không?
Không. Bỏ trống thì A4988, DRV8825 tự bật, động cơ luôn có dòng giữ. Nối EN giúp thả động cơ khi nghỉ cho đỡ nóng hoặc tắt khẩn cấp; với trục đứng thì không thả khi đang có tải.
Thư viện Stepper.h có dùng được với A4988, DRV8825 không?
Không phù hợp. Stepper.h đóng cắt trực tiếp 2 hoặc 4 dây cuộn, không có chế độ STEP/DIR và không có gia tốc. Với driver STEP/DIR, dùng AccelStepper, FastAccelStepper hoặc tự phát xung như ví dụ ở mục 5.
Động cơ bước có tự biết vị trí khi vừa bật nguồn không?
Không. Arduino chỉ đếm số xung đã phát, nên sau khi bật nguồn phải homing về công tắc hành trình hoặc cảm biến quang để lấy gốc. Nếu động cơ mất bước khi chạy, số đếm sai mà Arduino không biết, trừ khi gắn encoder.
Động cơ 28BYJ-48 quay một vòng bao nhiêu bước?
Khoảng 4.076 nửa bước, hay 2.038 bước đủ. Con số 4.096 và 2.048 tính theo tỉ số danh nghĩa 1/64, còn tỉ số thật xấp xỉ 1/63,68. Quay qua lại vài vòng thì không đáng kể; chạy liên tục như kim đồng hồ nên dùng số thực tế.
ESP32 3,3 V có điều khiển trực tiếp A4988 và TMC2209 được không?
Được. Nối VDD của driver vào 3V3, nối chung GND và tránh các chân strapping 0, 2, 12, 15 cho STEP/DIR.
TMC2209 có cần nối UART mới chạy được không?
Không. Ở chế độ độc lập, TMC2209 chạy bằng Vref và MS1/MS2 như A4988. UART chỉ cần khi muốn đặt dòng bằng phần mềm, chọn vi bước khác 8/16/32/64 hoặc dùng StallGuard thay công tắc hành trình.
Vi bước 1/16 có làm động cơ chính xác hơn 16 lần không?
Không. Vi bước làm chuyển động mịn và êm hơn, nhưng động cơ 1,8° có sai số góc bước khoảng ±5% và mô-men tăng thêm cho mỗi vi bước rất nhỏ nên ma sát có thể "nuốt" vài vi bước. Với vít me T8 lead 8, một bước đủ là 0,04 mm; nên tính độ chính xác theo con số này cộng độ rơ cơ khí.
Có dùng Arduino Nano với CNC Shield được không?
Có, nhưng phải dùng shield dành riêng cho Nano (thường ghi V4); Nano không cắm được lên CNC Shield V3 vốn theo chân Uno. GRBL nạp cho Nano giống Uno vì cùng chip ATmega328P.
14. Kết luận
Hệ động cơ bước Arduino chạy ổn định dựa trên bốn việc: chọn driver phù hợp dòng và điện áp, đặt Vref đúng theo điện trở cảm biến, lắp tụ bảo vệ sát chân nguồn, và phát xung có gia tốc bằng thư viện không chặn. Thêm số bước/mm tính đúng và homing bằng công tắc hành trình là có một trục định vị tin cậy; cần nhiều trục nội suy G-code thì GRBL trên CNC Shield V3 là con đường nhanh nhất.






