0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ESP32でワンショットタイマーを使う(esp32-arduino v3系)

Posted at

背景

esp32に限らず、タイマー割り込みを使う際はずーっと同じタイマー間隔で延々とタイマーを入れ続けることが多いかと思います。

でも例えば「2回点滅してちょっと休む」を繰り返すLEDチカチカとかをやろうとすると、同じ時間で繰り返すではやりづらい...※ちょっとロジックを工夫すれば同じ間隔でのタイマーでもできますけど、なんか気持ち悪い

その場合、繰り返しのタイマーを使うのではなく、こんな感じでワンショットタイマーを繰り返し実行したいのです。

  • 1回だけのタイマー割り込み(ワンショットタイマー)をセットする
  • 時間が経過しタイマーが弾ける(タイマー処理が実行される)
  • そのタイマー処理内で、再度時間を指定してタイマー割り込みをセット ※このタイミングで任意のタイマー時刻」をセットする
  • 次のタイマー処理が実行される
  • ※以降、繰り返し

しかし、ESP32でワンショットタイマーを使うという記事が見つからず、逆にうまく行かない、という例を見つけるぐらいでした。

実際うまく行ったのか?

結論としては、以下となりました。

  • esp32-arduino V3系ではOK
  • esp32-arduino V2系ではNG

esp32-arduino V2系で本当はやりたかったのですが、今の所 V3系でしかできませんでした。
なぜかV2系では、2回目の設定したタイマー処理が実行されません。

esp32-V3系でワンショットタイマーが動作したプログラム

動作確認時のesp32-arduinoのバージョンはv3.0.7です(2024/12/29 時点の最新)。
esp32-arduino_v3.png

esp32_oneshot_timer.ino
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

volatile uint32_t isrCounter = 0;
volatile uint32_t lastIsrAt = 0;

volatile bool timer_3s = false; // チェック時の値でタイマー時間を決める。false:1秒、true:3秒をセット

void ARDUINO_ISR_ATTR onTimer(){
  uint32_t timer_val;
  portENTER_CRITICAL_ISR(&timerMux);
  isrCounter = isrCounter + 1;
  lastIsrAt = millis();

  // タイマー時間を決める(1秒 or 3秒)
  timer_3s = !timer_3s;
  if(timer_3s) {
    timer_val = 3000000;
  } else {
    timer_val = 1000000;
  }
  timerRestart(timer); // タイマーを再スタート。★★★この行が重要★★★
  timerAlarm(timer, timer_val, false, 0); // タイマーを再設定
  
  portEXIT_CRITICAL_ISR(&timerMux);
  xSemaphoreGiveFromISR(timerSemaphore, NULL);
}

void setup() {
  Serial.begin(115200);
  timerSemaphore = xSemaphoreCreateBinary();

  timer = timerBegin(1000000);
  timerAttachInterrupt(timer, &onTimer);
  timerAlarm(timer, 1000000, false, 0); // 第3引数をfalse指定で、繰り返し無し=ワンショットタイマー。その際は第4引数は無効
}

void loop() {
  if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
    uint32_t isrCount = 0, isrTime = 0;
    portENTER_CRITICAL(&timerMux);
    isrCount = isrCounter;
    isrTime = lastIsrAt;
    portEXIT_CRITICAL(&timerMux);

    // タイマー割り込みが実行された時刻を表示
    Serial.print("onTimer no. ");
    Serial.print(isrCount);
    Serial.print(" at ");
    Serial.print(isrTime);
    Serial.println(" ms");
  }
}

まとめ

本来やりたかったesp32-arduino V2系ではできなかったのですが、V3系では可能なことを確認できたのでまずはよし、としようと思います。

なお、この記事は、【札幌現地+オンライン開催】力強くブログを108記事アウトプットする日の 20241229のブログの一つとして書きました。
参加した皆さん、お疲れ様です!

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?