ESP32 điều khiển động cơ bước 28BYJ-48 với ULN2003: nửa bước, quay đúng góc, kim giây

Hướng dẫn điều khiển động cơ bước 28BYJ-48 bằng ESP32 qua mạch ULN2003: chế độ nửa bước, 4076 bước một vòng, quay đúng góc theo lệnh, kim giây đồng hồ và thí nghiệm STEM.

Động cơ bước 28BYJ-48 kèm mạch ULN2003 là bộ động cơ bước rẻ và dễ dùng nhất cho học sinh. Động cơ bước không quay liên tục như động cơ DC mà nhích từng bước nhỏ theo thứ tự cấp điện các cuộn dây. Vì vậy chương trình biết chính xác trục đã quay bao nhiêu mà không cần cảm biến. Bộ này hợp với bàn xoay chụp ảnh, kim đồng hồ mô hình, cơ cấu mở rèm, máy cho cá ăn.

Bài viết giải thích chế độ nửa bước, cách tính số bước cho một góc, cách nối ESP32 với ULN2003, hai chương trình mẫu (quay đúng góc theo lệnh, kim giây đồng hồ) và gợi ý thí nghiệm STEM.

1. Động cơ bước và chế độ nửa bước

Hình minh họa bảng tám pha nửa bước của động cơ 28BYJ-48 qua bốn chân IN1 đến IN4 của ULN2003, kèm cách tính khoảng 4076 nửa bước cho một vòng trục ra
Hình minh họa: thứ tự cấp điện và cách tính số bước một vòng.
  • 28BYJ-48 có bốn cuộn dây. Dây đỏ là đầu chung nối +5 V; bốn dây xanh dương, hồng, vàng, cam đi qua ULN2003 xuống GND khi chân IN tương ứng ở mức cao.
  • Nửa bước: lần lượt cấp điện một cuộn, rồi hai cuộn liền nhau, cứ thế qua tám pha. Mỗi pha rôto nhích 5,625°. Chế độ này êm hơn và chia góc mịn hơn so với cấp từng cuộn một.
  • Hộp số bên trong giảm tốc khoảng 63,68 lần. Trục ra quay một vòng sau khoảng 64 × 63,68 ≈ 4076 nửa bước. Nhiều tài liệu ghi 4096; con số này lệch khoảng 0,5 % nên sau nhiều vòng sẽ thấy sai rõ.
  • ULN2003 là mạch đệm dòng gồm 7 cặp transistor Darlington. Mạch nhận mức 3,3 V của ESP32 và đóng ngắt dòng khoảng 100–250 mA của mỗi cuộn dây. Bốn LED trên mạch sáng theo pha, rất tiện để quan sát.

2. Linh kiện cần chuẩn bị

3. Sơ đồ nối dây

Sơ đồ nối ESP32 DevKit V1 với mạch ULN2003: IN1 vào D19, IN2 vào D18, IN3 vào TX2, IN4 vào RX2, nguồn 5 V lấy từ chân VIN, GND chung; động cơ 28BYJ-48 cắm vào đầu cắm 5 dây
Hình minh họa: sơ đồ nối ESP32, ULN2003 và động cơ 28BYJ-48.
Bảng nối dây
ULN2003ESP32
IN1D19 (GPIO19)
IN2D18 (GPIO18)
IN3TX2 (GPIO17)
IN4RX2 (GPIO16)
+5 V: chân VIN khi ESP32 cắm USB, hoặc nguồn 5 V riêng
−GND

Chân TX2, RX2 trên mạch là GPIO17 và GPIO16. Chương trình dùng chúng làm chân ra bình thường. Một động cơ 28BYJ-48 lấy 5 V từ cổng USB được; khi chạy hai động cơ trở lên thì dùng nguồn 5 V riêng, GND nối chung.

4. Chương trình 1: quay đúng góc theo lệnh

Gõ một số góc trên Serial Monitor (115200 baud, kiểu xuống dòng "New Line"). Ví dụ 90 quay 90°, -45 quay ngược 45°, v 3 đặt 3 ms cho mỗi nửa bước, 0 quay về vị trí lúc bật nguồn.

/*
  PYWORLD.VN - ESP32 điều khiển động cơ bước 28BYJ-48 qua mạch ULN2003, chế độ nửa bước
  ULN2003: IN1 -> GPIO19, IN2 -> GPIO18, IN3 -> GPIO17, IN4 -> GPIO16; nguồn mạch 5 V, GND chung với ESP32
  Lệnh trên Serial Monitor (115200, New Line): 90 = quay 90 độ, -45 = quay ngược 45 độ, v 3 = mỗi nửa bước 3 ms, 0 = về vị trí đầu
*/

const uint8_t CHAN[4] = {19, 18, 17, 16};     // IN1..IN4

// Tám pha của chế độ nửa bước: lần lượt cấp điện 1 cuộn, rồi 2 cuộn liền nhau
const uint8_t NUA_BUOC[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}
};

// 64 nửa bước một vòng rôto x hộp số khoảng 63,68 : 1 = khoảng 4076 nửa bước một vòng trục ra
const long BUOC_MOI_VONG = 4076;

long viTri = 0;        // vị trí so với lúc bật nguồn, đơn vị nửa bước
int pha = 0;           // chỉ số hàng đang dùng trong bảng NUA_BUOC
int msMoiBuoc = 2;     // thời gian mỗi nửa bước; nhỏ hơn 1 ms động cơ dễ trượt bước

void xuatPha(int p) {
  for (int i = 0; i < 4; i++) digitalWrite(CHAN[i], NUA_BUOC[p][i]);
}

void nhaCuon() {
  for (int i = 0; i < 4; i++) digitalWrite(CHAN[i], LOW);
}

void diBuoc(long soBuoc) {
  int huong = (soBuoc >= 0) ? 1 : -1;
  for (long i = 0; i < labs(soBuoc); i++) {
    pha = (pha + huong + 8) % 8;
    xuatPha(pha);
    viTri += huong;
    delay(msMoiBuoc);
  }
  nhaCuon();   // ngắt điện các cuộn dây cho đỡ nóng; trục được giữ nhờ ma sát hộp số
}

void inViTri() {
  Serial.printf("Vi tri: %ld nua buoc = %.1f do\n", viTri, viTri * 360.0 / BUOC_MOI_VONG);
}

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < 4; i++) pinMode(CHAN[i], OUTPUT);
  nhaCuon();
  delay(500);
  Serial.println("28BYJ-48: go so do (vi du 90, -45), v <ms>, hoac 0 de ve vi tri dau");
}

void loop() {
  if (!Serial.available()) return;
  String s = Serial.readStringUntil('\n');
  s.trim();
  if (s.length() == 0) return;

  if (s.charAt(0) == 'v' || s.charAt(0) == 'V') {
    int ms = s.substring(1).toInt();
    if (ms >= 1 && ms <= 50) {
      msMoiBuoc = ms;
      Serial.printf("Moi nua buoc %d ms (khoang %.1f vong/phut)\n", ms, 60000.0 / (ms * BUOC_MOI_VONG));
    }
    return;
  }

  long buoc;
  if (s == "0") {
    buoc = -viTri;                                   // quay ngược lại đúng số bước đã đi
  } else {
    float goc = s.toFloat();
    if (goc == 0) {
      Serial.println("Lenh khong hop le");
      return;
    }
    buoc = lroundf(goc * BUOC_MOI_VONG / 360.0f);
  }
  Serial.printf("Quay %ld nua buoc, mat khoang %.1f s\n", buoc, labs(buoc) * msMoiBuoc / 1000.0);
  diBuoc(buoc);
  inViTri();
}
Hình minh họa Serial Monitor khi gõ 90, -45, v 3 và 0: in số nửa bước, thời gian quay và vị trí hiện tại tính bằng độ
Hình minh họa: số nửa bước và vị trí sau từng lệnh.
  • NUA_BUOC[8][4] là bảng tám pha ở mục 1. Tăng chỉ số pha thì quay một chiều, giảm thì quay chiều kia.
  • lroundf(goc * 4076 / 360) đổi góc ra số nửa bước và làm tròn. Ví dụ 90° là 1019 nửa bước.
  • viTri đếm tổng số bước đã đi, nên lệnh 0 chỉ cần quay ngược đúng bấy nhiêu bước.
  • nhaCuon() ngắt điện cả bốn cuộn sau mỗi lần quay. Động cơ đỡ nóng, đỡ tốn điện, còn trục vẫn được ma sát hộp số giữ lại.

5. Chương trình 2: kim giây đồng hồ mô hình

Gắn một que nhẹ lên trục làm kim, đặt kim chỉ số 12 rồi cho chạy. Mỗi giây kim nhích một vạch, 60 giây quay đúng một vòng.

/*
  PYWORLD.VN - Kim giây đồng hồ mô hình: động cơ 28BYJ-48 nhích một vạch mỗi giây (ESP32 + ULN2003)
  Nối dây như chương trình BUOC_28BYJ48_QUAY_GOC
  Mỗi giây tính lại vị trí đích từ số giây để sai số làm tròn không cộng dồn qua từng vòng
*/

const uint8_t CHAN[4] = {19, 18, 17, 16};
const uint8_t NUA_BUOC[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}
};
const long BUOC_MOI_VONG = 4076;

long viTri = 0;
int pha = 0;
int giay = 0;
unsigned long tTruoc = 0;

void diToi(long dich) {
  while (viTri != dich) {
    int huong = (dich > viTri) ? 1 : -1;
    pha = (pha + huong + 8) % 8;
    for (int i = 0; i < 4; i++) digitalWrite(CHAN[i], NUA_BUOC[pha][i]);
    viTri += huong;
    delay(2);
  }
  for (int i = 0; i < 4; i++) digitalWrite(CHAN[i], LOW);
}

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < 4; i++) pinMode(CHAN[i], OUTPUT);
  Serial.println("Kim giay: dat kim chi so 12 roi cho chay");
  tTruoc = millis();
}

void loop() {
  if (millis() - tTruoc < 1000) return;
  tTruoc += 1000;

  giay++;
  long dich = (long)giay * BUOC_MOI_VONG / 60;   // vị trí của vạch thứ giay tính từ số 12
  diToi(dich);
  if (giay == 60) {                              // tròn một vòng: đặt lại mốc
    giay = 0;
    viTri = 0;
  }
  Serial.printf("Giay %2d -> vi tri %4ld nua buoc\n", giay, viTri);
}

4076 không chia hết cho 60 (khoảng 67,93 nửa bước mỗi giây). Nếu mỗi giây cứ đi 68 bước, sau mỗi vòng kim sẽ vượt 4 bước. Chương trình tính lại vị trí đích theo số giây đã qua: giay × 4076 / 60. Như vậy sai số làm tròn không cộng dồn, kim luôn về đúng số 12.

6. Tốc độ và lực của 28BYJ-48

  • Với 2 ms mỗi nửa bước, trục ra mất khoảng 8,2 giây cho một vòng (khoảng 7,4 vòng/phút).
  • Giảm xuống 1 ms thì nhanh gấp đôi nhưng động cơ dễ trượt bước, nhất là khi có tải. Trượt bước nghĩa là cuộn dây đã đổi pha mà rôto chưa kịp theo, nên vị trí đếm được không còn đúng.
  • Động cơ này yếu và chậm. Cơ cấu nặng, cần nhanh hoặc cần chính xác thì dùng động cơ bước NEMA 17 với driver A4988 (bài sau trong loạt).

7. Gợi ý dùng trong giờ học STEM

Mục tiêu: học sinh hiểu điều khiển vòng hở (đếm bước, không cần cảm biến), tỉ số truyền của hộp số, và cách xử lý sai số làm tròn.

  1. Kiểm chứng tỉ số truyền. Đánh dấu vị trí trục, lần lượt cho quay 4096 và 4076 nửa bước, đo độ lệch so với vạch ban đầu. Con số nào đúng hơn? Lặp lại 10 vòng để thấy rõ sai lệch.
  2. Tìm tốc độ lớn nhất. Gắn một tải nhẹ (đĩa bìa có kẹp giấy), giảm dần v cho tới khi động cơ bắt đầu trượt bước. Lập bảng tốc độ theo tải.
  3. Làm đồng hồ. Dùng chương trình 2, vẽ mặt đồng hồ bằng bìa. Mở rộng: thêm động cơ thứ hai làm kim phút, hoặc lấy giờ từ Internet qua NTP như bài đồng hồ ESP32 NTP.
  4. Bàn xoay chụp ảnh 360°. Mỗi lần quay 15°, dừng 2 giây để điện thoại chụp, được 24 ảnh quanh một vật.

Hoạt động gắn với tỉ số và số đo góc trong Toán, chuyển động quay và bánh răng trong Công nghệ, Vật lý, và lập trình trong Tin học.

8. Xử lý lỗi thường gặp

Lỗi thường gặp
Hiện tượngNguyên nhân thường gặpCách xử lý
LED trên ULN2003 nháy nhưng trục không quay, chỉ rungSai thứ tự IN1–IN4, hoặc bước quá nhanhKiểm tra lại bốn dây theo bảng; tăng v lên 3–5 ms
Quay ngược chiều mong muốnChiều quay phụ thuộc cách lắpĐổi dấu góc trong lệnh, hoặc đảo thứ tự mảng CHAN
Sau vài vòng lệch dần vị tríDùng 4096 thay vì 4076; có trượt bướcDùng 4076; giảm tốc độ, giảm tải
Động cơ nóngCuộn dây được cấp điện liên tụcGọi nhaCuon() sau mỗi lần quay như trong chương trình
ESP32 khởi động lạiNguồn USB yếu khi chạy nhiều động cơDùng nguồn 5 V riêng, GND chung

9. Xem thêm

Cùng loạt: ESP32 điều khiển động cơ DC với L298N, servo SG90 và động cơ bước NEMA 17 với A4988.


Tin tức liên quan

Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường
Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường

Làm xe robot tự tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 gắn trên servo quét trái phải, cầu phân áp cho chân ECHO, thuật toán chọn đường, lưu đồ và thí nghiệm STEM.

Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano
Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano

Hướng dẫn nối màn hình OLED 0.96 inch SSD1306 (I2C) với Arduino Nano, cài thư viện Adafruit, hiện chữ nhiều cỡ, vẽ thanh mức theo điện áp và lưu ý về bộ nhớ RAM.

ESP32 điều khiển động cơ bước NEMA 17 với A4988: vi bước, chỉnh dòng VREF, tăng tốc mượt
ESP32 điều khiển động cơ bước NEMA 17 với A4988: vi bước, chỉnh dòng VREF, tăng tốc mượt

Hướng dẫn điều khiển động cơ bước NEMA 17 bằng ESP32 qua driver A4988: nối dây, chỉnh dòng VREF, chọn vi bước 1/16, tăng tốc giảm tốc hình thang và thí nghiệm STEM.

Điều khiển relay từ xa bằng ESP-NOW: remote ESP32 một nút nhấn có phản hồi trạng thái
Điều khiển relay từ xa bằng ESP-NOW: remote ESP32 một nút nhấn có phản hồi trạng thái

Hướng dẫn làm bộ điều khiển relay từ xa bằng hai mạch ESP32 và ESP-NOW hai chiều: remote gửi lệnh, mạch relay báo lại trạng thái, lọc theo địa chỉ MAC và bật mã hóa.

ESP32 điều khiển servo SG90 bằng PWM, không cần thư viện: quét góc, biến trở, hiệu chỉnh
ESP32 điều khiển servo SG90 bằng PWM, không cần thư viện: quét góc, biến trở, hiệu chỉnh

Hướng dẫn điều khiển servo SG90 bằng ESP32 với bộ PWM LEDC 50 Hz có sẵn: xung 0,5–2,4 ms, sơ đồ nối, quét góc, vặn biến trở, hiệu chỉnh hai đầu hành trình và thí nghiệm STEM.

Hướng dẫn kết nối Wi-Fi trên ESP32: quét mạng, tự kết nối lại, IP tĩnh và phát Wi-Fi riêng
Hướng dẫn kết nối Wi-Fi trên ESP32: quét mạng, tự kết nối lại, IP tĩnh và phát Wi-Fi riêng

Hướng dẫn các thao tác Wi-Fi cần dùng nhất trên ESP32 với Arduino IDE: quét mạng, kết nối có thời gian chờ, xem IP và cường độ sóng, tự kết nối lại, đặt IP tĩnh, phát Wi-Fi riêng.

Hướng dẫn ESP32 làm web server điều khiển relay 4 kênh qua WiFi
Hướng dẫn ESP32 làm web server điều khiển relay 4 kênh qua WiFi

Hướng dẫn dùng ESP32 DevKit V1 làm web server trong mạng WiFi nội bộ, mở trang trên điện thoại để bật, tắt module relay 4 kênh; có sơ đồ nối dây, code Arduino IDE và lưu ý an toàn.

Hướng dẫn dùng mạch tạo trễ NE555 có relay: đấu dây và chỉnh thời gian trễ
Hướng dẫn dùng mạch tạo trễ NE555 có relay: đấu dây và chỉnh thời gian trễ

Hướng dẫn dùng mạch tạo trễ NE555 có relay bản 5 V và 12 V: nguyên lý tạo trễ, ý nghĩa các cọc VCC, GND, COM, CK, CB, cách chỉnh thời gian trễ, sơ đồ đấu dây và xử lý lỗi thường gặp.


Bình luận
Đã thêm vào giỏ hàng