前回、前々回と2回にわたりArduinoのデジタル出力についてやってきました。
デジタル入出力ピン(D0~D13)やアナログ入力ピン(A0~A5)からdigitalWrite関数を使ってHIGH(5V)またはLOW(0V)を出力させてLEDを点灯や消灯させるといったものです。
今回は出力に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の点灯がどのように変化するか確認するためのスケッチとなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //Arduino入門編③ 擬似的にデジタルピンでPWM出力 //https://burariweb.info int LED_PIN = 8; // LEDを接続するピンを指定(デジタルピン8番) int WAIT_ON_TIME = 500; // 点灯している時間を変数に入れる int WAIT_OFF_TIME = 500; // 消灯している時間を変数に入れる void setup(){ pinMode(LED_PIN, OUTPUT); // デジタルピン8番を出力に設定 } void loop(){ digitalWrite(LED_PIN, HIGH); // LEDを点灯(5Vを出力) delay(WAIT_ON_TIME); // 指定時間停止 digitalWrite(LED_PIN, LOW); // LEDを消灯(0Vを出力) delay(WAIT_OFF_TIME); // 指定時間停止 } |
回路はこんな感じ。(LEDに接続している制限抵抗は今回470Ωを使用)
まず初期値では、変数WAIT_ON_TIME、WAIT_OFF_TIMEには共に500を指定しており0.5秒(500ms)間隔でLEDが点灯・消灯を繰り返すようになっています。
ここまでは前回と同じですね!
それでは短い点滅サイクルの中でこの点灯・消灯の時間の間隔(割合)を変化させていくとどうなるか?
先程のスケッチの先頭にある変数部分の値を下のように変えてみて下さい。
5 6 7 | int LED_PIN = 8; // LEDを接続するピンを指定(デジタルピン8番) int WAIT_ON_TIME = 10; // 点灯している時間を変数に入れる int WAIT_OFF_TIME = 10; // 消灯している時間を変数に入れる |
この状態ではLEDは明るく点灯している状態になります。
それでは、WAIT_OFF_TIME変数の値はこのまま10(0.01秒消灯)に固定しておき、点灯している時間WAIT_ON_TIME変数の値を10、9、8・・・と少しずつ小さくしていくとLEDの点灯はどう変化するか?
LEDが点灯している時間が短くなるとそれに伴いLEDも暗くなるのが確認出来るかと思います。
つまり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マイコンボード上でパルスを発生させるので(タイマー割り込み)、先ほど述べたようにプログラムの動作に影響する事なく安定して出力させる事ができます。
PWMでLEDの明るさを制御する
PWMについて理解できたところで、実際にこれを使いLEDを点灯させてみましょう。
簡単なテストスケッチとしてこちらを用意しました。
DUTYという変数の値を変えることによりLEDの明るさが変化します。(0~255)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //Arduino入門編③ PWM出力でLEDを点灯 //https://burariweb.info int LED_PIN = 9; // PWM出力させるピン番号を指定 int DUTY = 255; // デューティー比を指定(0~255) void setup(){ pinMode(LED_PIN, OUTPUT); // 指定ピンを出力(OUTPUT)に設定 // pinMode関数はPWM出力では省略可! } void loop(){ analogWrite(LED_PIN, DUTY); // 指定ピンにアナログ値(PWM)を出力 } |
先程の回路を少し繋ぎ直し、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関数があります。
15 16 17 18 19 | void loop(){ analogWrite(LED_PIN, DUTY); // 指定ピンにアナログ値(PWM)を出力 } |
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を点灯させる事が出来ました。
分かりやすいようにこのスケッチでは記述しましたが、analogWrite関数でPWM出力させる場合この記述は省略することも出来ます。
LEDをゆっくり点灯・消灯させてみる
上記スケッチでanalogWrite関数を使いアナログ出力(PWM)について理解できたと思います。
それでは最後にLEDをゆっくり点灯・ゆっくり消灯させるスケッチも試してみましょう。
このようなサンプルスケッチを用意しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //Arduino入門編③ PWM出力でLEDをゆっくり点灯&消灯 //https://burariweb.info int LED_PIN = 9; // PWM出力させるピン番号を指定 int WAIT_TIME = 10; // 待ち時間を指定 int STEP = 1; // デューティー比の変化(ステップ数) void setup(){ } void loop(){ int i = 0; while(i <= 255){ // 変数iが255より小さい時繰り返し以下を実行 analogWrite(LED_PIN, i); // iの値をデューティー比としてPWM出力 delay(WAIT_TIME); // 指定時間停止 i = i + STEP; // 変数iをSTEP分増加させる } i = 255; while(i >= 0){ // 変数iが0より大きい時繰り返し以下を実行 analogWrite(LED_PIN, i); // iの値をデューティー比としてPWM出力 delay(WAIT_TIME); // 指定時間停止 i = i - STEP; // 変数iをSTEP分減少させる } } |
これまでのスケッチではpinMode関数で使用するピンを指定し出力(OUTPUT)に設定していました。
PWM出力にはanalogWrite関数を使いますが、PWMで使えるピンは決まっており出力(OUTPUT)での使用が前提なので省略する事が出来ます。(記述しても問題はないです)
while関数を使いデューティー比を0〜255に変化させLEDをゆっくりと点灯させています。
17 18 19 20 21 22 | int i = 0; while(i <= 255){ // 変数iが255より小さい時繰り返し以下を実行 analogWrite(LED_PIN, i); // iの値をデューティー比としてPWM出力 delay(WAIT_TIME); // 指定時間停止 i = i + STEP; // 変数iをSTEP分増加させる } |
またデューティー比を255〜0に変化させ、ゆっくりとLEDを消灯させています。
24 25 26 27 28 29 | i = 255; while(i >= 0){ // 変数iが0より大きい時繰り返し以下を実行 analogWrite(LED_PIN, i); // iの値をデューティー比としてPWM出力 delay(WAIT_TIME); // 指定時間停止 i = i - STEP; // 変数iをSTEP分減少させる } |
while 関数
【書式】while( 条件式 ) { 実行文 }
条件式に当てはまる場合、ループで(実行文)が繰り返し実行されます。
スケッチ先頭にあるSTEPという変数でデューティー比の増減値を変える事が出来るので(初期値は1にしています)、この値を変えてLEDの点灯の変化なども試して下さいね。
今回使った関数(コマンド)まとめ
今回新たに出てきたArduinoのコマンド(関数)をまとめておきます。
関数 | 使用方法 |
analogWrite(pin, value); | 指定したピンにアナログ値(PWMパルス)を出力します。 LEDの輝度を調整したり、モーターの回転速度を変えたり、サーボモーターの制御などに使われます。 【書式】analogWrite(pin, value); ※デジタル出力のように事前に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の制御も出来ます。
このあたり次回ご紹介出来たらと思います。
めっちゃわかりやすいです…
いつもほんと勉強になります
ありがとうございます師匠…
おおー、ありがとうございます(^o^)