割り込み / InterruptInクラスとTimeoutクラスとを併用してスイッチ入力をディバウンスする

pp.41-45

今度はスイッチ入力をディバウンスしたうえで前回と同じことをする。外部割り込みがかかったらTimeoutクラスのインスタンスをコールし、一定時間が経過してタイムアウトしたら(=バウンスが収まったら)何かを実行する。

テキストは、コピーコンストラクタと代入演算子とを禁止するためのコードも記述しているが、そのしくみも必要性もわからないためとりあえず省いた。

f:id:ti-nspire:20200909082013p:plain:h315

サンプルファイル

#include "mbed.h"
#include "PUSHBUTTON_Class.h"

BusOut leds(PA_10, PB_3, PB_5, PB_4);
bool   triggered(false);

void when_triggered(){
    triggered = true;
}

int main(){
    // PC_3への入力をディバウンスする。
    // PC_3を内部PullUpする。
    // PC_3への入力信号のFALL時にディバウンスする。
    // バウンスが収まったらwhen_triggered()函数を実行する。
    // バウンスの継続時間が5ms以内であると假定する。
    PUSHBUTTON_Class sw(PC_3, PullUp, FALL, &when_triggered, 5ms);

    uint8_t i = 0;
    while(true){
        if(triggered){
            triggered = false;
            leds = ~(i++); // マイコン側をsinkにしている。
        }
    }
 
    return 0;
}

ヘッダーファイル

#include "mbed.h"

#ifndef PUSHBUTTON_CLASS_H
#define PUSHBUTTON_CLASS_H

const uint8_t FALL = 0;
const uint8_t RISE = 1;

class PUSHBUTTON_Class{
typedef Kernel::Clock::duration_u32 chrono_t;
private:
    InterruptIn _intin;   // ここでMbed InterruptInクラスをインスタンス化しておく。
    Timeout     _timeout; // ここでMbed Timeoutクラスをインスタンス化しておく。

    uint8_t   _fall_rise; // fall時、rise時のどちらでディバウンスするかを格納しておくための変数。
    void     (*_fp)();    // ディバウンス後に実行する函数(ここでは返値なし、引数なし)へのポインタ。
    chrono_t  _time;      // バウンスを無視する時間(タイムアウト時間)を格納する変数。

    void _ISR_InterruptIn(); // 外部割り込み時に実行するISR。
    void _ISR_Timeout();     // Timeout割り込み時に実行するISR。
    
public:
    // コンストラクタ
    PUSHBUTTON_Class(PinName pin, PinMode mode, uint8_t fall_rise, void (*fp)(), chrono_t time);
};

#endif

実装ファイル

#include "PUSHBUTTON_Class.h"

void PUSHBUTTON_Class::_ISR_InterruptIn(){                                   // 外部割り込みがかかったら、
    _intin.disable_irq();                                                    // 一旦外部割り込みを無効化して、
    _timeout.attach(callback(this, &PUSHBUTTON_Class::_ISR_Timeout), _time); // タイムアウト割り込みをコールして、
}
void PUSHBUTTON_Class::_ISR_Timeout(){ // タイムアウトしたら(バウンスが収まったら)、
    if(_intin==_fall_rise){            // ピン変化の方向と実際のピンの値とが同じであったら、
        _fp();                         // 所望の函数を実行して。
    }
    _intin.enable_irq();               // 再度外部割り込みを有効化して次のピン変化に備える。
}

// コンストラクタ()
PUSHBUTTON_Class::PUSHBUTTON_Class(PinName pin, PinMode mode, uint8_t fall_rise, void (*fp)(), chrono_t time): 
    // ここで初期化しておく。
    _intin(pin, mode),
    _fall_rise(fall_rise),
    _fp(fp),
    _time(time)
{   // ピン変化割り込み時に実行するISRをattachする。
    if(fall_rise==RISE){_intin.rise(callback(this, &PUSHBUTTON_Class::_ISR_InterruptIn));}
    else               {_intin.fall(callback(this, &PUSHBUTTON_Class::_ISR_InterruptIn));}
}