First some notes:
- Use the
volatilequalifier for variables that are shared between interrupt service routines and the main program. - Using interrupts for switches is probably a poor design choice.
- On ESP32, you can use FunctionalInterrupt with a lambda functions.
That being said, you could solve this using compile-time recursion to generate an arbitrary number of functions:
struct FSwitch {
FSwitch(uint8_t pin) : pin(pin) {}
const uint8_t pin;
volatile bool changed = false;
volatile bool value = false;
};
FSwitch fswitches[] {27, 33, 15, 32, 14};
volatile bool sFlag = false;
void IRAM_ATTR run_isr(unsigned interrupt) {
auto &fs = fswitches[interrupt];
fs.changed = true;
fs.value = digitalRead(fs.pin);
sFlag = true;
}
using isr_func_ptr = void(*)(void);
template <class T, size_t N>
constexpr size_t len(const T(&)[N]) { return N; }
template <unsigned NumISR>
static constexpr isr_func_ptr get_isr_N(unsigned interrupt) {
return interrupt == NumISR - 1
? []() IRAM_ATTR { run_isr(NumISR - 1); }
: get_isr_N<NumISR - 1>(interrupt); // Compile-time tail recursion
}
template <>
constexpr isr_func_ptr get_isr_N<0>(unsigned) {
return nullptr; // Base case
}
isr_func_ptr get_isr(unsigned interrupt) {
return get_isr_N<len(fswitches)>(interrupt);
}
void setup() {
Serial.begin(115200);
for (auto &fs : fswitches) {
pinMode(fs.pin, INPUT);
fs.value = digitalRead(fs.pin); // initial state of each switch
}
for (unsigned i = 0; i < len(fswitches); ++i)
attachInterrupt(digitalPinToInterrupt(fswitches[i].pin), get_isr(i), CHANGE);
}
This generates a different function for each interrupt automatically:
If you compile these functions,
template <unsigned NumISR>
static constexpr isr_func_ptr get_isr_N(unsigned interrupt) {
return interrupt == NumISR - 1
? []() IRAM_ATTR { run_isr(NumISR - 1); }
: get_isr_N<NumISR - 1>(interrupt); // Compile-time tail recursion
}
template <>
constexpr isr_func_ptr get_isr_N<0>(unsigned) {
return nullptr; // Base case
}
/* constexpr */ isr_func_ptr get_isr(unsigned interrupt) {
return get_isr_N<len(fswitches)>(interrupt);
}
the compiler generates the following anonymous functions for you, and the get_isr function returns a function pointer to them.
get_isr_N<5u>(unsigned int)::{lambda()#1}::_FUN():
entry sp, 32
movi.n a10, 4
call8 _Z7run_isrj
retw.n
get_isr_N<4u>(unsigned int)::{lambda()#1}::_FUN():
entry sp, 32
movi.n a10, 3
call8 _Z7run_isrj
retw.n
get_isr_N<3u>(unsigned int)::{lambda()#1}::_FUN():
entry sp, 32
movi.n a10, 2
call8 _Z7run_isrj
retw.n
get_isr_N<2u>(unsigned int)::{lambda()#1}::_FUN():
entry sp, 32
movi.n a10, 1
call8 _Z7run_isrj
retw.n
get_isr_N<1u>(unsigned int)::{lambda()#1}::_FUN():
entry sp, 32
movi.n a10, 0
call8 _Z7run_isrj
retw.n
get_isr(unsigned int):
entry sp, 32
l32r a8, .LC3
beqi a2, 4, .L6
l32r a8, .LC4
beqi a2, 3, .L6
l32r a8, .LC1
beqi a2, 2, .L6
l32r a8, .LC0
beqi a2, 1, .L6
l32r a8, .LC2
movi.n a9, 0
movnez a8, a9, a2
.L6:
mov.n a2, a8
retw.n