void do_nothing(void) {Serial.println("nada");}
void (*interrupt_service_routines[])(void) = {
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing,
do_nothing
};
volatile uint8_t inputs[3];
void register_ISR(uint32_t interrupt_mask, void (*isr)(void)) {
PCICR = 0x0; // disable pin change interrupts while we're making changes
int8_t i = 0;
do {
if (interrupt_mask & (1L << i)) {
interrupt_service_routines[i] = isr;
if (i < 8) { // D0 -- D7, PCINT2
PCMSK2 |= (1 << (i - 0));
inputs[2] = PIND & PCMSK2;
PCIFR = 0x4; // write a 1 to *only* the relevant PCIFR bit
} else if (i < 14) { // D8 -- D13, PCINT0
PCMSK0 |= (1 << (i - 8));
inputs[0] = PINB & PCMSK0;
PCIFR = 0x2;
} else { // D14 -- D19, PCINT1
PCMSK1 |= (1 << (i - 14));
PCIFR = 0x1;
}
}
} while (++i < 32);
PCICR = 0x7; // re-enable pin change interrupts
}
void deregister_ISR(uint32_t interrupt_mask) {
PCICR = 0x0; // disable pin change interrupts while we're making changes
int8_t i = 0;
do {
if (interrupt_mask & (1 << i)) {
interrupt_service_routines[i] = do_nothing;
if (i < 8) { // D0 -- D7, PCINT2
PCMSK2 &= ~(1 << (i - 0));
} else if (i < 14) { // D8 -- D13, PCINT0
PCMSK0 &= ~(1 << (i - 8));
} else { // D14 -- D19, PCINT1
PCMSK1 &= ~(1 << (i - 14));
}
}
} while (++i < 32);
PCICR = 0x7; // re-enable pin change interrupts
}
#define RUN_ISR(first_pin, last_pin, io_bank, new_inputs) do { \
uint8_t change = (new_inputs) ^ inputs[(io_bank)]; \
switch (change) { \
case 0x01: \
interrupt_service_routines[(first_pin) + 0](); \
break; \
case 0x02: \
interrupt_service_routines[(first_pin) + 1](); \
break; \
case 0x04: \
interrupt_service_routines[(first_pin) + 2](); \
break; \
case 0x08: \
interrupt_service_routines[(first_pin) + 3](); \
break; \
case 0x10: \
interrupt_service_routines[(first_pin) + 4](); \
break; \
case 0x20: \
interrupt_service_routines[(first_pin) + 5](); \
break; \
case 0x40: \
interrupt_service_routines[(first_pin) + 6](); \
break; \
case 0x80: \
interrupt_service_routines[(first_pin) + 7](); \
break; \
default: \
int8_t i = (first_pin); \
do { \
if (change & 0x1) { \
interrupt_service_routines[i](); \
} \
change >>= 1; \
i++; \
} while (i <= (last_pin)); \
} \
inputs[(io_bank)] = (new_inputs); \
} while (0)
ISR(PCINT0_vect) {
RUN_ISR(8, 13, 0, PINB & PCMSK0);
}
ISR(PCINT1_vect) { // handle pin change interrupt for D14 to D19 here
RUN_ISR(14, 19, 1, PINC & PCMSK1);
}
ISR(PCINT2_vect) { // handle pin change interrupt for D0 to D7 here
RUN_ISR(0, 7, 2, PIND & PCMSK2);
}
#define COWPI_PB 0 //!< Index for arrays to access PINB/DDRB/PORTB and PCMSK0
#define D8_D13 0 //!< Alias of COWPI_PB corresponding to pins D8-D13 on the Arduino Uno & Arduino Nano
#define COWPI_PC 1 //!< Index for arrays to access PINC/DDRC/PORTC / PCMSK1
#define A0_A5 1 //!< Alias of COWPI_PC for corresponding to pins D14-D19 (A0-A5) on the Arduino Uno & Arduino Nano
#define D14_D19 1 //!< Alias of COWPI_PC for corresponding to pins D14-D19 (A0-A5) on the Arduino Uno & Arduino Nano
#define A0_A7 1 //!< Alias of COWPI_PC for corresponding to pins D14-D19 (A0-A5) on the Arduino Uno & Arduino Nano
#define D14_D21 1 //!< Alias of COWPI_PC for corresponding to pins D14-D19 (A0-A5) on the Arduino Uno & Arduino Nano
#define COWPI_PD 2 //!< Index for arrays to access PIND/DDRD/PORTD and PCMSK2
#define D0_D7 2 //!< Alias of COWPI_PD for corresponding to pins D0-D7 on the Arduino Uno & Arduino Nano
void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
pinMode(17, INPUT_PULLUP);
pinMode(13,OUTPUT); // LED
Serial.begin(9600);
register_ISR(1L << 10, foo);
register_ISR(1L << 15, foo);
register_ISR(1L << 17, foo); // ??
register_ISR(1L << 9, quux);
register_ISR(1L << 12, bar);
register_ISR(1L << 6, xyzzy);
register_ISR(1L << 3, xyzzy);
register_ISR(1L << 2, quux);
}
void loop() {
// Nothing needed
}
void foo(void) {
Serial.println("foo");
}
void bar(void) {
Serial.println("bar");
}
void xyzzy(void) {
Serial.println("xyzzy");
}
void quux(void) {
Serial.println("quux");
}