みなさん、Arduinoやってますか〜?
私は、Arduinoそのものもやってるし、ESP32でも、そしてRaspberryPI picoでも、お世話になっています。
とはいうものの、Arduino IDEから最近は、VSCode & PlatformIO に移行しつつありますが。
さて、Arduinoで、ハードウェア割り込みを使う時に、
って使ってますよね。
たとえば、ロータリーエンコーダの入力とか(loopで処理してもいいけど、なんか無駄な感じが・・・)、まあ少し複雑なプログラム書くときには必須ですよね。
で、普通だと、
void _isr(){ //割り込みコード } void begin(){ attachInterrupt(PIN, _isr, CHANGE); }
みたいに書くんだと思いますが、
少しクラスとか使ってたり、同じ割り込みを複数で使いたかったりすると、
void _isr(){
//割り込みコード
// ここでPIN_Aと、PIN_Bで処理分けたいけど・・・
}
void begin(){
attachInterrupt(PIN_A, _isr, CHANGE);
attachInterrupt(PIN_B, _isr, CHANGE);
}
こん感じで、1つの割り込みで、複数の処理させたいとか、やりたいですよね。
なので、例えば、
struct Param {
unsigned char pin;
int otherData;
};
void _isr(const Param* param){
if(param->pin == PIN_A){
// PIN_Aの処理
}else if(param->pin == PIN_A){
// PIN_Bの処理
}
}
Param a = {PIN_A, 100};
Param b = {PIN_B, 200};
void begin(){
attachInterruptWithParam(PIN_A, _isr, &a, CHANGE);
attachInterruptWithParam(PIN_B, _isr, &b, CHANGE);
}
みたいに、1つだけでも引数渡せれば、みたいな処理したくなりますよね。
クラスメソッド渡すときとかでも、
class Sample {
private:
int count = 0;
public:
static void onChange(Sample* _this){
// 変更された!
_this->count++;
}
public:
void begin(){
attachInterruptWithParam(PIN_A, onChange, this, CHANGE);
}
}
こんな感じで使えたり。
で、いろいろ試行錯誤して、とりあえず〜、って感じでできたのが、これ。
まあ、要は渡される変数を、固定領域に格納しておいて、attachInterruptの中は、Lambda式で記載することで、そしてマクロを活用することで、実現しています。
※固定領域では256個程度の割り込みは格納できるようにしているけど、まあそこまで使わないよね、という想定。
※また、__COUNT__マクロをつかちゃってるので、他で利用している場合は要注意です。
#define __MAX_ATTACH_INTERRUPT_WITH_PARAM 256
void* __attachInterruptParam[__MAX_ATTACH_INTERRUPT_WITH_PARAM];
#define attachInterruptWithParam(PIN, CB, P, F) \
{if((__COUNTER__ / 3) < __MAX_ATTACH_INTERRUPT_WITH_PARAM){ \
__attachInterruptParam[(__COUNTER__ - 1) / 3] = P; \
attachInterrupt(PIN, [](){ \
CB(static_cast<typeof(p)>(__attachInterruptParam[(__COUNTER__ - 2) / 3])); \
}, F); \
}}
コピペして使えるレベルだとは思いますが、
ある程度は理解して使っていただければと。