Có hai loại ngắt "thay đổi pin". Các ngắt ngoài, trong đó có hai trên Uno. Chúng được gọi là 0 và 1, tuy nhiên chúng đề cập đến chân kỹ thuật số 2 và 3 trên bảng. Chúng có thể được cấu hình để phát hiện tăng, giảm, thay đổi (tăng hoặc giảm) hoặc THẤP.
Ngoài ra, đó là các ngắt "thay đổi pin", giúp phát hiện sự thay đổi trạng thái chân trong bất kỳ trong số 20 chân (A0 đến A5 và D0 đến D13). Các ngắt thay đổi pin này cũng dựa trên phần cứng , vì vậy, bản thân chúng sẽ nhanh như các ngắt bên ngoài.
Cả hai loại đều hơi khó sử dụng ở cấp độ đăng ký, nhưng IDE tiêu chuẩn bao gồm Đính kèm (n) và DetachInterrupt (n) giúp đơn giản hóa giao diện với các ngắt ngoài. Bạn cũng có thể sử dụng Thư viện thay đổi mã pin để đơn giản hóa các ngắt thay đổi pin.
Tuy nhiên, chỉ đạo thư viện trong một phút, chúng ta có thể thiết lập rằng các ngắt thay đổi pin có thể nhanh hơn hoặc nhanh hơn các ngắt bên ngoài. Đối với một điều, mặc dù các ngắt thay đổi pin hoạt động trên các lô chân, bạn không phải kích hoạt toàn bộ lô. Ví dụ: nếu bạn muốn phát hiện các thay đổi trên chân D4, điều này sẽ đủ:
Ví dụ phác thảo:
ISR (PCINT2_vect)
{
// handle pin change interrupt for D0 to D7 here
if (PIND & bit (4)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of PCINT2_vect
void setup ()
{
// pin change interrupt (example for D4)
PCMSK2 |= bit (PCINT20); // want pin 4
PCIFR |= bit (PCIF2); // clear any outstanding interrupts
PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7
pinMode (4, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Thử nghiệm của tôi chỉ ra rằng phải mất 1.6 nút để pin "thử nghiệm" (chân 5) phản ứng với thay đổi trên chân ngắt (chân 4).
Bây giờ nếu bạn thực hiện phương pháp đơn giản (lười biếng?) Và sử dụng Đính kèm () bạn sẽ thấy kết quả chậm hơn, không nhanh hơn.
Mã ví dụ:
void myInterrupt ()
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of myInterrupt
void setup ()
{
attachInterrupt (0, myInterrupt, CHANGE);
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Việc này cần 3.7 Thay đổi để kiểm tra pin thử nghiệm, nhiều hơn rất nhiều so với 1.6. Tại sao? Bởi vì mã trình biên dịch phải tạo cho trình xử lý ngắt "chung" phải lưu mọi thanh ghi có thể hiểu được (đẩy chúng) khi vào ISR, sau đó khôi phục chúng (bật chúng) trước khi quay lại. Thêm vào đó là chi phí của một cuộc gọi chức năng khác.
Bây giờ chúng ta có thể giải quyết vấn đề đó bằng cách tránh Đính kèm () và tự thực hiện:
ISR (INT0_vect)
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of INT0_vect
void setup ()
{
// activate external interrupt 0
EICRA &= ~(bit(ISC00) | bit (ISC01)); // clear existing flags
EICRA |= bit (ISC00); // set wanted flags (any change interrupt)
EIFR = bit (INTF0); // clear flag for interrupt 0
EIMSK |= bit (INT0); // enable it
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Đó là tốc độ nhanh nhất trong số tất cả tại 1.52, - có vẻ như một chu kỳ đồng hồ đã được lưu ở đâu đó.
Tuy nhiên, có một cảnh báo cho các ngắt thay đổi pin. Chúng được bó theo từng đợt, vì vậy nếu bạn muốn có nhiều ngắt trên nhiều chân, bạn cần kiểm tra bên trong ngắt mà cái nào đã thay đổi. Bạn có thể làm điều đó bằng cách lưu trạng thái pin trước đó và so sánh nó với trạng thái pin mới. Điều này không nhất thiết phải đặc biệt chậm, nhưng bạn càng cần kiểm tra nhiều chân thì càng chậm.
Các đợt là:
- A0 đến A5
- D0 đến D7
- D8 đến D13
Nếu bạn chỉ muốn thêm một vài chân ngắt, bạn có thể tránh mọi thử nghiệm bằng cách chỉ chọn sử dụng ghim từ các lô khác nhau (ví dụ: D4 và D8).
Thêm chi tiết tại http://www.gammon.com.au/interrupts