Để tiếp thu bài học này tốt nhất, bạn nên ôn lại:
- Bài 7: Đi-ốt & Mạch chỉnh lưu nguồn DC (Hiểu nguyên lý mạch chỉnh lưu cầu và IC ổn áp 7805).
- Bài 9: Transistor đóng ngắt & khuếch đại (Nắm vững nguyên lý đóng cắt của MOSFET công suất lớn).
- Bài 15: Kiến trúc MCU & Giao tiếp GPIO (Hiểu cách đọc-sửa-ghi thanh ghi DDR/PORT).
Trong bài học trước, chúng ta đã lập trình cho
MCU nhấp nháy LED bằng cách sử dụng vòng lặp trễ
vô dụng delay() để đốt thời gian của
CPU. Cách tiếp cận này khiến CPU bị
block hoàn toàn — nó không thể làm bất kỳ việc gì khác trong lúc chờ đợi, kể cả việc đọc nút nhấn hay xử
lý khẩn cấp.
Để giải quyết bài toán đa nhiệm và đáp ứng tức thời trong các hệ thống nhúng thực tế, hai vũ khí quan trọng nhất là Ngắt phần cứng (Interrupts) và Bộ định thời (Timers). Bài học cuối cùng này sẽ phân tích chi tiết cơ chế hoạt động của chúng và hướng dẫn bạn ghép nối một hệ thống điều khiển LED thông minh (Smart LED Station) hoàn chỉnh — dự án Capstone kết hợp toàn bộ kiến thức của cả series.
1. Cơ chế Ngắt phần cứng (Hardware Interrupts)
1.1 Polling (Truy vấn vòng) vs Interrupt (Ngắt)
Hãy tưởng tượng bạn đang đợi một bưu phẩm giao đến nhà:
- Polling (Truy vấn vòng): Cứ 5 phút bạn lại chạy ra mở cửa kiểm tra xem shipper đến chưa. Việc này tốn cực kỳ nhiều công sức (CPU chu kỳ máy) và bạn không thể làm việc khác tập trung.
- Interrupt (Ngắt): Bạn ngồi làm việc bình thường. Khi shipper đến, họ bấm chuông (tín hiệu ngắt). Bạn dừng việc đang làm, ra nhận hàng (thực thi hàm ngắt), rồi quay lại bàn làm việc tiếp tục công việc trước đó.
Trong MCU, ngắt là một tín hiệu phần cứng từ các ngoại vi bên ngoài (như nút nhấn nhấn xuống) hoặc bên trong (như bộ định thời báo tràn) yêu cầu CPU tạm dừng chương trình chính ngay lập tức để chuyển sang xử lý một tác vụ ưu tiên cao gọi là ISR.
Quy trình xử lý ngắt của CPU diễn ra như sau:
- Một sự kiện ngắt xảy ra (ví dụ: chân INT0 nhận cạnh xuống từ nút nhấn).
- CPU hoàn thành lệnh hiện tại đang thực thi.
- CPU tự động lưu địa chỉ của lệnh tiếp theo (Program Counter) vào vùng nhớ ngăn xếp (Stack).
- CPU tra cứu bảng Vector ngắt (Interrupt Vector Table) để tìm địa chỉ của hàm ISR tương ứng và nhảy tới đó thực thi.
-
Khi kết thúc ISR (lệnh
RETI- Return from Interrupt), CPU khôi phục địa chỉ từ Stack và quay lại chạy chương trình chính bình thường.
1.2 Cạm bẫy dội phím cơ học (Contact Bounce) & Giải pháp lọc thông thấp RC
Khi bạn nhấn một nút cơ học, các tiếp điểm kim loại bên trong không tiếp xúc hoàn hảo ngay lập tức. Do tính chất đàn hồi, chúng sẽ nảy và chạm vào nhau nhiều lần trong khoảng $1\text{ ms} - 10\text{ ms}$ trước khi ổn định.
Hiện tượng này gọi là Dội phím (Contact Bounce). Đối với mắt người thì nút nhấn như ăn ngay lập tức, nhưng đối với CPU chạy hàng triệu lệnh mỗi giây, nó sẽ nhìn thấy hàng chục lần bật/tắt liên tục và kích hoạt ISR ngắt ngoài hàng chục lần chỉ cho một lần nhấn nút.
Để khử dội phím, chúng ta có hai phương án:
- Chống dội bằng phần cứng (Hardware Debounce): Cho tín hiệu qua mạch lọc thông thấp RC (Rơ-le/Nút nhấn $\rightarrow$ Điện trở $R$ $\rightarrow$ Tụ điện $C$ mắc song song xuống GND). Hằng số thời gian $\tau = R \cdot C$ (thường chọn $10\text{ k}\Omega$ và $100\text{ nF} \Rightarrow \tau = 1\text{ ms}$) hoạt động như một bộ giảm chấn làm trơn toàn bộ các xung nhọn dội phím tần số cao.
- Chống dội bằng phần mềm (Software Debounce): Khi phát hiện ngắt kích hoạt, kiểm tra lại trạng thái chân sau một khoảng thời gian chờ ngắn ($20\text{ ms} - 50\text{ ms}$) để xác nhận phím nhấn thực sự ổn định trước khi xử lý logic.
Tra cứu chi tiết về cách cấu hình ngắt ngoài và quản lý tài nguyên ngắt tại Datasheet ATmega328P (Microchip).
2. Bộ định thời (Timer) và Bộ chia tần (Prescaler)
2.1 Tại sao cần bộ định thời phần cứng?
Trong Bài 15, để tạo trễ ta dùng vòng lặp trống bắt CPU chờ. Điều này lãng phí chu kỳ máy.
Bộ định thời (Timer) là một khối phần cứng đếm xung nhịp độc lập nằm bên ngoài CPU. Nó
hoạt động như một đồng hồ đếm tự động: cứ sau một số chu kỳ clock hệ thống nhất định, thanh ghi đếm (ví dụ
TCNT0) sẽ tự cộng thêm 1 đơn vị, hoàn toàn không tốn tài nguyên xử lý của CPU.
2.2 Bộ chia tần (Prescaler) và cách hoạt động
Nếu clock hệ thống của vi điều khiển AVR chạy ở tần số $16\text{ MHz}$, nghĩa là tụ thạch anh dao động 16,000,000 lần mỗi giây. Một Timer 8-bit chỉ có thể đếm tối đa từ $0$ đến $255$. Nếu đếm trực tiếp xung clock hệ thống, thời gian tối đa để tụ đếm tràn chỉ là:
$$t_{max} = \frac{256}{16 \times 10^6\text{ Hz}} = 16\ \mu\text{s}$$
Khoảng thời gian này quá ngắn để tạo các ứng dụng thực tế (như nhấp nháy LED chu kỳ $1\text{ giây}$). Để kéo dài thời gian đếm, người ta đưa xung nhịp qua một bộ chia tần gọi là Prescaler. Prescaler sẽ chia tần số clock hệ thống xuống các tỉ lệ như $8, 64, 256, 1024$ trước khi đưa vào bộ đếm.
Nếu chọn Prescaler $= 1024$, tần số cấp cho Timer chỉ còn:
$$f_{timer} = \frac{16\text{ MHz}}{1024} = 15625\text{ Hz}$$
Mỗi bước đếm của Timer lúc này tốn $\frac{1}{15625\text{ Hz}} = 64\ \mu\text{s}$. Thời gian đếm tràn 8-bit tăng lên thành $64\ \mu\text{s} \times 256 \approx 16.38\text{ ms}$. Nếu sử dụng Timer 16-bit (đếm tới $65535$), thời gian tràn tối đa sẽ lên tới hơn $4.19\text{ giây}$.
Để tạo ra một ngắt định thời với tần số ngõ ra mong muốn $f_{target}$ ở chế độ Clear Timer on Compare Match (CTC), ta nạp giá trị vào thanh ghi so sánh $OCR0A$ theo công thức:
$$OCR0A = \frac{f_{osc}}{2 \cdot \text{Prescaler} \cdot f_{target}} - 1$$
Trong đó $f_{osc}$ là tần số clock hệ thống ($16\text{ MHz}$). Giá trị $OCR0A$ tính ra bắt buộc phải là một số nguyên dương nhỏ hơn $256$ đối với Timer 8-bit.
Đề bài: Sử dụng Timer 8-bit trên vi điều khiển chạy thạch anh $16\text{ MHz}$, hãy tính giá trị cần nạp vào thanh ghi so sánh $OCR0A$ và chọn Prescaler thích hợp để tạo ra ngắt định thời có tần số $f = 1\text{ kHz}$ (chu kỳ $1\text{ ms}$).
1. Thử với bộ chia tần Prescaler $= 64$:
$$OCR0A = \frac{16 \times 10^6\text{ Hz}}{1000\text{ Hz} \cdot 64} - 1 = 250 - 1 = 249$$
2. Kiểm tra tính hợp lệ: Giá trị $249$ là số nguyên và nhỏ hơn $256$, do đó hoàn toàn phù hợp để nạp vào thanh ghi so sánh 8-bit.
Kết luận: Cấu hình Timer chạy với bộ chia tần Prescaler $= 64$ và nạp giá trị $249$ vào thanh ghi $OCR0A$. Mỗi khi Timer đếm từ $0$ lên $249$ (tốn đúng $1\text{ ms}$), một ngắt so sánh sẽ được kích hoạt.
3. Tạo xung PWM bằng phần cứng (Hardware PWM)
Ở Bài 14, chúng ta tạo xung PWM bằng cách sử dụng IC 555 analog hoặc lập trình mềm (bật chân HIGH, chạy vòng lặp delay, hạ chân LOW). Cách tạo xung bằng phần mềm cực kỳ không chính xác vì CPU chỉ cần bị ngắt bởi tác vụ khác là độ rộng xung sẽ bị méo ngay lập tức.
Hardware PWM giải quyết triệt để vấn đề này. Bản thân khối Timer trong MCU có các cổng logic so sánh ngõ ra chuyên dụng liên kết trực tiếp với chân vật lý (như chân OC0A / OC0B):
- Bộ đếm $TCNT0$ tăng dần liên tục từ $0$ đến $255$.
- Thanh ghi so sánh ngõ ra $OCR0A$ lưu giá trị ngưỡng mong muốn (tương ứng với Duty Cycle).
- Khi $TCNT0 < OCR0A$: phần cứng tự động kéo chân OC0A lên mức HIGH.
- Khi $TCNT0 \ge OCR0A$: phần cứng tự động kéo chân OC0A xuống mức LOW.
- Chu kỳ lặp lại liên tục và chạy hoàn toàn tự động bằng phần cứng. CPU chỉ cần ghi đè trị số vào $OCR0A$ một lần duy nhất khi muốn thay đổi độ sáng LED hoặc tốc độ động cơ, sau đó có thể ngủ hoặc xử lý việc khác.
Nhiều người mới lập trình thường viết code liên tục cập nhật giá trị OCR0A trong vòng lặp
while(1) không có trễ. Việc ghi đè giá trị so sánh giữa chu kỳ đếm của Timer có thể làm
mất sự kiện Compare Match, dẫn đến chân ngõ ra bị treo ở mức cao hoặc mức thấp ngoài ý muốn (hiện
tượng glitch). Giải pháp là cấu hình chế độ Double Buffering (phần cứng tự động cập
nhật giá trị mới từ thanh ghi đệm vào thanh ghi hoạt động của OCR0A chỉ tại thời điểm Timer đếm chạm
đỉnh hoặc đáy).
4. Dự án tổng hợp cuối series (Smart LED Station)
Để khép lại lộ trình Điện Tử & Vi Mạch, chúng ta sẽ thiết kế một hệ thống điều khiển công suất LED thông minh (Smart LED Station) kết hợp tất cả các khối linh kiện đã học từ các bài học trước:
- Khối nguồn xoay chiều: Điện lưới hạ áp qua máy biến áp (Bài 6) xuống $12\text{V AC}$.
- Khối chỉnh lưu & Lọc: Cầu đi-ốt chỉnh lưu toàn chu kỳ kết hợp tụ lọc hóa $1000\ \mu\text{F}$ (Bài 7) biến áp AC thành nguồn $15\text{V DC}$ nhấp nháy mượt.
- Khối ổn áp tuyến tính: Sử dụng IC ổn áp 7805 (Bài 7) hạ áp từ nguồn DC xuống $5\text{V DC}$ ổn định để nuôi vi điều khiển MCU.
- Khối vi điều khiển: MCU đọc trạng thái nút nhấn kích ngắt ngoài qua chân INT0 (Bài 16). Mỗi lần nhấn nút, ngắt được kích hoạt để thay đổi các chế độ hoạt động (Mode).
- Khối công suất: Chân Hardware PWM của MCU (OC0A) điều khiển cực Gate của N-Channel MOSFET IRF540N (Bài 9) đóng ngắt tải dòng lớn.
- Khối tải tiêu thụ: Dải LED siêu sáng đấu nối tiếp với điện trở hạn dòng (Bài 2).
5. Sơ đồ mạch nguyên lý của bộ thử nghiệm giả lập (Simulator Circuit)
Để hiểu rõ các tín hiệu hiển thị trên Oscilloscope ảo của trình giả lập bên dưới, đây là sơ đồ đấu nối phần cứng chi tiết của hệ thống:
- Mạch ngắt ngõ vào (INT0 / PD2): Nút nhấn cơ học được kết nối nối tiếp với nguồn $5\text{V}$. Chân ngắt ngoài INT0 được kéo xuống đất (GND) thông qua một điện trở kéo xuống (pull-down) $R_{pd} = 10\ \text{k}\Omega$ để đảm bảo trạng thái ổn định LOW ($0\text{V}$) khi không nhấn nút. Tụ lọc chống dội $C_f = 100\text{ nF}$ mắc song song với điện trở tạo thành bộ lọc thông thấp RC phần cứng.
- Mạch công suất ngõ ra (OC0A / PD6): Chân phát xung PWM cứng (OC0A) của vi điều khiển được nối vào cực Gate của MOSFET kênh N (IRF540N) qua điện trở hạn dòng $100\ \Omega$. MOSFET đóng vai trò là một khóa điện tử tốc độ cao điều khiển nguồn điện $12\text{V}$ chạy qua dải đèn LED công suất lớn.
5. Smart LED & MCU Virtual Lab: Trình giả lập ngắt & định thời
Trình giả lập bên dưới mô phỏng hoạt động thời gian thực của vi điều khiển. Bạn có thể chọn cơ chế chống dội phím (Debounce) để quan sát sự méo dạng điện áp tại ngõ vào và xem cách ngắt ngoài INT0 chuyển đổi chu kỳ làm việc PWM cấp cho LED.
MCU Registers
Mã lệnh thực thi C / ISR Handler
Bạn muốn tự tay xây dựng một thiết bị điện tử chạy được ngoài đời thực? Hãy bước vào trang thực hành đặc biệt:
6. Trắc nghiệm kiểm tra
Câu 1: Tại sao ngắt Hardware PWM lại vượt trội hơn hoàn toàn so với Software PWM tự tạo bằng vòng lặp delay?
Câu 2: Nếu một vi điều khiển chạy xung nhịp clock hệ thống là $8\text{ MHz}$, sử dụng Timer 8-bit và chọn bộ chia tần Prescaler $= 256$. Tần số đếm của bộ đếm Timer lúc này là bao nhiêu?
Câu 3: Hiện tượng dội phím cơ học (Contact Bounce) nếu không được xử lý chống dội bằng phần cứng hoặc phần mềm sẽ gây ra hậu quả gì cho mạch kích ngắt ngoài?