mbed(3) タイマ割込み

今回は割込みを使用した、ワンショットタイマ、インターバルタイマの使用法を確認しました。

●タイマと割込み

ワンショットタイマとは、起動したら、一定時間後に一度だけ作動するタイマです。割込みを使用する場合は、割込み処理が一度だけ発生します。一定時間後に何かを作動させる、または何かを停止させる、という場合に使用できます。

インターバルタイマは指定した周期で何度も起動するタイマです。割込みを使用する場合は一定周期で割込み処理が実行されます。時計の秒針のように一定時間ごとに動かすようなものに使用できます。

●ワンショットタイマの使い方

<インスタンス生成>

Timeout myTimer;        // ワンショットタイマ

インスタンスを作成します。ここではインスタンス名を”myTimer”としています。

<割込みハンドラ>

void myIsr(void) {
    // ToDo:割込み処理
}

割込みサービスルーチンです。ここでは関数名を”myIsr”としています。

<ハンドラ登録、タイマスタート>

myTimer.attach_us(myIsr, tim);

attach_us()の”myIsr”は割込みハンドラのアドレス、”tim”はタイマ時間で単位はμs。attach()にすると”tim”は秒で指定可能。attach_ms()は存在しないみたいです。登録と同時にタイマが起動します。

<タイマ停止(途中で止めたいとき)>

myTimer.detach();

まだ、タイマが作動していないとき、タイマ動作をキャンセルしたいときに使用します。

●インターバルタイマの使い方

インスタンスの生成部分が異なるだけで、使い方はワンショットタイマとほぼ同じです。インターバルタイマは停止させるまで、指定した周期で割込みが発生し続けます。

<インスタンス生成>

Ticker myTimer;        // インターバルタイマ

インスタンスを作成します。ここではインスタンス名を”myTimer”としています。

<割込みハンドラ>

void myIsr(void) {
    // ToDo:割込み処理
}

割込みサービスルーチンです。ここでは関数名を”myIsr”としています。

<ハンドラ登録、タイマスタート>

myTimer.attach_us(myIsr, tim);

attach_us()の”myIsr”は割込みハンドラのアドレス、”tim”はタイマ時間で単位はμs。attach()にすると”tim”は秒で指定可能。attach_ms()は存在しないみたいです。登録と同時にタイマが起動します。

<タイマ停止(途中で止めたいとき)>

myTimer.detach();

繰り返し動作を止めたいときに使用します。

●ワンショットタイマ割込みの使用例

最初にLED1点灯させ、LED2を2秒後にワンショットタイマの割込みで点灯させます。

#include "mbed.h"

// test ワンショットタイマ割込

Timeout osTimer;        // ワンショットタイマ

DigitalOut Led1(LED1);  // LED1
DigitalOut Led2(LED2);  // LED2

// ワンショットタイマ 割込みハンドラ
void isrDlyOn(void) {
    Led2 = 1;               // 点灯
}

int main() {
    Led1 = 1;
    Led2 = 0;

    // ワンショットタイマ 割込み設定、タイマスタート
    osTimer.attach_us(isrDlyOn, 2000000);
    // osTimer.detach(); タイマ停止

    while(1) {}
}

●インターバルタイマ割込みの使用例

最初にLED1を点灯させ、500ms周期でLED2点滅させます。attach_ms()というのは無いみたいです。

#include "mbed.h"

Ticker intvTimer;       // インターバルタイマ

DigitalOut Led1(LED1);  // LED1
DigitalOut Led2(LED2);  // LED2

// インターバルタイマ 割込みハンドラ
void isrInterval(void) {
    Led2 = !Led2;               // 状態反転
}

int main() {
    Led1 = 1;

    // インターバルタイマ 割込み設定、タイマスタート
    intvTimer.attach_us(isrInterval, 500000);  // 500ms

    // intvTimer.detach(); タイマ停止

    while(1) {}
}

●複合1

ワンショットタイマとインターバルタイマが同時使用できるか確認します。

LED1はすぐに点灯、LED2は100ms周期で点滅、2.3s後にLED3点灯させます。

#include "mbed.h"

Timeout osTimer;        // ワンショットタイマ
Ticker intvTimer;       // インターバルタイマ

DigitalOut Led1(LED1);  // LED1
DigitalOut Led2(LED2);  // LED2
DigitalOut Led3(LED3);  // LED3

// インターバルタイマ 割込みハンドラ
void isrInterval(void) {
    Led2 = !Led2;               // 状態反転
}

// ワンショットタイマ 割込みハンドラ
void isrDlyOn(void) {
    Led3 = 1;               // 点灯
}

int main() {
    Led1 = 1;

    // インターバルタイマ 割込み設定、タイマスタート
    intvTimer.attach_us(isrInterval, 100000);   // 100ms

    // ワンショットタイマ 割込み設定、タイマスタート
    osTimer.attach_us(isrDlyOn, 2300000);       // 2.3s

    while(1) {}
}

●複合2

複数のタイマが使えるか確認します。インターバルタイマ2個、ワンショットタイマ1個で確認します。

#include "mbed.h"

Timeout osTimer;        // ワンショットタイマ
Ticker intvTimer;       // インターバルタイマ
Ticker intvTimer2;      // インターバルタイマ2

DigitalOut Led1(LED1);  // LED1
DigitalOut Led2(LED2);  // LED2
DigitalOut Led3(LED3);  // LED3
DigitalOut Led4(LED4);  // LED4

// インターバルタイマ 割込みハンドラ
void isrInterval(void) {
    Led2 = !Led2;               // 状態反転
}

// インターバルタイマ2 割込みハンドラ
void isrInterval2(void) {
    Led4 = !Led4;               // 状態反転
}

// ワンショットタイマ 割込みハンドラ
void isrDlyOn(void) {
    Led3 = 1;               // 点灯
}

int main() {
    Led1 = 1;

    // インターバルタイマ 割込み設定、タイマスタート
    intvTimer.attach_us(isrInterval, 100000);   // 100ms

    // インターバルタイマ 割込み設定、タイマスタート
    intvTimer2.attach_us(isrInterval2, 300000);   // 300ms

    // ワンショットタイマ 割込み設定、タイマスタート
    osTimer.attach_us(isrDlyOn, 2300000);       // 2.3s

    while(1) {}
}

●複合3

インターバルタイマ 3個、ワンショット1個で試してみました。問題なし。

#include "mbed.h"

Timeout osTimer;        // ワンショットタイマ
Ticker intvTimer;       // インターバルタイマ
Ticker intvTimer2;      // インターバルタイマ
Ticker intvTimer3;      // インターバルタイマ

DigitalOut Led1(LED1);  // LED1
DigitalOut Led2(LED2);  // LED2
DigitalOut Led3(LED3);  // LED3
DigitalOut Led4(LED4);  // LED4

// インターバルタイマ 割込みハンドラ
void isrInterval(void) {
    Led2 = !Led2;               // 状態反転
}

// インターバルタイマ 割込みハンドラ
void isrInterval2(void) {
    Led4 = !Led4;               // 状態反転
}

// インターバルタイマ 割込みハンドラ
void isrInterval3(void) {
    Led1 = !Led1;               // 状態反転
}

// ワンショットタイマ 割込みハンドラ
void isrDlyOn(void) {
    Led3 = 1;               // 点灯
}

int main() {
    // インターバルタイマ 割込み設定、タイマスタート
    intvTimer.attach_us(isrInterval, 100000);   // 100ms

    // インターバルタイマ2 割込み設定、タイマスタート
    intvTimer2.attach_us(isrInterval2, 300000);   // 300ms

    // インターバルタイマ3 割込み設定、タイマスタート
    intvTimer3.attach_us(isrInterval3, 120000);   // 120ms

    // ワンショットタイマ 割込み設定、タイマスタート
    osTimer.attach_us(isrDlyOn, 2300000);       // 2.3s

    while(1) {}
}

●インターバルタイマはいくつまで使えるのだろ?

今回、3つまで実際に作動するのが確認できましたが、いくつまで使えるかはネットで少し調べましたが、わかりませんでした。

そこで、実際に作動させていませんが、インスタンスだけたくさん作ってコンパイルエラーが出ないか確認しました。16個まで試しましたが、コンパイルエラーにはなりませんでした。

実際にうごくかどうかわかりませんが、ちゃんとインスタンスが作成できていれば、割込みベクタが確保されているということなので、有効だと思います。コンパイルエラーにならずにインスタンスの作成に失敗しているという可能性もありますが、無効ならコンパイラがチェックしてくれると思います。

ARMのマニュアルで割込みベクタのリザーブ領域などを調べればわかると思いますが、ARMのWEB見てみましたが、マニュアルがどこにあるかわからなかったので現在保留です。今のところ、2~3個使えれば足りそうなので。

32ビットマイコンなので、リソースは豊富にあるのでしょう。

コメントは受け付けていません。