3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

loop()を止めるな!

Last updated at Posted at 2021-03-24

Arduino でプログラミングをするときに、つい使ってしまうのが
delay()
です。
もちろん、Lチカ程度のごく単純なプログラムであれば何の問題もありません。
むしろ積極的に使っていいと思います。一秒間隔でLEDを点滅させたいのであれば

   :
void loop() {
  digitalWrite(LED,HIGH);
  delay(500);
  digitalWrite(LED,LOW);
  delay(500);
}

こんなので十分です。
では、「一秒間隔でLEDを点滅させつつ加速度を測定する」という場合はどうでしょうか?

   :
void loop() {
  digitalWrite(LED,HIGH);
  delay(500);
  digitalWrite(LED,LOW);
  delay(500);

  int accX = Acc.getX(); // 加速度を取得
}

これでは1秒おきにしか加速度を取得することができません。
そこで、

TmDeltaTime.h
# ifndef __TMDELTATIME_H__
# define __TMDELTATIME_H__
# include <Arduino.h>

/*** TmDeltaTime
 * 一定時間ごとにコールバックを返すクラス ***/
class TmDeltaTime{
    public:
    TmDeltaTime(){
      m_trigWorkArr=NULL;
    };
    ~TmDeltaTime(){
      if(m_trigWorkArr!=NULL){
        free(m_trigWorkArr);
        m_trigWorkArr=NULL;
      }
    };

    /***
     * Setup セットアップ内で呼ぶ
     *  _maxTrig:最大タイマートリガ数(デフォルト:8)    ***/
    void Setup(int8_t _maxTrig=8){
      m_trigNum = (_maxTrig>0)?_maxTrig:1;
      m_trigWorkArr = (TrigWork*)malloc(sizeof(TrigWork)*m_trigNum);
      for(int i=0;i<m_trigNum;++i){
        m_trigWorkArr[i].func=NULL;
        m_trigWorkArr[i].timer=0;
      }
      m_currentMillis = millis();
      m_deltaMillis = 0;
    }

    /*** 
     * AddTrig 一定時間ごとに呼ばれる関数を追加
     * _pFunc:コールバック関数
     * uint32_t: コールバック関数が呼ばれる周期[ミリ秒]
     * 返値: 成功でトリガーId,失敗で-1    ***/
    int8_t AddTrig(void (*_pFunc)(uint32_t), uint32_t _trigTime){
      for(int8_t trigId=0;trigId<m_trigNum;++trigId){
        if(m_trigWorkArr[trigId].func==NULL){
          m_trigWorkArr[trigId].func = _pFunc;
          m_trigWorkArr[trigId].trigTime = _trigTime;
          m_trigWorkArr[trigId].timer = 0;
          return trigId;
        }
      }
      return -1;
    }

    /** RemoveTrig 一定時間ごとに呼ばれる関数を削除
     * _trigId:コールバック関数
     * 返り値: 成功したらtrue   ***/
     bool RemoveTrig(int8_t _trigId){
      if(m_trigWorkArr[_trigId].func!=NULL){
        m_trigWorkArr[_trigId].func = NULL;
        m_trigWorkArr[_trigId].trigTime = 0;
        m_trigWorkArr[_trigId].timer = 0;
        return true;
      }
      return false;
    }

    /*** Update メインループ内で呼ぶ
     * 返り値: 前回呼ばれてからの時間[ミリ秒] ***/
    uint32_t Update(){
        uint32_t nowMillis = millis();
        m_deltaMillis = nowMillis - m_currentMillis;
        m_currentMillis = nowMillis;
        for(int8_t i=0;i<m_trigNum;++i){
          if(m_trigWorkArr[i].func!=NULL){
            m_trigWorkArr[i].timer += m_deltaMillis;
            if(m_trigWorkArr[i].timer >= m_trigWorkArr[i].trigTime){
              m_trigWorkArr[i].func(m_trigWorkArr[i].timer);
              m_trigWorkArr[i].timer -= m_trigWorkArr[i].trigTime;
            }
          }
        }
        return m_deltaMillis;
    };
    
    /*** GetRemainTrigNum 使用できる残トリガー数を取得
     * 返り値: 使用できる残トリガー数 ***/
    int8_t GetRemainTrigNum(){
        int8_t cnt = 0;
        for(int8_t i=0;i<m_trigNum;++i)
          if(m_trigWorkArr[i].func!=NULL)
            cnt++;
        return cnt;
    }
    private:
    struct TrigWork{
      void (*func)(uint32_t);
      uint32_t trigTime;
      uint32_t timer;
    } _TrigWork;

    TrigWork* m_trigWorkArr;
    int8_t m_trigNum;
    uint32_t m_currentMillis;
    uint32_t m_deltaMillis;
};
# endif // __TMDELTATIME_H__

こんなのを用意しておき、

main.cpp
# include <Arduino.h>
# include "tmDeltaTime.h"
  :
TmDeltaTime* pTdt= new TmDeltaTime(); // newが嫌なら最初から実体化させておく

void evCntA(uint32_t deltaTime){ //LED用
      // 0.5秒ごとに行う処理
}
void evCntB(uint32_t deltaTime){ // 加速度センサー用
      // 0.1秒ごとに行う処理
}
    :
void setup() {
  pTdt->Setup();
  pTdt->AddTrig(evCntA,500); // 0.5秒ごとにevCntA()を呼ぶ
  pTdt->AddTrig(evCntB,100); // 0.1秒ごとにevCntB()を呼ぶ
    :
}

void loop() {
  pTdt->Update(); // loop内で毎回呼ぶ
  delay(10); // 一定かつ適度な間隔で回す
}

こんな感じでコールバックで処理を行えば
loopを止めることなく複数の処理を適切な間隔で回すことができます。

3
4
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?