前回はLEDのPWMの考え方を学び、明るさ制御について実装しました。
PWMについて学んだ後は、それを利用してバーLEDアレイを制御し、流れるようなおしゃれな照明を実現することができます。部品リスト、回路、ハードウェアはすべて、プロジェクト「Flowing Light」のものと同じです。
ledに接続するGPIOピンはGPIO1とGPIO48を抜いて、バーLEDの右端2つを使わないように左に寄せておきましょう
接続図は以下のとおりです。
今回のコードはこちらです。
今回は今までよりも難しいので、壁にぶつかったような感覚になるかもしれません。ですが、守破離の『守』を思い出して、まずはコピペして動けばOKという程度に軽く考えましょう!楽しむことが何より大事です。
/**********************************************************************
Filename : FlowingLight2
Description : More cool flowing light.
Auther : www.freenove.com
Modification: 2022/10/20
**********************************************************************/
const byte ledPins[] = {21, 47, 38, 39, 40, 41, 42, 2}; //define led pins
const byte chns[] = {0, 1, 2, 3, 4, 5, 6, 7}; //define the pwm channels
const int dutys[] = {0, 0, 0, 0, 0, 0, 0, 0,
1023, 512, 256, 128, 64, 32, 16, 8,
0, 0, 0, 0, 0, 0, 0, 0
}; //define the pwm dutys
int ledCounts;
int delayTimes = 50; //flowing speed ,the smaller, the faster
void setup() {
ledCounts = sizeof(ledPins); //get the led counts
for (int i = 0; i < ledCounts; i++) { //setup the pwm channels
ledcSetup(chns[i], 1000, 10);
ledcAttachPin(ledPins[i], chns[i]);
}
}
void loop() {
for (int i = 0; i < 16; i++) { //flowing one side to other side
for (int j = 0; j < ledCounts; j++) {
ledcWrite(chns[j], dutys[i + j]);
}
delay(delayTimes);
}
for (int i = 0; i < 16; i++) { //flowing one side to other side
for (int j = ledCounts - 1; j > -1; j--) {
ledcWrite(chns[j], dutys[i + (ledCounts - 1 - j)]);
}
delay(delayTimes);
}
}
動作させるとこうなります。可愛いですね。より一層ナイト2000になりました。
コード解説
まずは7~14行目を見てみましょう。
const byte ledPins[] = {21, 47, 38, 39, 40, 41, 42, 2}; //define led pins
const byte chns[] = {0, 1, 2, 3, 4, 5, 6, 7}; //define the pwm channels
const int dutys[] = {0, 0, 0, 0, 0, 0, 0, 0,
1023, 512, 256, 128, 64, 32, 16, 8,
0, 0, 0, 0, 0, 0, 0, 0
}; //define the pwm dutys
int ledCounts;
int delayTimes = 50; //flowing speed ,the smaller, the faster
7行目で使用するGPIOピンを配列に格納しています。
8行目はPWMのチャネル番号を配列に格納しています。
9~12行目でデューティー比をどのように変化させるかという値を格納しています。
14行目は各待ち合わせの時間です。ここで定義しておくことで、後で好みに応じて修正する際に、一か所だけ修正すればよいので扱いやすくなっていますね。
続いてメインループについてです。
loop() 関数では、ネストした(入れ子の)for ループを使用して PWM のパルス幅を制御しています。1つ目の for ループで i に 1 を加算するたびに、LED バーグラフの表示が1つずつ右に移動します。この変化は duties 配列の値によってコントロールされます。以下の表のように、2行目の値が duties 配列の値に、各行の8つの緑色の四角がLED バーグラフの8つのLEDに対応しています。 i に1が加算されるたびに、LED バーグラフの表示は1つ右に移動し、右端に到達すると左端に戻り、目的の効果を実現します。
ちょっと難しいですが、ゆっくりと、iとjを一つずつ計算しながら動作をトレースしてみてください。そうすると「あぁ~、なるほど!」となると思います。
最初はdelayTimesを大きめにしてゆっくりと動作を追いかけてもいいかもしれません。
void loop() {
for (int i = 0; i < 16; i++) { //flowing one side to other side
for (int j = 0; j < ledCounts; j++) {
ledcWrite(chns[j], dutys[i + j]);
}
delay(delayTimes);
}
for (int i = 0; i < 16; i++) { //flowing one side to other side
for (int j = ledCounts - 1; j > -1; j--) {
ledcWrite(chns[j], dutys[i + (ledCounts - 1 - j)]);
}
delay(delayTimes);
}
}
今回のようにネストが深くなると、コードの読解は難しくなります。ループに限らずifなどの条件分岐が深くなる時も、理解しづらくなってきます。優秀なエンジニアの書いたコードを読み解くのは至難の業になりがちです。技術的な意味で行間を読む力が必要になってきます。沢山コードをみて、慣れていく必要があります。
今の時代はプログラムを一から全部自分で作り出すという時代ではなくなりました。ネット検索や生成AIで簡単にコードを入手できる時代です。そんな時代だからこそ、今はコードを完全に理解しようとするよりも、どんな処理をしているかといった概要だけわかっているだけでも大丈夫です。概要が分かればコードを見つけ出すことができるはずです。
焦らずに少しずつやっていきましょう!
コメント