Điều khiển động cơ bước dùng PIC16F877A: sơ đồ mạch, tạo xung bằng Timer, biến trở chỉnh tốc, LCD và Proteus
Điều khiển động cơ bước dùng PIC16F877A là cách dùng vi điều khiển 8 bit PIC16F877A của Microchip để phát trình tự cấp điện cho các cuộn dây (qua ULN2003, L298) hoặc phát xung STEP/DIR cho driver (A4988, DRV8825, TB6600), kèm đọc phím nhấn, biến trở chỉnh tốc độ và hiển thị trạng thái lên LCD 16x2. Chip có 40 chân, 33 chân I/O, ADC 10 bit 8 kênh, ba bộ định thời và chạy tối đa 20 MHz, đủ dư cho một đến bốn động cơ bước ở tốc độ của mô hình và máy nhỏ.
Phần khó thường không nằm ở trình tự xung mà ở những chi tiết làm mạch thật không chạy: cấu hình config bits, chân MCLR, chế độ LVP, PORTA mặc định là analog, nguồn motor làm reset chip, và cách tạo xung đều khi vừa phải quét phím vừa cập nhật LCD.
Phần nguyên lý chung về họ PIC với động cơ bước có ở bài điều khiển động cơ bước dùng PIC; nội dung dưới đây đi thẳng vào PIC16F877A: sơ đồ chân, mạch ghép, đoạn code mẫu, mô phỏng và nạp chip.

Nội dung
- 1. PIC16F877A có những gì để điều khiển động cơ bước
- 2. Sơ đồ chân và phân bổ cổng cho mạch điều khiển động cơ bước PIC16F877A
- 3. Mạch dao động 20 MHz, nguồn và chân MCLR
- 4. Ghép PIC16F877A với tầng công suất: ULN2003, L298 và driver STEP/DIR
- 5. Trình tự xung và code điều khiển động cơ bước bằng PIC16F877A
- 6. Tạo xung bằng delay hay bằng Timer và ngắt
- 7. Đọc biến trở bằng ADC để chỉnh tốc độ
- 8. Phím nhấn và LCD 16x2 trong đồ án
- 9. Mô phỏng Proteus mạch PIC16F877A điều khiển động cơ bước
- 10. Nạp chip bằng PICkit qua cổng ICSP
- 11. Lỗi thường gặp khi điều khiển động cơ bước dùng PIC16F877A
- 12. Gợi ý đề tài và giới hạn của PIC16F877A với động cơ bước
- 13. Câu hỏi thường gặp về điều khiển động cơ bước dùng PIC16F877A
1. PIC16F877A có những gì để điều khiển động cơ bước
PIC16F877A là vi điều khiển lõi 14 bit (mid-range), bộ nhớ chương trình 8K word Flash, 368 byte RAM, 256 byte EEPROM. Với bài toán động cơ bước, các khối đáng quan tâm là cổng I/O, Timer, CCP, ADC và ngắt ngoài.
| Khối chức năng | Thông số | Dùng vào việc gì |
| Xung nhịp | Tối đa 20 MHz (chu kỳ lệnh 200 ns) | Tính chính xác thời gian giữa các bước |
| Cổng I/O | PORTA 6, PORTB 8, PORTC 8, PORTD 8, PORTE 3 chân | Xuất trình tự pha, STEP/DIR, đọc phím, LCD |
| Dòng mỗi chân | 25 mA (hút hoặc cấp) | Chỉ đủ kéo LED, ngõ vào driver; không kéo trực tiếp cuộn dây |
| Timer0 / Timer1 / Timer2 | 8 bit / 16 bit / 8 bit | Timer1 tạo chu kỳ bước, Timer0 quét phím |
| CCP1, CCP2 | Capture, Compare, PWM | Compare + Timer1 tạo chu kỳ bước tự nạp lại |
| ADC | 10 bit, 8 kênh AN0–AN7 | Đọc biến trở chỉnh tốc độ |
| Ngắt ngoài | RB0/INT, ngắt đổi trạng thái RB4–RB7 | Công tắc hành trình, nút dừng khẩn |
| Nguồn | 2,0–5,5 V (ở 20 MHz cần 4,5–5,5 V) | Thực tế cấp 5 V từ 7805 |
Mỗi chân tối đa 25 mA, tổng cả cổng khoảng 200 mA, trong khi cuộn dây motor bước nhỏ nhất cũng ăn vài chục đến vài trăm mA, nên luôn phải có tầng công suất ở giữa.
2. Sơ đồ chân và phân bổ cổng cho mạch điều khiển động cơ bước PIC16F877A
Phân bổ chân hợp lý giúp viết code gọn (xuất cả nibble một lần) và tránh đụng các chân đặc biệt. Cách chia dưới đây là cách phổ biến cho đồ án một hoặc hai động cơ.
| Chân (DIP40) | Tên | Gán chức năng | Ghi chú |
| 1 | MCLR/VPP | Điện trở 10 kΩ lên 5 V, nút Reset xuống mass | Bắt buộc kéo lên, không được để hở |
| 2 | RA0/AN0 | Biến trở chỉnh tốc độ | Cấu hình analog qua ADCON1 |
| 11, 32 | VDD | 5 V | Mỗi chân một tụ 100 nF sát chân |
| 12, 31 | VSS | Mass | Nối cả hai chân |
| 13, 14 | OSC1, OSC2 | Thạch anh 20 MHz + 2 tụ 15–22 pF | Config HS |
| 33 | RB0/INT | Công tắc gốc (home) hoặc dừng khẩn | Dùng ngắt ngoài |
| 34, 35, 37, 38 | RB1, RB2, RB4, RB5 | Phím: chạy/dừng, đổi chiều, chế độ, cài đặt | Bật trở kéo lên nội của PORTB |
| 36 | RB3/PGM | Tránh dùng nếu chưa tắt LVP | Xem mục 7 |
| 39, 40 | RB6/PGC, RB7/PGD | Để trống cho mạch nạp ICSP | Không treo tải nặng |
| 19–22 | RD0–RD3 | IN1–IN4 của ULN2003/L298 hoặc STEP, DIR, EN | Xuất nibble thấp PORTD |
| 27–30 | RD4–RD7 | Động cơ thứ hai hoặc LCD 4 bit | Tùy thư viện LCD |
3. Mạch dao động 20 MHz, nguồn và chân MCLR
Ba phần "phụ" này quyết định chip có chạy hay không, nhiều hơn cả code.
Thạch anh 20 MHz
- Đấu thạch anh giữa chân 13 và 14, mỗi chân một tụ 15–22 pF xuống mass, đặt sát chip.
- Config dao động phải là HS. Để XT với thạch anh 20 MHz, mạch thường không dao động hoặc dao động chập chờn.
- Ở 20 MHz, một chu kỳ lệnh là 200 ns; mọi phép tính Timer bên dưới đều dựa trên Fosc/4 = 5 MHz.
Nguồn cho mạch
Mạch thông dụng lấy 12 V cho motor, hạ 5 V bằng 7805 cho PIC; tụ 100 nF ở từng cặp VDD/VSS, tụ hóa 100–470 µF ở đầu vào 7805 và nguồn motor. Mass motor đi riêng về cực âm nguồn, gặp mass logic tại một điểm, để xung dòng cuộn dây không làm dao động chân VSS của PIC.
Chân MCLR
PIC16F877A không có bit cấu hình tắt chân MCLR, nên chân 1 luôn là chân reset tích cực mức thấp. Điện trở 10 kΩ lên 5 V là bắt buộc; nút reset nối từ chân này xuống mass, có thể thêm điện trở 100–470 Ω nối tiếp nút. Tránh đặt tụ lớn trực tiếp lên MCLR nếu nạp chip tại mạch (ICSP), vì tụ làm chậm sườn điện áp lập trình.
4. Ghép PIC16F877A với tầng công suất: ULN2003, L298 và driver STEP/DIR
Chọn tầng công suất theo loại motor đang có. Motor 5 dây hoặc 6 dây đơn cực dùng ULN2003; motor 4 dây lưỡng cực dòng nhỏ dùng L298; motor NEMA 17, NEMA 23 dòng từ 1 A trở lên nên dùng driver STEP/DIR có hạn dòng.
| Tầng công suất | Motor phù hợp | Chân PIC dùng | Code phải làm |
| ULN2003 | Đơn cực 5 dây/6 dây, dòng ≤ 0,5 A/pha | RD0–RD3 → IN1–IN4 | Xuất trình tự 4 hoặc 8 trạng thái |
| L298N | Lưỡng cực 4 dây, điện trở cuộn cao | RD0–RD3 → IN1–IN4, ENA/ENB lên 5 V | Xuất trình tự cầu H |
| A4988 / DRV8825 | NEMA 17 đến khoảng 1,5–2 A | RD0 → STEP, RD1 → DIR, RD2 → EN | Phát xung, PIC không lo trình tự pha |
| TB6600 / DM542 | NEMA 17–34 | RD0 → PUL+, RD1 → DIR+, PUL−/DIR− về mass | Phát xung, cần độ rộng xung đủ dài |
a. PIC16F877A với ULN2003 cho motor đơn cực
Bốn chân RD0–RD3 nối IN1–IN4, bốn ngõ ra OUT1–OUT4 nối bốn đầu pha, dây chung của motor nối cực dương nguồn motor (5 V hoặc 12 V tùy motor), chân COM (chân 9) của ULN2003 cũng nối cực dương này để diode dập bên trong làm việc. Mass ULN2003 nối chung mass PIC. Motor đảo gió, motor máy in cũ loại 5 dây như trong ảnh trên chạy tốt với cách đấu này. Chi tiết dòng, sụt áp và nhiệt của IC xem bài điều khiển động cơ bước bằng ULN2003; thứ tự dây và chế độ kích từ của motor 4 pha 5 dây có ở bài động cơ bước 4 pha 5 dây.
b. PIC16F877A với L298 cho motor lưỡng cực
RD0, RD1 điều khiển cuộn A (IN1, IN2), RD2, RD3 điều khiển cuộn B (IN3, IN4); ENA, ENB nối 5 V hoặc nối thêm hai chân PIC nếu muốn ngắt điện cuộn khi đứng. L298 không hạn dòng, sụt áp 2–4 V, nên chỉ hợp motor điện trở cuộn cao; giới hạn này và cách chọn nguồn đã phân tích ở bài điều khiển động cơ bước dùng L298. Cùng một mảng trình tự cho ULN2003 dùng được cho L298 ở chế độ full step hai pha, chỉ khác ý nghĩa vật lý: ở L298 mỗi cặp bit là hai đầu của cùng một cuộn.
c. PIC16F877A với driver STEP/DIR (A4988, DRV8825, TB6600)
Khi dùng driver, PIC chỉ cần hai chân: STEP (mỗi sườn lên là một bước hoặc vi bước) và DIR (chiều quay). Ngõ ra 5 V của PIC khớp trực tiếp mức logic của A4988, DRV8825; với TB6600, DM542 ngõ vào là opto, đấu chung cathode: PUL+, DIR+ nối chân PIC, PUL−, DIR− nối mass.

Sơ đồ trên áp dụng nguyên cho PIC16F877A: VDD của A4988 lấy 5 V từ 7805, STEP và DIR nối RD0, RD1, chân RESET và SLEEP nối với nhau, tụ 100 µF đặt sát chân VMOT. Độ rộng xung STEP tối thiểu của A4988 là 1 µs, DRV8825 khoảng 1,9 µs; với TB6600 nên giữ mức cao ít nhất khoảng 5 µs cho opto kịp đóng. Khi viết code, giữ chân STEP ở mức cao vài micro giây rồi mới kéo xuống là an toàn cho mọi loại. Đặt dòng, vi bước của TB6600 xem bài mạch điều khiển động cơ bước TB6600.
5. Trình tự xung và code điều khiển động cơ bước bằng PIC16F877A
Với ULN2003 và L298, PIC phải tự xuất trình tự pha. Gom bốn chân pha vào nibble thấp PORTD giúp mỗi bước chỉ là một lệnh ghi cổng.
Bảng trình tự xuất ra PORTD (RD3…RD0)
| Chế độ | Số trạng thái | Giá trị lần lượt (hex) | Đặc điểm |
| Wave (1 pha) | 4 | 0x01, 0x02, 0x04, 0x08 | Ít dòng, mô-men thấp nhất |
| Full step (2 pha) | 4 | 0x03, 0x06, 0x0C, 0x09 | Mô-men lớn nhất ở bước đủ |
| Half step (1-2 pha) | 8 | 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09 | Gấp đôi độ phân giải, êm hơn |
Đổi chiều quay chỉ là duyệt mảng theo chiều ngược lại. Khi ghi PORTD mà nibble cao đang dùng cho việc khác (LCD), phải giữ nguyên 4 bit cao: PORTD = (PORTD & 0xF0) | seq[i];.
Khung chương trình CCS C (delay đơn giản)
#include <16F877A.h>#fuses HS, NOWDT, PUT, BROWNOUT, NOLVP, NOPROTECT#use delay(clock=20M)- Mảng:
const int8 seq[8] = {0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09}; - Trong
main():set_tris_d(0xF0);rồi vòng lặpoutput_d(seq[i]); delay_ms(t); i = (i + 1) & 7; - Đổi chiều:
i = (i - 1) & 7;
delay_ms(t) của CCS nhận biến.
Cùng logic viết bằng MikroC PRO for PIC
- Config chọn trong Edit Project: HS, WDT Off, LVP Off; Oscillator 20 MHz.
TRISD = 0xF0; PORTD = 0;PORTD = (PORTD & 0xF0) | seq[i];Delay_ms()của MikroC chỉ nhận hằng số; muốn trễ theo biến dùngVdelay_ms(t);.
Cùng logic viết bằng XC8 (MPLAB X)
#pragma config FOSC = HS, WDTE = OFF, PWRTE = ON, BOREN = ON, LVP = OFF, CPD = OFF, WRT = OFF, CP = OFF#define _XTAL_FREQ 20000000__delay_ms()và__delay_us()chỉ nhận hằng số. Trễ theo biến: viết vòng lặpfor (k = 0; k < t; k++) __delay_us(100);.
Phát xung STEP/DIR cho A4988, TB6600
RD1 = dir;(đặt chiều trước, chờ vài micro giây)RD0 = 1; __delay_us(5); RD0 = 0;- Chờ phần còn lại của chu kỳ bước rồi lặp lại.
Bảng quy đổi số bước ra góc quay
| Motor / chế độ | Bước mỗi vòng | 90° cần bao nhiêu bước |
| Hybrid 1,8°, full step (A4988 để 1/1) | 200 | 50 |
| Hybrid 1,8°, vi bước 1/8 | 1.600 | 400 |
| Hybrid 1,8°, vi bước 1/16 | 3.200 | 800 |
| PM 7,5° tháo máy in, full step | 48 | 12 |
| PM 7,5°, half step | 96 | 24 |
Muốn quay đúng một góc, đếm số bước trong vòng lặp hoặc trong ngắt rồi dừng khi đủ. Với motor có hộp số như 28BYJ-48, số bước mỗi vòng khác hẳn; con số thật có ở bài động cơ bước 5 dây.
6. Tạo xung bằng delay hay bằng Timer và ngắt
Code dùng delay dễ hiểu và đủ cho bài thực hành đầu tiên, nhưng đến khi thêm LCD, phím và biến trở thì tốc độ motor bắt đầu dao động. Lý do: mỗi lần ghi LCD mất vài trăm micro giây đến vài mili giây, mỗi lần đọc ADC mất khoảng 20 µs, và tất cả các khoảng đó cộng vào khoảng cách giữa hai bước.
Cách tính Timer1 ở 20 MHz
Timer1 đếm xung Fosc/4 = 5 MHz. Đặt bộ chia trước (prescaler) 1:8, mỗi lần đếm là 1,6 µs, Timer1 16 bit tràn sau tối đa 65.536 × 1,6 µs ≈ 104,9 ms. Như vậy một ngắt Timer1 phủ được chu kỳ bước từ vài chục micro giây đến khoảng 105 ms, tức 10 bước/giây đến hàng nghìn bước/giây, đủ cho hầu hết motor.
- Số đếm cần: N = chu kỳ bước / 1,6 µs. Ví dụ bước 5 ms → N = 3.125.
- Kiểu nạp lại thủ công: trong ngắt ghi TMR1 = 65.536 − N (ở ví dụ là 62.411), rồi xuất bước tiếp theo.
- Kiểu dùng CCP1 Compare: đặt CCPR1 = N, chế độ CCP1M = 1011 (special event trigger). Khi Timer1 bằng CCPR1, phần cứng tự xóa Timer1 về 0 và bật cờ ngắt CCP1IF. Không phải nạp lại TMR1 bằng phần mềm nên chu kỳ chính xác tuyệt đối, chỉ còn trễ vào ngắt vài micro giây.
Trong hàm ngắt nên làm gì
- Xóa cờ ngắt (TMR1IF hoặc CCP1IF).
- Xuất trạng thái pha tiếp theo, hoặc tạo một xung STEP ngắn.
- Tăng/giảm biến đếm vị trí, so với vị trí đích, dừng khi đủ.
- Không ghi LCD, không đọc ADC, không gọi delay dài trong ngắt.
Vì sao không dùng module PWM của CCP để phát xung STEP ở tốc độ thấp
Với thạch anh 20 MHz, tần số PWM thấp nhất của PIC16F877A là Fosc / (4 × 16 × 256) ≈ 1.220 Hz (Timer2 prescaler tối đa 1:16, PR2 = 255). Motor 1,8° full step ở 1.220 bước/giây đã là hơn 360 vòng/phút, không thể khởi động thẳng ở tốc độ này. PWM phần cứng chỉ hợp khi dùng vi bước cao (1/16 trở lên) và có cách đếm xung riêng. Với đồ án thông thường, Timer1 + Compare là lựa chọn đúng.
Tăng tốc và giảm tốc mềm
Tải quán tính sẽ làm motor mất bước nếu khởi động ngay ở tốc độ cao. Cách làm trên PIC: bắt đầu với chu kỳ bước dài (ví dụ 10 ms), mỗi bước giảm chu kỳ một lượng nhỏ cho tới chu kỳ đích; gần tới vị trí dừng thì làm ngược lại. Có thể tính trước một bảng 32–64 giá trị chu kỳ, lưu trong ROM bằng mảng const, để trong ngắt chỉ cần tra bảng thay vì tính phép chia. Phần lý thuyết gia tốc hình thang, S-curve và chọn driver có ở bài điều khiển động cơ bước lưỡng cực.
7. Đọc biến trở bằng ADC để chỉnh tốc độ
Biến trở 10 kΩ đấu kiểu chia áp: hai đầu ngoài lên 5 V và mass, chân giữa vào RA0/AN0, thêm tụ 100 nF từ AN0 xuống mass để lọc nhiễu motor.
Cấu hình ADC cho PIC16F877A ở 20 MHz
| Thanh ghi / tham số | Giá trị | Ý nghĩa |
| ADCON1 | 0x8E | Chỉ AN0 là analog, các chân PORTA/PORTE còn lại số; kết quả căn phải |
| Xung ADC | Fosc/32 | TAD = 1,6 µs, đúng mức tối thiểu cho phép |
| Thời gian thu mẫu | ≥ khoảng 20 µs | Chờ sau khi chọn kênh, trước khi bắt đầu chuyển đổi |
| Kết quả | 0–1023 | Ghép ADRESH:ADRESL |
Trong CCS C dùng setup_adc(ADC_CLOCK_DIV_32); setup_adc_ports(AN0); set_adc_channel(0); delay_us(20); v = read_adc(); (khai báo #device ADC=10 để lấy đủ 10 bit). Trong MikroC dùng ADC_Read(0).
Quy đổi giá trị ADC thành chu kỳ bước
- Ánh xạ tuyến tính: chu kỳ = Tmin + (1023 − v) × (Tmax − Tmin) / 1023. Vặn biến trở lên, chu kỳ ngắn lại, motor quay nhanh.
- Giới hạn Tmin theo khả năng motor (ví dụ motor PM 7,5° với ULN2003 khoảng 2–3 ms mỗi bước; motor hybrid qua A4988 tùy vi bước).
- Đọc ADC trong vòng lặp chính, khoảng 20–50 lần mỗi giây là đủ; ghi giá trị mới vào biến chu kỳ, hàm ngắt lấy giá trị này ở bước tiếp theo.
- Lọc trung bình 4–8 lần đọc để tốc độ không rung theo nhiễu.
Nếu ứng dụng chỉ cần quay liên tục với tốc độ chỉnh bằng núm vặn, không cần định vị (băng tải nhỏ, máy khuấy, quay rang), động cơ giảm tốc mini kèm bộ điều tốc thường gọn và khỏe hơn một mạch PIC + động cơ bước.
8. Phím nhấn và LCD 16x2 trong đồ án
Phím nhấn trên PORTB
PORTB có trở kéo lên nội, bật bằng cách xóa bit RBPU của thanh ghi OPTION_REG (trong CCS: port_b_pullups(TRUE);). Phím nối từ chân RB xuống mass, không cần điện trở ngoài; nhấn là mức 0.
- Chống dội: khi thấy mức 0, chờ 20–30 ms rồi đọc lại, xác nhận mới xử lý, sau đó chờ nhả phím.
- Nếu tạo xung bằng Timer1, quét phím trong vòng lặp chính hoặc dùng Timer0 tràn mỗi khoảng 10 ms để đếm thời gian chống dội, không dùng delay dài.
- Công tắc hành trình hoặc nút dừng khẩn nên đưa vào RB0/INT để phản ứng ngay trong ngắt, không chờ vòng lặp.
Phân công điển hình: RB1 chạy/dừng (bật, tắt TMR1ON), RB2 đảo chiều, RB4 đổi chế độ full/half step, RB5 nhập số vòng hoặc số độ, RB0/INT công tắc gốc.
LCD 16x2 (HD44780) chế độ 4 bit
LCD cần 6 chân: RS, E và D4–D7; chân RW nối mass (chỉ ghi). Chân V0 nối con trượt biến trở 10 kΩ để chỉnh tương phản, chân A/K là đèn nền (thường cần điện trở hạn dòng nếu module không có sẵn). Thư viện lcd.c của CCS mặc định dùng PORTD; nếu nibble thấp PORTD đã dành cho motor, phải sửa định nghĩa chân của thư viện để LCD sang PORTB/PORTC, hoặc chuyển motor sang PORTC. Trong MikroC, chân LCD khai báo bằng các biến sbit LCD_RS at ..., đổi cổng tùy ý.
- Chỉ ghi lại LCD khi nội dung thay đổi (tốc độ, chiều, số bước), không xóa màn hình mỗi vòng lặp; lệnh xóa màn hình (clear) mất khoảng 1,5 ms và làm chữ nhấp nháy.
- Hiển thị tốc độ theo vòng/phút: rpm = 60 / (chu kỳ bước × số bước mỗi vòng). Ví dụ 200 bước/vòng, 5 ms mỗi bước → 60 vòng/phút.
9. Mô phỏng Proteus mạch PIC16F877A điều khiển động cơ bước
Proteus có sẵn model PIC16F877A, ULN2003A, L298 và MOTOR-STEPPER (chọn được đơn cực hoặc lưỡng cực, góc bước, điện trở cuộn), đủ để chạy thử toàn bộ đồ án trước khi làm mạch.
Các bước mô phỏng
- Biên dịch ra file .hex (CCS, MikroC, XC8 đều xuất được).
- Nhấp đúp PIC16F877A, mục Program File chọn file .hex, mục Processor Clock Frequency gõ 20MHz. Proteus lấy xung nhịp từ ô này, linh kiện thạch anh vẽ trên sơ đồ không quyết định tốc độ mô phỏng.
- Chân VDD, VSS của PIC bị ẩn và tự nối nguồn; chân MCLR thì không, vẫn phải kéo lên 5 V qua điện trở.
- Đặt điện áp và điện trở cuộn của MOTOR-STEPPER sát motor thật; model sẽ hiển thị góc quay trên thân motor.
Proteus không đòi tụ thạch anh, tụ lọc nguồn, không mô phỏng quán tính tải và sụt áp nguồn, nên mạch chạy được trong mô phỏng chưa chắc chạy ngoài thực tế. Cảnh báo "simulation not running in real time" chỉ là máy tính không theo kịp khi xung quá dày, không phải lỗi code.
Các tình huống motor lắc qua lại trong Proteus do sai thứ tự cuộn đã có hướng xử lý ở bài điều khiển động cơ bước bằng L293; với PIC16F877A, cần kiểm tra thêm ADCON1 nếu dùng chân PORTA/PORTE làm ngõ ra và giá trị TRISD.
10. Nạp chip bằng PICkit qua cổng ICSP
PIC16F877A nạp được tại mạch qua 5 dây ICSP. Đặt sẵn một hàng rào 5–6 chân trên PCB giúp sửa code nhiều lần mà không phải nhổ chip.
| Chân PICkit | Nối tới PIC16F877A | Lưu ý |
| 1 – VPP/MCLR | Chân 1 | Vẫn giữ trở 10 kΩ lên 5 V, không gắn tụ lớn |
| 2 – VDD | Chân 11/32 (5 V) | Mạch có nguồn riêng thì không cho PICkit cấp nguồn |
| 3 – VSS | Chân 12/31 | Mass chung |
| 4 – PGD | RB7 (chân 40) | Không treo tải nặng |
| 5 – PGC | RB6 (chân 39) | Không treo tải nặng |
| 6 – PGM (LVP) | RB3 (chân 36) | Chỉ dùng khi nạp điện áp thấp; nạp thường không cần |
Phần mềm
- PICkit 3, PICkit 4, PICkit 5: dùng MPLAB X IPE, chọn thiết bị PIC16F877A, nạp file .hex.
- PICkit 2 (và các bản tương thích): dùng phần mềm PICkit 2 Programmer độc lập, PIC16F877A nằm trong danh sách hỗ trợ.
- PICkit chỉ cấp được dòng nhỏ (vài chục mA); nếu mạch có LCD đèn nền, driver, relay thì cấp nguồn ngoài cho mạch và tắt chức năng cấp nguồn của PICkit.
Bit LVP và chân RB3
Chip mới xuất xưởng có thể bật LVP (lập trình điện áp thấp). Khi LVP bật, RB3 là chân PGM: nếu chân này để hở hoặc nhận nhiễu lên mức cao, chip có thể vào chế độ lập trình và ngừng chạy chương trình. Luôn tắt LVP trong config (NOLVP / LVP = OFF) và nạp bằng điện áp cao thông thường; sau đó RB3 mới dùng làm I/O bình thường.
11. Lỗi thường gặp khi điều khiển động cơ bước dùng PIC16F877A
| Hiện tượng | Nguyên nhân hay gặp | Cách xử lý |
| Nạp xong mạch không làm gì, LED không sáng | Config XT/RC với thạch anh 20 MHz, thiếu tụ thạch anh, MCLR để hở | Config HS, tụ 15–22 pF, trở 10 kΩ ở MCLR |
| Chạy được một lúc rồi đứng | WDT đang bật mà code không xóa | Tắt WDT hoặc gọi lệnh xóa WDT định kỳ |
| Chạy chập chờn, chạm tay vào chip thì chạy | RB3 nổi khi LVP bật, MCLR không kéo lên | Tắt LVP, kiểm tra trở MCLR |
| Ngõ ra PORTA, PORTE không đổi mức | Chân còn ở chế độ analog | Ghi ADCON1 (0x06 cho toàn bộ số, 0x8E nếu chỉ dùng AN0) |
| RA4 không lên mức cao | RA4 là cực máng hở | Thêm trở kéo lên hoặc đổi chân |
| PIC reset mỗi khi motor bắt đầu quay | Sụt áp, nhiễu mass từ motor, thiếu tụ | Tụ 100 nF tại VDD, tụ lớn ở nguồn motor, mass hình sao, BOR bật |
| Motor rung tại chỗ, không quay | Sai thứ tự pha, chu kỳ bước quá ngắn | Đổi thứ tự trong mảng, tăng chu kỳ bước, thêm tăng tốc mềm |
| Tốc độ thay đổi khi LCD cập nhật | Tạo xung bằng delay trong vòng lặp | Chuyển sang Timer1 + ngắt |
| Motor và ULN2003/L298 rất nóng khi đứng yên | Vẫn cấp điện cuộn dây khi dừng | Xuất 0x00 ra các pha khi không cần giữ lực |
Không cắm, rút dây motor khi mạch đang có điện, nhất là với A4988, DRV8825.
12. Gợi ý đề tài và giới hạn của PIC16F877A với động cơ bước
PIC16F877A đủ dùng cho các đề tài: bàn xoay chụp ảnh sản phẩm 360°, rèm/cửa trượt mô hình, cơ cấu cấp phôi theo số bước, bơm định lượng bằng động cơ bước, máy quấn dây đếm vòng, đồng hồ kim dùng motor nhỏ. Với hai motor, mỗi motor dùng một nibble PORTD (ULN2003/L298) hoặc hai cặp STEP/DIR; một ngắt Timer1 có thể phục vụ cả hai bằng cách đếm chu kỳ riêng cho từng motor.
Giới hạn cần biết trước khi chọn PIC16F877A
- Không có dao động nội: luôn cần thạch anh.
- Tạo xung bằng phần mềm nên chạy nội suy nhiều trục đồng thời (như máy CNC 3 trục) rất vất vả; việc đó hợp với firmware GRBL trên vi điều khiển khác hoặc bo điều khiển chuyên dụng.
- Xung STEP tối đa thực tế trong ngắt khoảng vài kHz đến khoảng 10 kHz mỗi kênh, tùy độ dài hàm ngắt; đủ cho NEMA 17 vi bước thấp, không đủ cho vi bước 1/32 ở tốc độ cao.
- Nếu ứng dụng cần lực lớn, tốc độ cao và phản hồi vị trí (máy công nghiệp), PIC chỉ nên làm phần giao diện; phần chuyển động giao cho driver chuyên dụng hoặc motor servo có driver riêng nhận xung.
Cách chọn loại motor cho đề tài (PM nhỏ, hybrid NEMA 17, có hộp số) xem trang tổng quan động cơ bước; với motor 4 dây lưỡng cực cầm trên tay, quy trình tìm cặp cuộn và chạy lần đầu có ở bài điều khiển động cơ bước 4 dây.
13. Câu hỏi thường gặp về điều khiển động cơ bước dùng PIC16F877A
- Dùng thạch anh 4 MHz hoặc 8 MHz thay cho 20 MHz được không? Được. Với 4 MHz chọn config XT, với 8–20 MHz chọn HS. Phải sửa khai báo tần số trong code (
#use delay(clock=4M)hoặc_XTAL_FREQ) và tính lại giá trị Timer1, vì chu kỳ lệnh lúc này là 1 µs thay vì 200 ns. Ở 4 MHz, ADC nên dùng xung Fosc/8 trở lên để TAD không dưới 1,6 µs. - Vì sao code chạy đúng trong Proteus nhưng nạp vào mạch thật thì không chạy? Proteus bỏ qua nhiều điều kiện mà chip thật bắt buộc: tụ thạch anh, tụ lọc nguồn, config dao động đúng loại, LVP tắt, WDT tắt. Hãy kiểm tra lần lượt nguồn 5 V tại chân 11/32, điện áp chân MCLR (phải gần 5 V), config bits trong file .hex, rồi nạp thử chương trình nháy LED để chắc chip đã chạy trước khi gắn motor.
- PIC16F877A có điều khiển được driver TB6600 hay DM542 không? Có. Ngõ ra 5 V của PIC kéo được opto của driver: nối PUL+, DIR+ vào chân PIC, PUL−, DIR− về mass, không cần điện trở thêm vì 5 V là mức chuẩn của các driver này. Chỉ cần giữ xung STEP ở mức cao khoảng 5 µs trở lên và đặt DIR trước xung đầu tiên vài micro giây.
- Một PIC16F877A điều khiển được mấy động cơ bước? Về chân, PORTD và PORTC đủ cho bốn motor qua ULN2003/L298, hoặc nhiều hơn nếu dùng driver STEP/DIR. Giới hạn thật là thời gian xử lý trong ngắt: chạy đồng thời hai đến bốn motor ở tốc độ vừa phải là hợp lý; nhiều hơn nên chuyển sang vi điều khiển mạnh hơn hoặc dùng bo chuyên dụng.
- Nên viết code bằng CCS C, MikroC hay XC8? CCS C có nhiều hàm dựng sẵn (
output_d,read_adc,lcd.c) nên viết nhanh, hợp đồ án ngắn ngày. MikroC có thư viện LCD, ADC, phím rất gọn và trình cấu hình config trực quan. XC8 là trình biên dịch chính thức của Microchip trong MPLAB X, bản miễn phí đủ dùng, viết theo thanh ghi nên dễ chuyển sang PIC đời mới. - Có dùng module PWM của PIC16F877A để phát xung STEP được không? Chỉ khi cần tần số cao. Ở 20 MHz, PWM phần cứng không xuống được dưới khoảng 1.220 Hz và không tự đếm số xung, nên không khởi động motor từ tốc độ thấp và không định vị được. Dùng Timer1 với CCP Compare để tạo chu kỳ bước, mỗi ngắt phát một xung, vừa kiểm soát tốc độ vừa đếm được vị trí.
- Làm sao để động cơ quay đúng 90° hoặc đúng một số vòng rồi dừng? Tính số bước cần: số bước = góc / góc mỗi bước (đã tính vi bước). Motor 1,8° full step cần 50 bước cho 90°, vi bước 1/16 cần 800 bước. Trong hàm ngắt đếm từng bước, khi đủ thì tắt Timer1; nên có công tắc gốc để xác định vị trí 0 mỗi lần bật máy vì motor vòng hở không biết vị trí ban đầu.
- PICkit báo không tìm thấy chip hoặc đọc sai Device ID, xử lý thế nào? Kiểm tra thứ tự 5 dây ICSP (chân 1 PICkit có dấu tam giác là VPP), mạch đã có nguồn hoặc đã bật cấp nguồn từ PICkit, chân MCLR không có tụ lớn, RB6/RB7 không treo LED hay IC khác.
- Có thay PIC16F877A bằng PIC16F887 mà giữ nguyên mạch được không? Gần như được vì cùng sơ đồ chân 40 chân và cùng các cổng. Cần sửa code: PIC16F887 cấu hình analog bằng ANSEL/ANSELH thay cho ADCON1, có dao động nội 8 MHz (có thể bỏ thạch anh), config bits có tên khác.
- Vì sao vặn biến trở mà tốc độ motor đổi giật cục hoặc chỉ có vài nấc? Thường do chỉ đọc ADC 8 bit, ánh xạ thẳng giá trị vào hàm delay tính bằng mili giây (mỗi nấc 1 ms là quá thô ở tốc độ cao), hoặc ADC bị nhiễu. Đọc đủ 10 bit, tính chu kỳ theo micro giây qua Timer1, thêm tụ 100 nF tại chân AN0 và lấy trung bình vài lần đọc.
- LCD 16x2 chỉ hiện một hàng ô vuông đen, không ra chữ là do đâu? Hàng ô đen nghĩa là LCD có nguồn nhưng chưa được khởi tạo. Kiểm tra định nghĩa chân RS, E, D4–D7 trong thư viện có trùng với mạch không, chân RW đã nối mass chưa, độ trễ khởi tạo sau khi cấp nguồn, và chỉnh biến trở tương phản V0.
- Có dùng chân RB6, RB7 để điều khiển motor được không? Được sau khi nạp xong, nhưng không nên. Hai chân này là PGC, PGD của ICSP; treo ULN2003 hay driver lên đó dễ làm PICkit nạp lỗi, và mỗi lần nạp motor có thể giật. Nên để RB6, RB7 cho phím nhấn có trở kéo lên hoặc bỏ trống, dùng PORTD/PORTC cho motor.






