1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【FreeRTOS × ESP32】Timerとは?vTaskDelay不要の定周期処理

Last updated at Posted at 2026-01-25

この記事でわかること

  • FreeRTOS Software Timer(ソフトウェアタイマ)で何ができるか
  • Timerコールバックは「どこで動くか」
  • 最小サンプル(ESP32 / ESP-IDFで動く)
  • 主要API(Create / Start / Stop / Reset / ChangePeriod / FromISR)の役割

こんな方におすすめ

  • 周期処理(センサー取得、監視、LED点滅)をキレイに書きたい
  • vTaskDelay() ループが増えてタスクが散らかってきた
  • タイマーのコールバックで何をしてよいか分からない

1. FreeRTOS Software Timerとは

FreeRTOSの Software Timer は、「指定時間後にコールバックを呼ぶ」「一定周期でコールバックを呼ぶ」ための仕組みです。

  • One-shot:1回だけ発火(タイムアウトなど)

  • Auto-reload:周期で発火(定周期処理)

重要ポイント:

  • Timerコールバックは、あなたのタスクの中では動きません
  • Timer Service Task上で実行されます

つまり、コールバックで重い処理をすると、他のタイマー処理も巻き込んで遅れる可能性があります。

2. Timerコールバックでやっていいこと/ダメなこと

やっていいこと(推奨)

  • フラグを立てる

  • Task Notification / Semaphore / EventGroup で「処理タスクを起こす」

  • 最小限の処理(短時間で終わるもの)

ダメなこと(事故りやすい)

  • 長い printf(ログ出力が詰まるとタイマサービスが止まる)

  • 重い処理(JSONパース、ファイルI/O、通信など)

  • ブロックする可能性のある処理(ロック待ち、長い待ちなど)

結論:Timerは“起床トリガー”に徹して、処理は別タスクへ が安全です。

3. 【最小サンプル】1秒ごとに処理タスクを起こす(ESP32 + ESP-IDF)

やりたいこと

  • Timer:1秒ごとに発火
  • WorkerTask:Timerに起こされたらログを出す
#include <cstdio>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"

static TaskHandle_t workerHandle = nullptr;
static TimerHandle_t periodicTimer = nullptr;

static void WorkerTask(void *pv)
{
    uint32_t cnt = 0;
    for (;;) {
        // タイマーから通知が来るまでブロック(CPUを使わない)
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        // 本処理はタスク側で実施
        printf("[Worker] tick %u\n", (unsigned)cnt++);
    }
}

// Timerコールバック(Timer Service Task上で動く)
static void PeriodicTimerCb(TimerHandle_t xTimer)
{
    // ここでは「通知だけ」にするのが安全
    xTaskNotifyGive(workerHandle);
}

extern "C" void app_main(void)
{
    xTaskCreate(WorkerTask, "WorkerTask", 2048, nullptr, 5, &workerHandle);

    // 1秒周期のAuto-reloadタイマ
    periodicTimer = xTimerCreate(
        "Periodic",
        pdMS_TO_TICKS(1000), // period
        pdTRUE,              // auto-reload
        nullptr,             // timer ID(必要なら使う)
        PeriodicTimerCb
    );

    if (periodicTimer == nullptr) {
        printf("xTimerCreate failed\n");
        return;
    }

    // タイマ開始(コマンドキュー経由。通常はブロック時間0でOK)
    xTimerStart(periodicTimer, 0);
}


動きのポイント

  • タイマーは 1秒ごとに発火
  • コールバックは通知だけ(軽い)
  • WorkerTaskが起床してログ出力(本処理)

4. One-shot(1回だけ発火)の最短例

「3秒後に1回だけ何かしたい」なら、uxAutoReload = pdFALSE。

static TimerHandle_t oneShotTimer = nullptr;

static void OneShotCb(TimerHandle_t xTimer)
{
    printf("[OneShot] fired!\n");
}

oneShotTimer = xTimerCreate(
    "OneShot",
    pdMS_TO_TICKS(3000),
    pdFALSE,   // 1回だけ
    nullptr,
    OneShotCb
);
xTimerStart(oneShotTimer, 0);

5. 主要API(Qiitaは薄め:役割だけ)

  • xTimerCreate():タイマ作成(失敗時は NULL
  • xTimerStart() / xTimerStartFromISR():開始
  • xTimerStop() / xTimerStopFromISR():停止
  • xTimerReset() / xTimerResetFromISR():今から周期を数え直す
  • xTimerChangePeriod() / xTimerChangePeriodFromISR():周期変更
  • pvTimerGetTimerID():Timer ID取得(複数タイマを共通コールバックで捌く時に便利)

※ ISR(割り込み)から操作する場合は、通常版ではなく FromISR系 を使います。

6. よくあるハマりどころ

  • xTimerCreateしただけで動くと思う
    → xTimerStart() が必要

  • コールバックで重い処理をして全体が遅れる
    → コールバックは Timer Service Task上。ここが詰まると他タイマーも遅れる

  • 周期はTick基準
    → pdMS_TO_TICKS() を使う(Tick粒度より細かい精度は出ない)

7. まとめ

  • Software Timerは「一定時間後/一定周期で起こす」仕組み
  • コールバックは Timer Service Task上で動く(重要)
  • コールバックは軽く、処理はタスクへ(通知して起床)が安全
  • まず覚えるのは Create / Start(必要ならStop/Reset/ChangePeriod)

FreeRTOS × ESP32 記事シリーズ

1
1
1

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?