Saya pikir penamaan yang tumpang tindih antara vektor dan pin membingungkan
Ini!
Alasannya ada 8 pin eksternal yang berbeda untuk vektor interupsi adalah untuk memudahkan tata letak PCB atau menggunakan pin yang berbeda jika ada konflik dengan fungsi pin lainnya.
Apakah saya benar dalam berpikir ... satu-satunya cara untuk menentukan pin mana yang menyebabkan interupsi adalah mencatat keadaan mereka setelah setiap interupsi dan membandingkan nilai sebelumnya dan saat ini dari semua pin yang diaktifkan di PCMSKn?
Cukup banyak, katakanlah Anda hanya peduli tentang PB0 (PCINT0) dan PB1 (PCINT1). Jadi perubahan pin memungkinkan mask PCMSK0 akan diatur ke 0x03.
// External Interrupt Setup
...
volatile u_int8 previousPins = 0;
volatile u_int8 pins = 0;
ISR(SIG_PIN_CHANGE0)
{
previousPins = pins; // Save the previous state so you can tell what changed
pins = (PINB & 0x03); // set pins to the value of PB0 and PB1
...
}
Jadi jika pins
0x01 Anda tahu itu PB0 ... Dan jika Anda perlu tahu apa yang berubah, Anda perlu membandingkannya previousPins
, persis seperti yang Anda pikirkan.
Perlu diingat dalam beberapa kasus, pins
mungkin tidak akurat jika pin telah berubah sejak interupsi tetapi sebelumnya pins = (PINB & 0x03)
.
Pilihan lain adalah menggunakan vektor interupsi terpisah dengan satu pin dari masing-masing vektor sehingga Anda tahu mana yang diubah. Sekali lagi, ini juga memiliki beberapa masalah, seperti prioritas interupsi dan sekali CPU memasuki ISR, global interrupt mengaktifkan bit I-bit
di SREG
akan dihapus sehingga semua interupsi lainnya dinonaktifkan, meskipun Anda dapat mengaturnya di dalam interupsi jika Anda inginkan, yang akan menjadi interupsi bersarang.
Untuk informasi lebih lanjut, lihat catatan aplikasi Atmel Menggunakan Interupsi Eksternal untuk Perangkat megaAVR.
Memperbarui
Ini adalah contoh kode lengkap yang baru saya temukan di sini .
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}