Ngắt trong Arduino là gì?
Ngắt trong Arduino là một hoạt động xảy ra bất ngờ và không thường xuyên trong quá trình chạy chương trình. Đây là những sự kiện ngoài sự kiện chính đang diễn ra. Ví dụ, bạn đặt hẹn giờ đồng hồ và đi ngủ… Bất ngờ đồng hồ reo, đây được xem là một sự kiện ngắt vì nó làm gián đoạn công việc đang diễn ra, tức là đang ngủ. Một ví dụ khác, bạn đang làm việc khi bất ngờ có người gọi điện để thông báo rằng bạn đã nhận được hàng và yêu cầu bạn đến lấy, đây cũng là một sự kiện ngắt.
Tại sao cần phải sử dụng ngắt trong Arduino và các vi điều khiển?
Trong Arduino và các vi điều khiển khác, mỗi lần chỉ có thể xử lý một lệnh. Chúng ta không thể xử lý nhiều lệnh cùng một lúc. Tuy nhiên, điều này không đồng nghĩa với việc một lệnh phải tương ứng với một việc. Hãy tưởng tượng, nếu bạn cần đếm một khoảng thời gian nhất định, thay vì phải nhìn chằm chằm vào đồng hồ để đếm thì bạn có thể sử dụng chức năng hẹn giờ. Đây là lập trình ngắt. Vi điều khiển có phần cứng hỗ trợ ngắt, giúp cho việc lập trình trở nên đơn giản hơn. Thay vì liên tục kiểm tra đầu vào, dữ liệu truyền đến hoặc một khoảng thời gian, mỗi khi có sự kiện ngắt xảy ra, phần cứng của vi điều khiển sẽ thông báo cho mã lập trình để xử lý. Điều này giúp cho quá trình lập trình trở nên dễ dàng hơn.
Sử dụng ngắt Timer trong Arduino
Đối với Arduino, ngắt Timer thường được sử dụng để đặt các khoảng thời gian nhất định, xuất xung tần số tùy chỉnh ra các chân số hay định thời gian kiểm tra dữ liệu truyền nối tiếp. Số lượng Timer phụ thuộc vào Board Arduino sử dụng. Với Arduino UNO, chúng ta có 3 Timer, Timer 0, Timer 1 và Timer 2.
Giới thiệu về Timer trong Arduino UNO
Arduino UNO sử dụng 3 Timer: Timer 0, 1 và 2. Các Timer này tăng giá trị dựa trên xung nhịp của Arduino. Khi bạn đặt giá trị ngắt, Timer sẽ tăng dần giá trị khi nhận xung nhịp và so sánh với giá trị được đặt trước. Khi hai giá trị bằng nhau, một sự kiện ngắt sẽ xảy ra.
- Timer 0 và Timer 2 là hai Timer 8 bit, có thể đếm từ 0 đến 255.
- Timer 1 là Timer 16 bit, có thể đếm từ 0 đến 65535.
Arduino UNO có xung nhịp là 16MHz, tương đương với 1/16000000s hoặc 63ns. Với giá trị xung nhịp này, Timer 0 và Timer 2 chỉ có thể đếm từ 0 đến 16 us và Timer 1 có thể đếm từ 0 đến 4 ms.
Sử dụng thư viện để lập trình ngắt
Để sử dụng ngắt trong Arduino, bạn cần đặt lệnh trong hàm setup(). Có một số thư viện được sử dụng để lập trình ngắt cho Timer 1 và Timer 3. Bạn có thể sao chép và đặt thư mục thư viện vào thư mục của Arduino IDE. Thư viện này bao gồm các hàm:
- initialize() // Khởi động ngắt Timer.
- start() // Khởi động lại sau khi sửa đổi.
- startBottom() // Cho Timer bắt đầu đếm lại từ giá trị 0.
- read() // Đọc giá trị hiện tại của Timer.
- stop() // Dừng Timer.
- attachInterrupt() // Thêm địa chỉ hàm để gọi khi xảy ra ngắt và bắt đầu đếm.
- detachInterrupt() // Hủy địa chỉ ngắt.
- pwm(char pin, int duty, long microseconds) // Băm xung ra chân pin với số chu kỳ là duty và độ rộng là microseconds.
- disablePwm(char pin) // Hủy băm xung.
Thư viện TimerOne: Link thư viện TimerOne
Thư viện TimerThree: Link thư viện TimerThree
Ví dụ sử dụng ngắt Timer
Dưới đây là một ví dụ sử dụng ngắt Timer để nháy LED mỗi 0.15s. Ví dụ này sử dụng biến chia sẻ giữa hàm ngắt và chương trình chính. Đầu tiên, chúng ta định nghĩa chân LED, biến LED_BUILTIN được sử dụng để chỉ định LED được gắn trên Board mạch. Ví dụ với Arduino UNO, LED_BUILTIN=13. Sau đó, chúng ta khởi tạo Timer 1 và đặt thời gian ngắt là 150000us (0.15s). Khi xảy ra ngắt, chương trình sẽ gọi hàm blinkLED() để nháy LED. Trong hàm blinkLED(), chúng ta sẽ thay đổi trạng thái của LED giữa LOW và HIGH. Cuối cùng, chương trình sẽ in ra số lần nháy LED qua Serial Monitor của Arduino.
const int led = LED_BUILTIN; // Định nghĩa chân LED
void setup(void) {
pinMode(led, OUTPUT);
Timer1.initialize(150000); // Khởi động ngắt, thời gian đặt là 0.15s
Timer1.attachInterrupt(blinkLED); // Khi xảy ra ngắt, gọi hàm blinkLED()
Serial.begin(9600);
}
int ledState = LOW;
volatile unsigned long blinkCount = 0;
void blinkLED(void) {
if (ledState == LOW) {
ledState = HIGH;
blinkCount = blinkCount + 1;
} else {
ledState = LOW;
}
digitalWrite(led, ledState);
}
void loop(void) {
unsigned long blinkCopy;
noInterrupts();
blinkCopy = blinkCount;
interrupts();
Serial.print("blinkCount = ");
Serial.println(blinkCopy);
delay(100);
}
Bài hướng dẫn này chỉ giới thiệu cách sử dụng ngắt và lập trình ngắt Timer với thư viện.