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を止めることなく複数の処理を適切な間隔で回すことができます。