PWM制御とは?Arduino(ESP32)コマンドで使い方を詳しく紹介

PWM制御とは?アイキャッチ画像Arduinoコマンド
スポンサーリンク

「PWM制御」とはマイコンボード等でLEDランプの明るさを調整したり、モーターの速度を変えたりする時に使用される制御方法です。

「PWM制御」の基本動作から「Arduino(ESP32)コマンド」を使ったプログラミング方法、サンプルプログラムを使用して、音(ブザー)と光(LED)で動作確認しながら使い方を詳しく紹介します。

PWM制御でRCサーボモータを使用したラジコンの作り方も、以下のリンクで詳しく紹介しています。

LEGOで作るBluetooth遠隔操作ラジコン(Arduinoコマンド、ESP32系マイコンATOM使用)
M5StickC PlusとATOMを使用してBluetooth通信とジョイスティックで操作するラジコンカーをLEGOブロックで作ります。LEGOなので組み合わせは自由!自分好みのラジコンを作りましょう♪

1.PWM制御とは

「PWM制御」とは「パルス幅変調(Pulse Width Modulation)制御」とも呼ばれ、マイコンボード等の出力端子に接続した「負荷の電力を調整」する制御方法です。

「負荷の電力を調整」できるということはLEDランプの明るさを調整したり、モータの速度を可変できるという事になります。

「ON/OFF制御」が「ON」か「OFF」かの2つの状態しか持たないのに対して「PWM制御」では「ON」と「OFF」をパルス状に繰り返し「ON/OFF」のパルス幅を制御することで「ON」から「OFF」までの中間の電圧レベルを作り出すことができ、これにより「負荷の電力を調整」することができます。


「ON/OFF制御」と「PWM制御」をLEDランプの点灯を例に電圧波形で確認してみましょう。

・ON/OFF制御

PWM制御とは?

「ON」で電圧がHighの状態になるとLEDに電流が流れ、LEDランプが点灯します。
「OFF」で電圧がLow(0V)になるとLEDには電流が流れなくなり、LEDランプは消灯します。

・PWM制御

PWM制御とは?

波形の中央部が「PWM制御」部です。ここでは「ON」と「OFF」が同じ時間間隔で交互に繰り返しています。この時LEDには電流が流れたり、流れなくなったりを繰り返します。

「ON」と「OFF」の繰り返しがゆっくりの場合、LEDランプは点滅して見えますが、超高速で点滅する場合「ON」と「OFF」の比率で「ON」の時間比率分の明るさで点灯しているように見えます。

今回の場合は「ON」と「OFF」の間隔が 1:1で同じため、LEDは50%の明るさで点灯しているように見えます。

電圧は常に一定ですが、連続して「ON」している時よりも「ON」の時間が50%になるため、同じ時間で流れる電流の量が50%になり、負荷の電力も50%になります。

このように電圧の「ON/OFF」を繰り返し、「ON」の時間比率(Duty比)を調整して、流れる電流の大きさを変化させることで、負荷の電力を制御することを「PWM制御」といいます。

2.Duty比について

「Duty比」とは「PWM制御」の電圧波形の「High/Low」時間の組み合わせを1周期とした「PWM周期」の「High」時間の比率を「%」で表したものです。

「Duty比」ごとに電圧波形を確認すると以下のようになります。

PWM制御とは?Duty比について

電圧Highで点灯するLEDランプで例えると「Duty比 20%」より「Duty比 80%」の方が明るく点灯します。

3.分解能と周波数について

「PWM制御」における「分解能」と「周波数」について、先に紹介した「Duty比」と合わせて、下図のPWM出力波形で詳しく紹介します。

PWM制御とは?分解能と周波数について

「PWM制御」における「分解能」とは「PWM周期を分解できる能力」になります。
PWM周期を何分割できるかを決める値になり、「分解能」が高ければ高いほど、その中で細かく「Duty比」を設定することができます。(最小単位:1/分解能)

「分解能」は「bit数」で決まり、以下の式で求められます。

分解能 = 2のbit数乗

「8bit」の場合の分解能は、2の8乗で「256」、「12bit」では2の12乗で「4096」となります。

「bit数、分解能」ごとの設定可能な最小Duty比 [%] と「Duty比」ごとの設定値は以下表のようになり、「分解能」が高いほど「Duty比」が細かく設定できるのがわかると思います。

bit数分解能設定可能な
最小Duty比 [%]
Duty比約20%
の時の設定値
Duty比約50%
の時の設定値
Duty比約80%
の時の設定値
Duty比100%
の時の設定値
4166.2381316
82560.390651128205256
1240960.0244819204832774096
16655360.001513107327685242965536

「PWM制御」における「周波数(Hz)」とは「1秒間のPWM周期の数」です。

1秒間に「PWM周期」の数が50個の場合は「50Hz」1000個の場合は「1000Hz = 1kHz」となります。

LEDランプの場合「周波数」が低いと点滅しているような「チラツキ」が目立つため、周波数を高くすることで連続点灯しているように制御することができます。

ブザー等スピーカーを接続して「音階」の調整を行う場合は「Duty比」ではなく「周波数」で調整します。

設定できる「周波数(Hz)」の最大値はPWM出力波形を生成するための「クロック周波数」によって「bit数、分解能」で異なります。
これについては使用するマイコンボードごとに仕様を確認する必要があります。

4.Arduinoコマンドを使用したPWM制御方法

M5Stack等に使用されている「ESP32」を搭載したマイコンボードで使用できる「PWM制御」用コマンドの使い方について詳しく紹介します。

・PWM制御コマンド(Ledc 〜)一覧

「PWM制御」を行う「Arduinoコマンド」には「analogWite()」というものもありますが、こちらは周波数が500〜1000Hzで固定で「Duty比」のみの制御となります。

実用的な「PWM制御」を行うためには、周波数の設定も可能な「Ledc 〜」コマンドが便利です。

以下が「Ledc 〜」コマンドの一覧です。

ledcSetup ( チャンネル , 周波数 , bit数(分解能) ) ; //PWM出力波形の初期設定
ledcAttachPin( 端子番号 , チャンネル ) ;
 //チャンネルに対する出力端子を設定
ledcWrite( チャンネル , Duty比 ) ;
 // 指定したDuty比でPWM出力
ledcWriteTone( チャンネル , 周波数 ) ;
 // 指定した周波数でPWM出力
ledcWriteNote( チャンネル , NOTE_音階 , オクターブ ) ;
 // 指定した音階でPWM出力
ledcDetachPin
( 端子番号 ) ;
 // PWM出力端子とチャンネルの結びつきを解除

ledcRead( チャンネル ) ; // チャンネルに指定したデューティ比を取得
ledcReadFreq( チャンネル ) ; // チャンネルに指定した周波数を取得

これらの使い方について、次から詳しく紹介していきます。


・初期設定

「PWM制御」を行うためには以下のように初期設定を行います。

pinMode( 端子番号 , OUTPUT ) ; // PWM出力を行う端子を出力端子として設定
ledcSetup ( チャンネル , 周波数 , bit数(分解能) ) ; //PWM出力波形の初期設定
ledcAttachPin( 端子番号 , チャンネル ) ; //チャンネルに対する出力端子を設定
ledcSetupPWMで使用するチャンネル(チャネルともいう)と周波数、bit数(分解能)を設定
チャンネル:PWM出力タイミングを生成するチャンネルで 0〜15の中から指定
       16個のチャンネルは 0/1 、2/3 〜 12/13、14/15 でペアになっており、
       各ペアで周波数とbit数(分解能)は同じに設定する必要があります。
周波数:PWM出力周波数を設定します。
bit数(分解能):PWM周期の分解能をbit数(1〜16)で指定

ledcAttachPin:チャンネルに対する出力端子を設定
端子番号:PWM出力を行うマイコンボードの出力端子番号を設定

「周波数」の最大値は使用するマイコンボードのPWM出力波形を生成するための「クロック周波数」から「bit数、分解能」によって以下の式で決まります。

周波数最大値 = クロック周波数 / 2のbit数乗

「M5Stack」に使用されている「ESP32」のクロック周波数の80MHzから「bit数、分解能」ごとに設定できる「周波数」の最大値を求めると以下表のようになります。

bit数分解能周波数最大値
1240,000,000
2420,000,000
3810,000,000
4165,000,000
5322,500,000
6641,250,000
7128625,000
8256312,500
bit数分解能周波数最大値
9512156,250
10102478,125
11204839,063
12409619,531
1381929,766
14163844,883
15327682,441
16655361,221
PWM制御を行うための初期設定では、まず使用する端子を出力端子として設定します。
次に、PWM出力タイミングを生成するチャンネルを指定し、周波数とbiti数(分解能)を設定します。
最後に指定したチャンネルに対する出力端子を設定します。
各チャンネルのPWM波形を生成するための「クロック」は内部タイマー等の他の機能にも使用されています。
このため、使用するチャンネルや、周波数、biti数(分解能)の設定によっては他の機能の動作がおかしくなったり、PWMが意図しない動作になることがあるかもしれません。
これについては使用するマイコンボードのデータシートで詳細を確認する必要があります。
うまく動作しない場合はチャンネルを変更して動作確認してみましょう。

・PWM出力実行①(初期設定の内容でDuty比を指定して実行)

チャンネルに指定した周波数、分解能でPWM出力を実行するためには以下のコマンドを実行します。
一度実行すると指定したPWM波形を出力し続けます。

ledcWrite( チャンネル , Duty比 ) ; // 指定したDuty比でPWM出力
ledcWrite:初期設定でチャンネルに設定した「周波数、bit数(分解能)、端子番号」で「Duty比」を指定してPWM出力を実行
チャンネル:初期設定で設定した、使用するチャンネル番号を指定
Duty比 :PWM周期(分解能)の「Duty比(Highレベルの割合)」を指定
      0〜分解能の最大値(0% 〜 100%)
Duty比の設定例
チャンネル」に設定したbit数(分解能)が10bit(2の10乗で「1024」)の場合に、Duty比を50%にしたい時は「Duty比」の値を「512」に設定します。

・PWM出力実行②(周波数を指定して実行)

周波数を指定して、以下のようにPWM出力を行うこともできます。
この場合、先に行った初期設定の ledcSetup() の設定は無効になります。

ledcWriteTone( チャンネル , 周波数 ) ; // 指定した周波数でPWM出力
ledcWriteTone:「チャンネル周波数」を指定してPWM出力を実行
チャンネル
PWM出力タイミングを生成するチャンネルで、0〜15の中から指定
       16個のチャンネルは 0/1 、2/3 〜 12/13、14/15 でペアになっており、

       各ペアで周波数は同じに設定にする必要があります。

周波数:出力したい「周波数(Hz)」を数値で指定します。


・PWM出力実行③(音階、オクターブを指定して実行)

音階(ドレミ〜)、オクターブを指定してPWM出力を行うこともできるため、出力端子にスピーカーを接続すれば、指定した音階で音を鳴らすことができます。
この場合、先に行った初期設定の ledcSetup() の設定は無効になります。

ledcWriteNote( チャンネル , NOTE_音階 , オクターブ ) ; // 指定した音階でPWM出力
ledcWriteNote:「チャンネル音階オクターブ」を指定してPWM出力を実行
チャンネル:PWM出力タイミングを生成するチャンネルで、0〜15の中から指定
       16個のチャンネルは 0/1 、2/3 〜 12/13、14/15 でペアになっており、

       各ペアで音階、オクターブは同じに設定する必要があります。

音階NOTE_音階 「C(ド)〜B(シ)」で指定。
オクターブ:オクターブ(同一音階で倍の周波数)を 0〜8段階で設定

音階」部は以下の中から指定します。
 C、 Cs、 D、 Eb、  E、  F、   Fs、    G、 Gs、 A、 Bb、 B
(ド、ド#、レ、ミ♭、ミ、ファ、ファ#、ソ、ソ#、ラ、シ♭、シ)

・その他のコマンド

その他にも以下のようなコマンドがあります。

ledcDetachPin( 端子番号 ) ; // PWM出力端子とチャンネルの結びつきを解除
ledcRead( チャンネル ) ; // チャンネルに指定したデューティ比を取得
ledcReadFreq( チャンネル ) ; // チャンネルに指定した周波数を取得
ledcDetachPin() は ledcAttachPin() と組み合わせることで、指定した出力端子に対して、PWM出力の有効無効を切り替えることができます。

5.PWM制御を音と光で動作確認(M5StickC Plus使用)

実際にマイコンボード「M5StckC Plus」に内蔵されている「LED」と「ブザー」を使用して動作確認してみましょう。
サンプルプログラム(コピペ)も準備しましたので、書き込んで動作確認してみるとより理解が深まると思います。

「M5StickC Plus」については、以下のリンクで詳しく紹介しています。

M5StickC Plusの使い方、初期設定、サンプルプログラム、M5StickCとの違い等を詳しく紹介
M5StickC PlusをArduino IDEやPlatformIOで使うための初期設定やサンプルプログラムでの動作確認の方法です。ビジュアルプログラミングのUiFlowの初期設定についても紹介します。

開発環境の「ArduinoIDE」の使い方については、以下のリンクで詳しく紹介しています。

M5StackシリーズのためのArduino IDEのインストール方法と初期設定、使い方紹介
M5Stackシリーズ(StickC、ATOM等)のためのArduino IDEのインストール方法から初期設定、スケッチ例の書き込み、コピペでの使い方まで詳しく紹介します。インストールはArduinoでも同じです。

 ・PWMでLED調光、ブザー音制御(動作確認)

「M5StackC Plus」の外部出力端子には「抵抗内蔵LED」の「+(アノード)」を「G0」に、「ー(カソード)」を「GND」に接続します。
「GROVEコネクタ」には「ボリューム(ANGLE UNIT)」を下写真のように接続しています。

PWM制御とは?動作確認

「抵抗内蔵LED」と「ボリューム(可変抵抗器)」については、以下のリンクで詳しく紹介しています。

LED(発光ダイオード)の使い方。Lチカでの動作確認方法
LEDが登場するまで光源としては白熱電球が主流でした。白熱電球は電気を熱に変えて光りますがLEDは+と-の電気が結合する時のエネルギーで光り、電気を直接光に変換するため発光効率が非常に良いです。
ボリューム(可変抵抗器)の使い方、つなぎ方、抵抗値計算等を回路図も使って詳しく解説
ボリュームというと音量調節のイメージですが、明るさや回転数等を調整するのにも使用されます。「抵抗(固定抵抗器)」が固定の抵抗値を持つのに対して「可変抵抗器」は抵抗値を調整することができます。このボリューム(可変抵抗器)について紹介します。

ボリュームを回すことで「Duty比(または周波数、音階の場合はオクターブ)」を調整することができます。

「LED」について、下図のように、本体の「LED(赤)」はPWM出力がLow(0V)の時に点灯します。
対して、外部出力端子に接続した「抵抗内蔵LED(青)」はPWM出力がHigh(3.3V)の時に点灯します。

本体LED赤、出力「Low」で点灯

PWM制御とは?動作確認

外部LED青、出力「High」で点灯

PWM制御とは?動作確認

このため「Duty比」を変化させて「LED(赤)」が明るくなると「LED(青)」は暗く、LED(青)」が明るくなると「LED(赤)」は暗くなるという動作になります。

このように、接続する負荷の接続方法によっても変化のしかたは異なるので、これについても動作確認してみましょう。

ブザーについて、本体正面のボタンAを押すたびにブザーの「ON/OFF」を切り替えられます。
LEDとブザーには同じPWM波形が出力されます。
音と光でどのような違いになるかを確認してみましょう。

「Duty比」を変えるとLEDの明るさは変わっても、ブザーの音階は変わりません。逆に、「周波数」を変えるとブザーの音階は変わってもLEDの明るさは変わりません。
また、「Duty比」0% と 100% の時は電圧の変化が無いため、ブザー内部の振動板が振動しないため音は鳴りません。

実際に動作確認を行ったものが下写真になります。

まず、本体の液晶画面の表示内容について紹介します。

PWM制御とは?動作確認

液晶画面には「ledcSetup()」で設定した「チャンネル、周波数、ビット数(分解能)が表示されます。
「ADC:」にはボリュームからのアナログ入力値(分解能 0〜4095/電圧 0〜3.3V)が表示されます。

「Duty:」には実際に出力されている波形の「Duty比」の設定値を取得して表示し「%」にも換算して表示しています。「Duty比」はボリュームを調整することで変動します。


実際にボリュームで「Duty比」を可変させLEDの動作確認を行うと下写真のようになります。

Duty比 0%

PWM制御とは?動作確認

「Duty比」が 0%の時、本体LED(赤)の明るさは100%、外部の抵抗内蔵LED(青)は消灯になります。

Duty比 100%

PWM制御とは?動作確認

「Duty比」が 100%の時、本体LED(赤)は消灯、外部の抵抗内蔵LED(青)は明るさが100%になります。


「Duty比」を変化させると、それぞれのLEDが交互に明るくなったり、暗くなったりすることが確認できます。

Duty比 10%

PWM制御とは?動作確認

Duty比 50%

PWM制御とは?動作確認

Duty比 90%

PWM制御とは?動作確認
それぞれのLEDには同じPWM波形が出力されていますが、接続方法の違いで電流の流れる方向が異なるため、このような動作になります。

本体ボタンAを押すごとに、本体ブザーのON/OFFが切り替えられます。
「Duty比」の変化でブザーの音がどのように変化するかが確認できます。

「Duty比」の変化でLEDの明るさは変化しますが、ブザーの音は変化しないのが確認できると思います。音を変化させるには「周波数」の変更が必要ですが、今回は周波数は固定になっているためです。
「Duty比」が変化する瞬間は音階が変わったように聞こえますが、持続音は変わっていません。(「Duty比」0% と 100% 付近では音が不安定になります。)
また、人間の可聴域は 20Hz〜20,000Hzと言われていますので、音の確認はこの範囲内で行いましょう。

プログラムを書き換えることで、PWM出力を、周波数や音階(オクターブ)で指定して動作確認を行うことができます。

PWM制御とは?動作確認

ledcWriteTone()で「周波数(Hz)」を指定してPWM出力を実行した場合は上画像のようになります。
ボリュームのアナログ入力値がそのまま周波数として出力されます。
本体ボタンAを押すとブザーが鳴り、音の変化が確認できます。

PWM制御とは?動作確認

ledcWriteNote()で「音階(オクターブ)」を指定してPWM出力を実行した場合は上画像のようになります。
ボリュームのアナログ入力値によって設定した音階(上写真ではラのA)のオクターブが調整できます。
周波数(Hz)の表示は設定した音の周波数がオクターブ倍で段階的に表示されます。
本体ボタンAを押すとブザーが鳴り、音の変化が確認できます。

「周波数(Hz)」が変わるとブザーの音階は変化しますが、LEDの明るさは変化しません。
これは「周波数(Hz)」が変化しても「Duty比」は固定で変わらないためです。
周波数や音階でPWM出力を実行する場合は「チャンネル、bit数(分解能)」の表示は初期設定で設定した数値のままのため無視してください。「Duty比」の値は内部で設定されているようで、今回の動作確認では常に「511」の表示となりました。

 ・サンプルプログラム(コピペ)

サンプルプログラムは以下になります。「コピペ」して書き込んでください。

※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

/* PWM出力動作確認 */
#include <M5StickCPlus.h> // ヘッダーファイル
// 端子割り付け
#define ADC_PIN 33 // アナログ入力端子
// PWM出力端子設定
#define PWM_OUT_PIN 0     // PWM出力端子番号(外部出力)
#define PWM_LED_PIN 10    // PWM出力端子番号(本体LED赤)
#define PWM_BUZZER_PIN 2  // PWM出力端子番号(本体ブザー)

// PWM出力設定(周波数と分解能はチャンネルのペアでは同じに設定する)
#define CH 1        // PWM出力チャンネル(0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15でペア)
#define FREQ 1000   // PWM出力周波数(最大周波数 : 80MHz / 2の「bit数」乗)
#define BIT_NUM 10  // bit数(1bit〜16bit)

// 変数設定
float ad_val;       // アナログ入力値格納用
float duty;         // Duty比
float resolution;   // 分解能
float battery;      // バッテリー残量表示用
bool state = false; // ボタン操作状態保持用

// 初期設定 -----------------------------------------
void setup() {
  M5.begin(); // (LCD有効, POWER有効, Serial有効)
  Serial.begin(9600); // シリアル出力初期化(今回は未使用)
  // アナログ入力設定
  pinMode(ADC_PIN, ANALOG); // アナログ入力

  // PWM出力に使用する端子を出力設定
  pinMode(PWM_OUT_PIN, OUTPUT);     // 外部出力端子
  pinMode(PWM_LED_PIN, OUTPUT);     // 本体LED
  pinMode(PWM_BUZZER_PIN, OUTPUT);  // 本体ブザー

  // PWM初期設定
  ledcSetup(CH, FREQ, BIT_NUM);   // PWM設定(チャンネル, 周波数, bit数)
  ledcAttachPin(PWM_OUT_PIN, CH); // PWMチャンネル割り当て(端子番号, チャンネル)(外部出力)
  ledcAttachPin(PWM_LED_PIN, CH); // PWMチャンネル割り当て(端子番号, チャンネル)(本体LED)

  // 液晶表示初期設定
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setRotation(1);    // 画面向き設定(USB位置基準 0:下/ 1:右/ 2:上/ 3:左)
  M5.Lcd.setTextSize(1);    // 文字サイズ(整数倍率)
  M5.Lcd.setTextFont(4);    // フォント
}
// メイン -------------------------------------------
void loop() {
  M5.update();  //本体ボタン状態更新
  // アナログ入力処理
  ad_val = analogRead(ADC_PIN); // アナログ入力値(0〜4095)を取得
  // アナログ入力値(0〜4095)を Duty比に換算
  resolution = pow(2, BIT_NUM);         // 分解能(2のnビット乗)
  duty = resolution * (ad_val / 4095);  // 換算

  // PWM出力実行(以下の3ついずれか1つを有効にして動作確認)
  ledcWrite(CH, duty);       // チャンネルに指定した周波数、分解能で実行する場合(チャンネル、Duty比)
  // ledcWriteTone(CH, ad_val); // 周波数を指定して実行する場合(チャンネル、周波数)
  // ledcWriteNote(CH, NOTE_A, (int)(ad_val / 500.0)); // 音階を指定して実行する場合(チャンネル、音階、オクターブ0〜8)
                                                    // ド、ド#、レ、ミ♭、ミ、ファ、ファ#、ソ、ソ#、ラ、シ♭、シ
                          // NOTE_*(*部に音階指定):*= C、 Cs、D、 Eb、 E、  F、  Fs、 G、 Gs、A、 Bb、B

  //ボタンAで本体ブザーON/OFF(PWMチャンネル割り当て、解除)
  if (M5.BtnA.wasPressed() == 1 && state == false) {  // stateがfalseで本体ボタンが押されていたら
    ledcAttachPin(PWM_BUZZER_PIN, CH);                // PWMチャンネル割り当て(ピン番号, チャンネル)(本体ブザー)
  }
  if (M5.BtnA.wasPressed() == 1 && state == true) {   // stateがtrueで本体ボタンが押されていたら
    ledcDetachPin(PWM_BUZZER_PIN);                    // PWMチャンネル割り当て解除(ピン番号)(本体ブザー)
  }
  if (M5.BtnA.wasReleased()) {  // 本体ボタンが離されていたら
    state = !state;             // ボタン操作状態反転
  }
  // バッテリー残量(MAX約4.2V、限界電圧3V)パーセント換算表示
  battery = (M5.Axp.GetBatVoltage() - 3) * 90;  // バッテリー残量取得、換算
  if (battery > 100) { battery = 100; }         // 換算値が100以上なら100にする
  // LCD表示処理
  M5.Lcd.setTextFont(2);  // フォント
  M5.Lcd.setCursor(200, 3); M5.Lcd.setTextColor(DARKGREY, BLACK);
  M5.Lcd.printf("%3.0f%%     ", battery);                           // バッテリー残量表示
  M5.Lcd.setTextFont(4);  // フォント
  M5.Lcd.setCursor(5, 5);   M5.Lcd.setTextColor(WHITE, BLACK);      // 座標設定(x, y)、(文字色, 背景)
  M5.Lcd.print("PWM TEST");                                         // タイトル
  M5.Lcd.setCursor(5, 30);  M5.Lcd.setTextColor(ORANGE, BLACK);
  M5.Lcd.printf("ch : %d  Hz : %4.1f              ", CH, ledcReadFreq(CH)); // チャンネル、実際の出力周波数
  M5.Lcd.setCursor(5, 55);  M5.Lcd.setTextColor(CYAN, BLACK);
  M5.Lcd.printf("bit : %d ( %d )    ", BIT_NUM, (int)resolution);   // ビット数、分解能(int型にキャスト)
  M5.Lcd.setCursor(5, 80);  M5.Lcd.setTextColor(GREEN, BLACK);
  M5.Lcd.printf("ADC : %4.0f ( %1.1fV )       ", ad_val, ad_val * (3.3 / 4095.0)); // アナログ入力値表示(電圧換算)
  M5.Lcd.setCursor(5, 105); M5.Lcd.setTextColor(WHITE, BLACK);
  M5.Lcd.printf("Duty : %d( %4.1f%%   )       ", ledcRead(CH),  ledcRead(CH) * 100.0 / resolution); // Duty比(High状態比率)
  delay(100);  // 遅延時間(ms)
}

 ・プログラムの解説

サンプルプログラムの10〜13行目で「チャンネル」「周波数」「bit数」を設定しています。
ここの値を色々なパターンで書き換えて動作確認してみましょう。

29〜32行目で「本体LED(赤)G10」「本体ブザー G2」「外部抵抗内蔵LED(青)用端子G0」を出力端子として設定しています。

35行目でPWM出力波形の初期設定を行なっています。

36, 37行目で「本体LED(赤)G10」と「外部抵抗内蔵LED(青)用端子G0」に使用するチャンネルを設定しています。
「本体ブザー G2」は「本体ボタンA」を押すごとにON/OFFを切り替えるため63行目で設定、66行目で解除しています。

55行目でPWM出力を実行しています。55〜57行目の3つのパターンでPWM出力を実行することができます。どれか1つを有効にして、他の2つはコメントアウトして無効にしましょう。

55〜57行目3つ全部有効にした場合は、一番下の「音階」指定でのPWM出力になります。

6 .まとめ

「PWM制御」について紹介しました。

「PWM制御」とは、電圧の「ON/OFF」を繰り返し「Duty比」を調整することで流れる電流の大きさを調整して、負荷の電力を制御する制御方法です。

「Duty比」とは出力電圧波形の「High/Low」時間の組み合わせを1周期とした「PWM周期」の「High」時間の比率を「%」で表したものです。

設定できる「Duty比」の精度は「bit数」から「分解能」で決まり、設定できる最小値は「1/分解能」、最大値は「2のbit数乗」となります。

「周波数(Hz)」は「1秒間のPWM周期の数」で、1秒間に「PWM周期」の数が50個の場合は「50Hz」1000個の場合は「1kHz」となります。

LEDランプの場合「周波数」が低いと点滅しているような「チラツキ」が目立つため、周波数を高くします。ブザー等で「音階」の調整を行う場合は「Duty比」ではなく「周波数」で調整します。

「PWM制御」のプログラムは「Arduino(ESP32)のコマンド(Ledc 〜)」が便利で「M5StickC Plus」等で簡単に動作確認することができます。

「PWM制御」は「LED」の明るさ調整や、モータの回転制御、ブザー音の制御等、用途は幅広く欠かせない技術です。プログラム言語が変わっても基本原理は同じため基本を理解して、使いこなせるようになりましょう。

モーターの制御について、モーターには「DC」「ブラシレス」「単相、多相」「ステッピング」モーター等がありますが、これらの制御は全て今回紹介した基本の「PWM制御」の応用です。
これらのモーターの制御には「Hブリッジ回路」や「回生処理」「正弦波近似PWM制御」「ホールIC」等の位置検出についての理解が必要になるため、今後また詳しく紹介できればと思います。

コメント

タイトルとURLをコピーしました