Cách sử dụng ngắt Timer trên Arduino Uno

posted in: Vi điều khiển | 0

Thông thường khi lập trình cho arduino các bạn chỉ chạy 1 tiến trình trong hàm loop. Nhưng với các dự án phức tạp hơn sẽ đòi hỏi phải dùng ngắt Timer. لعبه القمار روليت Hay dùng nhất là để đọc giá trị cảm biến sau 1 khoảng thời gian cố định, ví dụ như 2s đọc giá trị cảm biến 1 lần mà không làm ảnh hưởng đến chương trình chính.

Hôm nay mình sẽ giới thiệu cách dùng ngắt timer để chạy 3 tiến trình đồng thời. Cụ thể hơn là nháy 3 đèn led độc lập với nhau.

Arduino Uno hỗ trợ 3 Timer

  • Timer0: Được dùng cho hàm delay(), millis(). Để không làm xung đột chương trình thì các bạn không nên dùng Timer này.
  • Timer1: 16-Bit.
  • Timer2: 8-Bit.

1. Cách dùng ngắt Timer 1

Hình 1. Chọn xung nhịp cho Timer1

Tần số thạch anh trên Arduino uno là 16MHz. Mình muốn đèn Led1 sáng 1. اربح المال من الانترنت 5s rồi tắt 1.5s thì chọn giá trị

TCNT1 = 2^16 – 1.5s*(16*10^6)/1024 = 42099

Ở đây 2^16 là Timer 16 bit và 1024 là prescaler, giá trị này bạn có thể chọn theo bảng trên.

2. Cách dùng ngắt Timer 2

Hình 1. Chọn xung nhịp cho Timer2

Mình muốn đèn Led2 sáng 0.3s rồi tắt 0.3s thì làm như sau.

Giả sử mình chọn giá trị để Timer 2 có chu kì lặp là 0. بلاك جاك 21 01s

TCNT2 = 2^8 – 0.01s*(16*10^6)/1024 = 100

Ở đây 2^8 là Timer 8 bit và 1024 là prescaler, giá trị này bạn có thể chọn theo bảng trên.

Để có được 0.3s sáng tắt thì ta lặp lại ngắt 0.3s/0.01s = 30 lần.

Đã xong phần tính toán giờ ta chuyển qua phần lập trình




3. Lập trình

Mình sẽ cho LED0 sáng tắt 1s ở hàm loop(), LED1 sáng tắt 1.5s ở chương trình ngắt Timer1 và LED2 sáng tắt 0.3s ở chương trình ngắt Timer2. Chúng ta đã có 3 tiến trình chạy độc lập với nhau.

Để cấu hình cho Timer thì ta dùng đoạn lệnh sau

  cli(); //Tắt ngắt toàn cục
  TCCR1A = 0; //Reset Timer1
  TCCR1B = 0;      
  TIMSK1 = 0;
  //Setup Timer1
  TCCR1B |= (1 << CS12)|(1 << CS10) ; //Chọn prescaler 1024 CS12=1,CS10=1 xem bảng phía trên
  TCNT1= 42099; //Giá trị tính toán phía trên
  TIMSK1 |= (1 << TOIE1); //Overflow interrupt enable
  sei(); //Cho phép ngắt toàn cục

Khai báo chương trình ngắt của Timer

ISR (TIMER1_OVF_vect) //Chương trình ngắt Timer1
{ 

}

Toàn bộ chương trình

#include <avr/interrupt.h>
#define LED1 11
#define LED2 12
#define LED0 13
int dem; // Giá trị lặp lại
ISR (TIMER2_OVF_vect) //Chương trình ngắt Timer2
{
  dem++;
  if (dem == 30){ //Đủ 30 lần thì thực hiện đảo tín hiệu chân LED2
    dem = 0;
    digitalWrite(LED2,!digitalRead(LED2));
  }
  TCNT2 = 100;
}
ISR (TIMER1_OVF_vect) //Chương trình ngắt Timer1
{ 
  digitalWrite(LED1,!digitalRead(LED1)); //Sáng tắt LED1
  TCNT1= 42099;
}
void setup() {
  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  cli(); //Tắt ngắt toàn cục
  TCCR1A = 0; //Reset Timer1
  TCCR1B = 0;      
  TIMSK1 = 0;
  //Setup Timer1
  TCCR1B |= (1 << CS12)|(1 << CS10) ; //Chọn prescaler 1024 CS12=1,CS10=1 xem bảng phía trên
  TCNT1= 42099; //Giá trị tính toán phía trên
  TIMSK1 |= (1 << TOIE1); //Overflow interrupt enable
 
  TCCR2A = 0; //Reset Timer2
  TCCR2B = 0;      
  TIMSK2 = 0;
  //Setup Timer2
  TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20) ; //Chọn prescaler 1024 CS22=1,CS21=1, CS20=1 xem bảng phía trên
  TCNT2 = 100; //Giá trị tính toán phía trên
  TIMSK2 |= (1 << TOIE2); //Overflow interrupt enable
  sei(); //Cho phép ngắt toàn cục
  dem = 0; //Khởi động giá trị lặp lại Timer2
}

void loop() {
  digitalWrite(LED0,!digitalRead(LED0)); //Sáng tắt LED0
  delay(1000);
}

Trả lời

Email của bạn sẽ không được hiển thị công khai.