Arduino-ミリ秒指定で処理を連続実行する

Arduino関連の質問掲示板などを見ると、Sleepを使ってタイミングを調整し何かしらの処理をし、かつその間に別の処理をさせるにはどうしたらいいかという内容の質問が良く出てくる。

例えばこんなの。

void loop()
{
    // なんかの処理
    Sleep(1000);
    // なんかの処理
    Sleep(500);
    // 上の繰り返し
}

上のような処理にすれば、「何かの処理」を指定した時間間隔で処理されることになるわけだが、当然のごとく、loop内のどっかで別の処理、例えばスイッチの監視などをリアルタイム性を持たせて実行させるには、loop内のSleepを別の処理に変えかつ処理を分割して、監視の合間にloop内の処理を実行させる必要が出てくる。

RTOSが利用できる環境、例えばESP32-IDFなどでは、スレッドを起こして処理をさせればいいのだけどArduino環境ではそういうこともできず、初心者はこの段階でどうすればいいのかわからなくなってしまう。

そこで、上のような処理をすることに特化したクラスを作成してみた。

概要

関数とその関数を実行したのちSleepする時間を組で持たせたコンテナクラスという位置づけ。
コンテナと言ってもvector等で個数管理しているのではなく、テンプレート引数でコンテナ数を設定できるようにしている。

利用する際には以下の様な実装になる。

  • setupメソッド内
    push_backメソッドで、処理する関数とSleep時間のペアを登録していく。
  • loopメソッド内
    startメソッドでpush_backの登録順に関数処理を行い、doCheckメソッドで継続処理と、登録されているものが完了したかどうかの判断をしている。

実際のサンプルは以下の様になる。

#include <Arduino.h>
#include <FunctionAndSleep.hpp>

Take4::FunctionAndSleep<5> func;
bool started = false;

void setup()
{
    Serial.begin(115200);
    func.push_back([] {
        Serial.print("hoge1 ");
        Serial.println(func.millisec());},
        1000); // 待機時間1000ms
    func.push_back([] {
        Serial.print("hoge2 ");
        Serial.println(func.millisec());},
        100); // 待機時間100ms
}

void loop()
{
    auto input = Serial.read();
    if (input >= 0) {
        // 何か入力があったら先頭から開始するようにする
        started = false;
    }
    if (!started) {
        func.start();
        started = true;
    }
    else {
        if (!func.doCheck()) {
            // 登録している処理が終了したので、サイドstartさせるためにフラグのリセットを行っている
            started = false;
        }
    }
}

処理関数にはラムダ式を記述できるので、そこまで可読性が悪くなるということはないと思う。

実装

実際のソースはesp32用ライブラリとして作成しているgithubに追加している。
一応、arduino/esp32で利用できるようにはなっている。

Sleep相当の処理は、時間の差分で調整するようにしてある。
単純な引き算なのでタイマーが一周まわったらどうするの?という問題はあるのだけど。
(同じような処理を過去行って、問題なく動いたような気はしているのだけど)

librarieseesp32/FunctionAndSleep.hpp at master · take4blue/librarieseesp32
Contribute to take4blue/librarieseesp32 development by creating an account on GitHub.

今回、実装するところで苦労したのがArduinoにSTLがないということ。
ちょっと知らなかった。

なので今回ustdというライブラリを使用している。
名前空間がustdになるのと実装がちょっと違うようなのだけどとりあえず目的とする動作は達成している。

コメント

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