11月25日発売 書籍『Arduinoと3Dプリンタでロボットを作ろう』を出させて頂きました!

【Arduino入門編③】PWM制御でLEDをゆっくり点灯&消灯させてみる!アナログ出力(PWM)の解説その①

前回前々回と2回にわたりArduinoのデジタル出力についてやってきました。

デジタル入出力ピン(D0~D13)やアナログ入力ピン(A0~A5)からdigitalWrite関数を使ってHIGH(5V)またはLOW(0V)を出力させてLEDを点灯や消灯させるといったものです。

【Arduino入門編①】ArduinoでLEDを点滅(Lチカ)させてみる!Arduinoの基本となるデジタル出力の解説その①
【Arduino入門編②】複数のLEDを点滅(Lチカ)させてみる!デジタル出力の解説その②

今回は出力にHIGH or LOWしかできないデジタル出力では難しい、LEDをゆっくり点灯させたり任意の明るさで点灯させたりするアナログ的な動作をやってみたいと思います。

【Arduino】アナログ出力(PWM)を使ってLEDをゆっくり点灯・消灯させてみる!

今回の目標

これまでやってきたデジタル出力のHIGHかLOWだけでは実現するのが難しいアナログ的な動作、こちらではLEDをゆっくり点灯させたり消灯させたりする動作をやってみたいと思います。

今回新たに出てくるanalogWrite関数を使ったアナログ出力(PWM)について理解できればと思います。

デジタルでアナログ的な動作をさせるのは意外と大変!?

これまでやってきたデジタルでの出力ではHIGHかLOW、つまり出力される電圧がArduinoの場合5Vか0Vの2パターンしかありませんでした。

それではLEDをゆっくり明るくさせたり(暗くしたり)、または50%の明るさで点灯させたい場合などどうすればいいのでしょうか?

このようなアナログ的な動作をやるにはデジタルでは少し厄介な話?となります。

例えばアナログ回路の場合、下図のようにLEDに接続した抵抗値によりLEDの明るさを変えることが出来ます。(下図ではArduinoは単に5Vの電圧出力のためだけに使っています)

それではArduinoの出力ピンに接続したLEDを同様に制御するにはどうしたらいいのか?
うぅ〜ん、なかなかいい方法が思いつきませんね!

試しにこれまでやってきたデジタル出力ピンを使って少しやってみましょう。
以下に簡単なスケッチを作ってみました。

変数WAIT_ON_TIME、WAIT_OFF_TIMEに入る数字(ミリ秒)を変化させてLEDが点灯している時間と消灯している時間の比率を変えていくとLEDの点灯がどのように変化するか確認するためのスケッチとなります。

回路はこんな感じ。(LEDに接続している制限抵抗は今回470Ωを使用)

まず初期値では、変数WAIT_ON_TIME、WAIT_OFF_TIMEには共に500を指定しており0.5秒(500ms)間隔でLEDが点灯・消灯を繰り返すようになっています。
ここまでは前回と同じですね!

それでは短い点滅サイクルの中でこの点灯・消灯の時間の間隔(割合)を変化させていくとどうなるか?
先程のスケッチの先頭にある変数部分の値を下のように変えてみて下さい。

この状態ではLEDは明るく点灯している状態になります。

それでは、WAIT_OFF_TIME変数の値はこのまま10(0.01秒消灯)に固定しておき、点灯している時間WAIT_ON_TIME変数の値を10、9、8・・・と少しずつ小さくしていくとLEDの点灯はどう変化するか?

LEDが点灯している時間が短くなるとそれに伴いLEDも暗くなるのが確認出来るかと思います。

LEDが点灯している時間が長い(10ms)

LEDが点灯している時間が短い(1ms)

つまりLEDが点灯している時間の割合が小さくなっていくとLEDの明るさもそれに比例して暗くなっていきます。

簡単に言うとLEDを高速で点灯・消灯させていくと人間の目では追いつく事が出来ず、点灯している時間の割合が大きいと明るく、そしてその時間の割合が小さいと暗く写るという事です。
まさにこれが今回やろうとしているPWMを使った制御というものとなります。

そして1周期にあるオンしている時間(LEDでは点灯している時間)の割合がデューティー比と呼ばれるものとなり、このようにデューティー比を大きくすればLEDは明るく、小さくすれば暗く点灯させる事ができます。

このスケッチではデジタル出力でdelay関数を使い擬似的にPWM制御をやってみました。
しかし実際にはプログラムは他のものも動いているのでその処理に時間がかかればタイミングもズレてしまい明るさが変化してしまうのであまりこの方法は現実的ではありません。

そこで今回やろうとしているアナログ出力(PWM)の話となってきます。

PWM(Pulse Width Modulation)とは?

先述したようにHIGHとLOWを周期的に出力する機能PWM(Pulse Width Modulationの略)がArduinoには備わっています。

このPWMは指定した割合でHIGHとLOWの間隔を切り替えて出力することが出来る便利な機能です。
今回やろうとしているLEDの明るさ調整などに使える機能です。
またサーボモーターやDCモーターの制御などにも使えます。

簡単にPWNについて説明すると、1周期内にあるHIGHの時間の割合(これをデューティー比といいます)によって制御する方式となります。

つまりLEDを点灯させる場合、デューティー比100%(常にHIGHの状態)ではLEDは100%で点灯し、デューティー比50%では半分の輝度、0%で消灯するという事になります。

そしてArduinoでは(こちらではArduino UNOで説明しています)14本あるデジタル入出力ピンのうち『〜』記号がついている3・5・6・9・10・11番ピンの計6本がPWM出力が出来る端子となっています。

このPWM出力はArduinoマイコンボード上でパルスを発生させるので(タイマー割り込み)、先ほど述べたようにプログラムの動作に影響する事なく安定して出力させる事ができます。

MEMO
『〜』記号が付いていない他のピンではPWM出力が出来ないので注意が必要です!

PWMでLEDの明るさを制御する

PWMについて理解できたところで、実際にこれを使いLEDを点灯させてみましょう。
簡単なテストスケッチとしてこちらを用意しました。
DUTYという変数の値を変えることによりLEDの明るさが変化します。(0~255)

先程の回路を少し繋ぎ直し、PWM出力が使える9番ピンにLEDを接続します。

ここで新しくanalogWrite関数が出てきました。
これがPWMを出力するための関数となります。
デジタル入出力ピンの3・5・6・9・10・11番ピンの計6本で使う事が出来ます。

analogWrite・・・アナログという文字がありますが実際にはデジタル端子を使っています。
そうです!
先述したPWMについて理解できていればこれも納得ですね!
アナログ的に出力できる(5Vや0V以外の値が取り出せる)わけですが、実際には短い周期でHIGHとLOWのパルスをデジタルとして出しています。

スケッチ解説

DUTYという変数を今回使いましたが、この値を0~255の範囲で(初期値は255になっています)変えてスケッチを動かしてみて下さい。
数字を小さくしていくと・・・LEDの点灯が少しずつ暗くなっていくのが確認出来ます。
デューティー比を指定することによりLEDの明るさを制御出来ましたね!
これがPWM制御となります。

今回新しく出てきた関数としてanalogWrite関数があります。

analogWrite 関数
指定したピンにアナログ値(PWMパルス)を出力します。
LEDの輝度を調整したりモーターの回転速度やサーボモーターの制御などに使われます。

 

【書式】analogWrite(pin, value);

 

pin:出力させたいピン番号
value:デューティー比(0〜255)

 

※デジタル出力のように事前にpinMode関数を使い出力設定する必要はありません。

指定したピン(PWM出力が出来る3・5・6・9・10・11番ピン)にデューティー比を指定して出力させる関数となります。

ここでデューティー比の指定には0〜100までの%指定ではなく、analogWrite関数の場合0〜255までの数字で指定します。
この点が少し注意が必要ですね!
ArduinoのPWM出力ピンは8ビットの分解能を持っています。
2の8乗、つまり256(0〜255)の範囲で指定するという事です。
少しややこしいですが、analogWrite関数で指定するデューティー比の値は0〜255で指定しないといけないと覚えておけばいいと思います。

そして今回のLEDの明るさを変える場合、この値が0なら消灯、255なら100%で点灯、半分の127では50%で点灯するという事になります。

これが確認できれば今回の目標は達成です。
Arduinoを使いPWM制御によりアナログ的にLEDを点灯させる事が出来ました。

MEMO
上記スケッチでは、setup関数内にpinMode関数で使用するピンを出力(OUTPUT)として設定しています。
分かりやすいようにこのスケッチでは記述しましたが、analogWrite関数でPWM出力させる場合この記述は省略することも出来ます。

LEDをゆっくり点灯・消灯させてみる

上記スケッチでanalogWrite関数を使いアナログ出力(PWM)について理解できたと思います。
それでは最後にLEDをゆっくり点灯・ゆっくり消灯させるスケッチも試してみましょう。
このようなサンプルスケッチを用意しました。

これまでのスケッチではpinMode関数で使用するピンを指定し出力(OUTPUT)に設定していました。
PWM出力にはanalogWrite関数を使いますが、PWMで使えるピンは決まっており出力(OUTPUT)での使用が前提なので省略する事が出来ます。(記述しても問題はないです)

while関数を使いデューティー比を0〜255に変化させLEDをゆっくりと点灯させています。

またデューティー比を255〜0に変化させ、ゆっくりとLEDを消灯させています。

while 関数
【書式】while( 条件式 ) { 実行文 }

条件式に当てはまる場合、ループで(実行文)が繰り返し実行されます。

スケッチ先頭にあるSTEPという変数でデューティー比の増減値を変える事が出来るので(初期値は1にしています)、この値を変えてLEDの点灯の変化なども試して下さいね。

今回使った関数(コマンド)まとめ

今回新たに出てきたArduinoのコマンド(関数)をまとめておきます。

関数使用方法
analogWrite(pin, value);指定したピンにアナログ値(PWMパルス)を出力します。
LEDの輝度を調整したり、モーターの回転速度を変えたり、サーボモーターの制御などに使われます。

【書式】analogWrite(pin, value);
pin:出力させたいピン番号
value:デューティー比(0〜255)

※デジタル出力のように事前にpinMode関数を使い出力設定する必要はありません!

while(条件式) {実行文}【書式】while( 条件式 ) { 実行文 }

条件式に当てはまる場合、ループで(実行文)が繰り返し実行されます。

今回のポイント

  • PWMを使えば出力させる値(電圧)をアナログ的に変化させる事ができる!
  • PWMで使えるピンはデジタル入出力ピンの3・5・6・9・10・11番ピン!
  • アナログ出力(PWM)にはanalogWrite関数を使い、0~255までの数字でデューティー比を指定する !
  • analogWrite関数を使う場合、事前にpinMode関数で使うピンの初期化(設定)を行う必要はありません!

今回使用したパーツ

Arduino UNO

Arduinoはオープンソースのハードウェアなので正規品以外にも互換品が多数メーカーから販売されています。
互換品でも正規品と比べて特に問題なく使用でき数百円程度で購入が可能なのでArduino学習用としていいですね!

Arduino スターターキット

また、これからArduino学習を進めていくにあたりArduino UNO(互換品)やブレッドボード、ジャンパーピンなどがセットになったスターターキットが販売されています。
私はGeekcreit製のスターターキットを使っていますが、ELEGOO製のものは国内Amazonなどでも購入可能で人気があるようです。(セット内容はほぼ同じです!)

そしてELEGOOのサイトからスターターキット用サンプルスケッチのダウンロードも可能です。(Geekcreitのキットでも使えます)

参考 チュートリアルダウンロードELEGOO

基本的にこれからこのセットで出来るものから紹介していこうと考えていますが、かなり多くのことが出来ます。
電子工作を始めるにはまずブレッドボードやジャンパーピン、メインとなるArduino UNOやサーボ、LEDなどの基本的なパーツがないと実際に動かすことが出来ませんが、個々にパーツを購入して回路を組んでとなるとかなりの手間がかかります。

スターターキットがあればArduinoの初歩的なことはかなりの数こなすことが出来るのでオススメです!
そこからスキルアップに伴い個別でセンサーなど必要なものを増やしていくのがいいと思います。

最後に!

今回analogWrite関数を使いアナログ出力(PWM)によりLEDを点灯させてみました。
デジタル出力のHIGHかLOWだけでなく、アナログ値を出力する事ができる便利な機能です。

またこのPWMはサーボモーターやDCモーターの制御などにも使われるので、これからArduinoを学習していくにあたり重要な機能の1つとなると思います。

今回、単色のLEDをPWMによって制御し点灯する事が出来ました。
このPWMでの制御を使えば、光の3原色である赤(RED)・緑(GREEN)・青(BLUE)のLEDが1つになったRGBフルカラーLEDの制御も出来ます。

このあたり次回ご紹介出来たらと思います。

その他 Arduino入門編 記事一覧
【Arduino入門編㉛】INA219モジュールで電圧・電流を計測する基本的な方法! 【Arduino入門編㉚】マイコンのデジタル端子(I/O)不足を解消!『I/Oエキスパンダー(MCP23017)』の基本的な使い方! 【Arduino入門編㉙】SPI通信の基礎知識!SPIで使われる信号線や接続方法などについて! 【Arduino入門編㉘】ソフトウェアシリアルを使ってみる! 【Arduino入門編㉗】赤外線(IR)モジュールを使いリモコンの信号を読み取り送受信する方法! 【Arduino入門編㉖】UARTシリアル通信の基礎知識!Arduino間でのデータのやり取りなどをやってみる! 【Arduino入門編㉕】ステッピングモーターを動かしその基礎を理解する!(28BYJ-48 & ULN2003) 【Arduino入門編㉔】Arduinoで7セグメントLEDを制御してみよう!(スタティック制御 / ダイナミック制御) 【Arduino入門編㉓】PCA9685 16チャンネルPWMサーボモータードライバを使って複数のサーボモーターを同時に制御してみる!(最大16台) 【Arduino入門編㉒】ArduinoでDCモーターを制御する。【L298Nデュアルモータードライバ】 【Arduino入門編㉑】温湿度センサー(DHT11)を使い温度と湿度を計測する! 【Arduino入門編⑳】Arduino Uno R3ボードのピン配列&基本機能まとめ! 【Arduino入門編⑲】RTC(リアルタイムクロック)モジュールDS3231を使いシンプルな時計を作る![I2C通信] 【Arduino入門編⑱】I2C通信の基礎!LCDディスプレイに文字を表示させてみる![後編] 【Arduino入門編⑰】LCDディスプレイに文字を表示させてみる![前編][1602 LCDモジュール] 【Arduino入門編⑯】サーボモーターをジョイスティックやシリアルモニタから動かしてみる! 【Arduino入門編⑮】Arduino Unoへの電力供給(外部電源)および電源出力端子の使い方!【追記】 【Arduino入門編⑭】センサーシールド(Sensor Shield)を使ってみる! 【Arduino入門編⑬】テスト環境に便利!Arduino拡張ボード(シールド)プロトタイプシールドを使ってみる! 【Arduino入門編⑫】光センサー(Cdsセル)をアナログ入力ポートで読み取り制御に使ってみる!

2 COMMENTS

ks

めっちゃわかりやすいです…
いつもほんと勉強になります
ありがとうございます師匠…

返信する

コメントを残す