Arduino UNO R4 でタイマー割り込みを使う

Arduino

タイマー割り込みライブラリFspTimer

Arduino_LED_Matrixの中身を見ていたら、Arduino UNO R4で簡単にタイマー割り込みを使えるライブラリ FspTimer が存在することに気付きました。簡単な使い方をまとめておきます。

とにかくサンプル

Arduinoを買ったら誰もが最初に試す『Lチカ』を、FspTimerを使用して作ってみました。

スケッチ

C++
#include "FspTimer.h"

FspTimer _timer;

#define LEDPIN 13

void callbackfunc(timer_callback_args_t *arg)
{
  static bool led=false;
  if(led){
    digitalWrite(LEDPIN, HIGH);
  }else{
    digitalWrite(LEDPIN, LOW);
  }
  led = !led;
}

void setup() {
  pinMode(LEDPIN, OUTPUT);
 
  uint8_t type;
  int8_t ch = FspTimer::get_available_timer(type);
  if (ch < 0) {
    return;
  }
  _timer.begin(TIMER_MODE_PERIODIC, type, ch, 1.0f, 50.0f, callbackfunc, nullptr);
  _timer.setup_overflow_irq();
  _timer.open();
  _timer.start();
}

void loop(){
 
}

プログラム解説

ライブラリのインクルード
C++
#include "FspTimer.h"

タイマー割り込みを使うために、まず “FspTimer.h” をインクルードします。私の環境では個別にインストールした記憶はありませんので、R4初接続時に自動的にインストールされていたのだと思います。

まぁ Arduino_LED_Matrix のアニメーション機能で使用しているので、LEDマトリクスでアニメーション出来ているなら確実にインストールされています。

FspTimerクラスのインスタンスを生成
C++
FspTimer _timer;

FspTimerクラスのインスタンスを生成します。ここでは _timer という名前のインスタンス(グローバル変数)にしています。

Lチカのための変数・定数
C++
#define LEDPIN 13

ボード上のLEDが接続されているpin番号を定数LEDPINとして設定しています。Lチカ動作のためのもので、タイマーとは直接関係ありません。

コールバック関数を定義する
C++
void callbackfunc(timer_callback_args_t *arg)
{
  static bool led=false;
  if(led){
    digitalWrite(13, HIGH);
  }else{
    digitalWrite(13, LOW);
  }
  led = !led;
}

コールバック関数は、タイマー割り込みによってシステムから自動的に呼び出される関数です。つまり、この関数の中に『タイマー割り込みによって定期的に実行したい処理』を記述します。

コールバック関数の使用は以下の通りです。

引数
意味
timer_callback_args_t*システムから呼び出されるとき、FspTimer.begin()関数で設定された値が代入される

FspTimer.begin()関数内で

返却値

void(なし)

動作

タイマー割り込みの設定の際『どの関数を呼び出すか』を指定するようになっているので、コールバック関数には任意の名前を付けることが出来ます。ここでは callbackfunc() という身も蓋もない名前にしていますが(笑)。

内容も任意です。『必ずやらなければ行けないこと』『返さなければいけない値』などはありません。単に『タイマー割り込みによって実行したい処理』を書くだけです。

この例では、この関数が1回呼び出されるたびに LEDPIN の出力ををHIGH→LOW→HIGH→LOW→…と交互に切り替えるようになっています。

Lチカのための初期化
C++
void setup() {
  pinMode(LEDPIN, OUTPUT);
 

setup()関数の最初、pinMode()関数は、ボード上のLEDが接続された入出力端子LEDPINを出力に設定しています。Lチカ動作のための設定です。

使用可能なタイマーチャンネルおよびタイマータイプの取得
C++
void setup() {
  pinMode(LEDPIN, OUTPUT);
 
  uint8_t type;
  int8_t ch = FspTimer::get_available_timer(type);
  if (ch < 0) {
    return;
  }
  _timer.begin(TIMER_MODE_PERIODIC, type, ch, 1.0f, 50.0f, callbackfunc, nullptr);
  _timer.setup_overflow_irq();
  _timer.open();
  _timer.start();
}

ここからがいよいよタイマー割り込みのための設定です。

まず、複数あるタイマーチャンネル/タイマータイプのうち、現在利用可能なものを取得します。取得のためには FspTimer::get_available_timer() 関数を使用します。

書式
C++
uint8_t FspTimer::get_available_timer(uint8_t type)
引数
名前意味
typeuint8_t&利用可能なタイマータイプ

形式としては引数ですが、変数の参照渡しにより、引数として記述した変数に結果が代入されて返却されます。従って引数には『uint8_t型の変数名』しか記述できません。get_available_timer()関数では返却すべき値がタイマータイプタイマーチャンネルの2つあるためこのような仕様になっています。

返却値
意味
int8_t利用可能なタイマーチャンネル

返却値は、利用可能なタイマーチャンネルの番号を表します。
利用可能なタイマーが存在しない場合は負の値が返却されます。

23行目のif分ではタイマーチャンネルchの値をチェックしています。もしタイマーチャンネルとして負の値が返却されていた場合は利用可能なタイマーがないということなので、それ以降のタイマー初期化処理を中止してsetup()関数を終了します。

タイマーの設定
C++
void setup() {
  pinMode(LEDPIN, OUTPUT);
 
  uint8_t type;
  int8_t ch = FspTimer::get_available_timer(type);
  if (ch < 0) {
    return;
  }
  _timer.begin(TIMER_MODE_PERIODIC, type, ch, 1.0f, 50.0f, callbackfunc, nullptr);
  _timer.setup_overflow_irq();
  _timer.open();
  _timer.start();
}

タイマーの設定には、FspTimer.begin()関数を使用します。

書式
C++
bool FspTimer.begin(timer_mode_t mode, uint8_t type, uint8_t ch, float freq, float duty, GPTimerCbk_f func, void* ctx)
引数
名前意味
modetimer_mode_tタイマーの動作モード
typeuint8_tタイマーのタイプ
chuint8_tタイマーのチャンネル
freqfloat割り込み周波数(Hz)。
『1.0f』のように、float型と解釈される形式で記述する
dutyfloatデューティ比(%)。
『50.0f』のように、float型と解釈される形式で記述する
funcGPTimerCbk_fコールバックする関数
ctxvoid*コールバック関数に与える引数。不要ならnullptrを与えておく。

・タイマーの動作モードに設定可能な値には、以下のような定数(正確にはenum型)が定義されています(r_timer_api.h内)。

名前意味
TIMER_MODE_PERIODIC定期モード
割り込みの後、再度タイマーが開始する
TIMER_MODE_ONE_SHOTワンショットモード
割り込み後にタイマーが停止する
TIMER_MODE_PWMPWMモード
タイマーがノコギリ波PWMを生成
TIMER_MODE_ONE_SHOT_PULSEワンショットパルスモード
ノコギリ波ワンショットパルスモード
TIMER_MODE_TRIANGLE_WAVE_SYMMETRIC_PWM対称三角波PWMモード
TIMER_MODE_TRIANGLE_WAVE_ASYMMETRIC_PWM非対称三角波PWMモード
TIMER_MODE_TRIANGLE_WAVE_ASYMMETRIC_PWM_MODE3非対称三角波PWMモード3

今回は、とりあえず定期モード TIMER_MODE_PERIODIC を憶えておけばよいと思います。これで一定時間ごとに割り込み処理を行うことが出来ます。

・type と ch は、get_available_time()関数で取得したものをそのまま渡せば良いでしょう。

・freq は割り込みの発生周波数(Hz)、つまり1秒間に割り込みが発生する回数を記述します。たとえば10.0を指定すると1秒間に10回、つまり0.1秒に1回の割り込みが発生することになります。
型はfloatなので、『1』ではなく『1.0f』のように記述しておいた方が無難です(末尾の『f』がfloat型の定数であることを示しています)。

また、この値はあまり小さく(割り込み間隔を長く)できません。0.75(約1.33秒)あたりが限界で、それより小さい値(長い時間)を指定するとまったく動かなくなります。

・dutyはデューティ比を記述します。
これも型はfloatなので、50%を指定したい場合は『50.0f』のように記述しておいた方が無難です。
定期モードではあまり意味がない値のような気もしますが、とりあえず50.0fと指定しておけば良いでしょう。

・funcはコールバック関数(タイマー割り込みで呼び出したい関数)です。型としては『関数へのポインタ』ですが、要は定義した関数の名前(引数のカッコ部分は書かず、関数名だけ)を記述します。

・ctxはコールバック関数の呼び出し時に与えたい引数を記述します。ポインタの形で渡されます。引数が不要な場合は nullptr (ヌルポインタ)を記述しておくとよいでしょう。

返却値

初期化に成功するとture、失敗するとfalseのbool値です。

このプログラムでは、1秒に1回、繰り返し割り込み処理が発生するように設定しています。

割り込みの有効化
C++
void setup() {
  pinMode(LEDPIN, OUTPUT);
 
  uint8_t type;
  int8_t ch = FspTimer::get_available_timer(type);
  if (ch < 0) {
    return;
  }
  _timer.begin(TIMER_MODE_PERIODIC, type, ch, 1.0f, 50.0f, callbackfunc, nullptr);
  _timer.setup_overflow_irq();
  _timer.open();
  _timer.start();
}

設定した割り込みを有効化するには、setup_overflow_irq()関数を使用します。

書式
C++
void FspTimer.setup_overflow_irq()
割り込み処理の開始
C++
void setup() {
  pinMode(LEDPIN, OUTPUT);
 
  uint8_t type;
  int8_t ch = FspTimer::get_available_timer(type);
  if (ch < 0) {
    return;
  }
  _timer.begin(TIMER_MODE_PERIODIC, type, ch, 1.0f, 50.0f, callbackfunc, nullptr);
  _timer.setup_overflow_irq();
  _timer.open();
  _timer.start();
}

あとはタイマーチャンネルを有効化・タイマーの開始です。とりあえず定期実行をしたいだけなら、FspTimer.open()関数とFspTimer.start()関数を実行すればよい、と憶えておけば充分です。

書式
C++
bool FspTimer.open()
bool FspTimer.start()
今回もloop()内では何もしない
C++
void loop(){
 
}

setup()関数内でタイマー割り込みの設定が終わっているので、loop()内には何も記述しなくてもLチカします。

loop()内に処理を記述すると、タイマー割り込みとloop()内の処理が相互に無関係に実行されます。

実行結果

ボード上のLED(L)が、点灯(1秒)→消灯(1秒)→点灯(1秒)→消灯(1秒)→…を繰り返します。

まとめ

・Arduino UNO R4で一定時間ごとに割り込み処理を行うためには、FspTimerライブラリを使用すると簡単

コメント

タイトルとURLをコピーしました