ESP32でLEDフェード機能を試してみた:LEDCの仕組みと時間ずれの理由

ESP32でエルチカ(LED点滅)ができるようになったので、次のステップとしてLEDのフェード機能を試してみました。 じわじわ明るくなったり暗くなったりする、あの演出です。

Arduino IDE の [ファイル] → [スケッチ例] → [ESP32] → [Analog Out] → [LEDC Fade] を開くと、フェード機能を使ったサンプルが確認できます。

この記事では、

  • LEDCとは何か
  • フェードの仕組み
  • 実際のプログラム構造
  • フェード時間が理論値とズレる理由

をまとめて紹介します。

スポンサーリンク

1. LEDCとは?ESP32のPWMフェード機能

ESP32にはLEDC(LED Control)というPWM制御用のハードウェアモジュールがあります。 フェード機能もこのLEDCに含まれています。

LEDCのフェードは、

  • デューティ比(ON/OFF比)を少しずつ変化させる
  • カウンターが目標値に達したら割り込みが発生
  • 割り込みでフェード終了を検知

という仕組みで動作します。

私たちが設定するのは、

  • カウンターの分解能(例:12bit)
  • PWM周波数(例:5kHz)
  • フェード時間(ミリ秒)

の3つだけ。 あとはLEDCが自動でフェード処理をしてくれます。

2. PWM波形を観察してみる

実際の波形を見ると、1周期の中でON時間(デューティ比)が徐々に変化しているのが分かります。

  • 周波数:5kHz
  • 1周期:200µs
  • デューティ比が少しずつ変化 → 明るさが滑らかに変わる

LEDCは高速・低速の2グループを持ち、それぞれに

  • 4つのタイマー
  • 8つのチャンネル

が割り当てられています。 Arduinoのサンプルでは高速グループが使われます。

3. プログラムの流れ(タイマー設定 → チャンネル設定)

サンプルコードの流れを簡単に整理すると次の通りです。

① タイマー設定

  • 分解能(例:12bit)
  • 周波数(例:5kHz)
  • 使用するタイマー番号
  • 高速/低速モード

これらを構造体にまとめて ledc_timer_config() に渡します。

② チャンネル設定

  • 使用するチャンネル番号
  • 割り当てるGPIOピン
  • 初期デューティ比
  • 使用するタイマー番号

これを ledc_channel_config() に渡して設定します。

③ フェード開始

ledcFadeWithInterrupt() を呼ぶとフェードがスタートし、 目標デューティ比に達すると割り込みが発生してフラグが立ちます。

4. フェード時間が理論値とズレる問題

ここからが本題です。

例えば、

  • フェード時間:3000ms
  • 明→暗→明 の往復:6000ms

になるはずですが、実際に測ると約5秒しかかかりません。

他の値でも同様で、

フェードタイム設定理論値(往復)実測値
1000ms2000ms約1600ms
1500ms3000ms約1600ms(なぜか同じ)
2000ms4000ms約3200ms

どれも 約0.8秒短い という結果になりました。

5. なぜズレるのか?原因は「ステップ間隔の自動計算」

フェード時間は次の式で決まります。

フェード時間=カウンター最大値周波数×ステップ間隔

ここで問題なのが、

  • ステップ間隔は整数値しか使えない
  • ESP32側が自動で近似値を割り当てる

という点です。

例えば12bit分解能ならカウンター最大値は4096。 周波数5kHzなら1カウントあたり約0.2ms。

フェードタイム1000msを設定しても、 内部計算で最適なステップ間隔が1に丸められ、 結果として 1.6秒 になってしまう、というわけです。

6. 対策:フェード時間は「ズレる前提」で調整する

結論として、

  • LEDCのフェード時間は設定値どおりにはならない
  • 内部のステップ間隔が整数に丸められるため誤差が出る
  • 正確なフェード時間が必要なら自分で補正する必要がある

という仕様になっています。

まとめ

  • ESP32のLEDCはPWMフェードを簡単に実装できる便利な機能
  • しかしフェード時間は内部計算の都合で設定値とズレる
  • 正確な時間が必要な場合は補正や自前制御が必要

ESP32のLEDCは強力ですが、内部仕様を理解しておかないと「なんで?」とハマるポイントもあります。 今回の検証が、同じように悩んでいる方の参考になれば幸いです。

error: コンテンツ保護のため右クリック使用禁止