Project 3.1 配列と繰り返し/Flowing Light

前回までで単独のLEDを制御することを学びました。

あわせて読みたい
Project 2.2 デバウンス/MINI table lamp 前回はLEDをスイッチで制御しました。 https://kaneshige.org/?p=175 今回はスイッチの動作を変えます。スイッチを一度押すとLEDが点灯して、もう一度押すと消灯するよ...

今回は複数のLEDを制御する方法を学びます。

このプロジェクトでは、複数のLEDを使用して流れる光を作ります。ナイトライダーですね。(ご存知ない若い方は画像検索してみて下さい)

今回使う部品は『バーLEDアレイ』です。freenoveのマニュアルだとLEDバーグラフと書いてあります。

全部で20ピンありますが、内部的には10個の独立したLEDが並んでいるだけですので、難しく考える必要はありません。

以下のような回路を作ります。

物理的な接続図は以下の通り。

コードは以下の通り。

/**********************************************************************
  Filename    : FlowingLight
  Description : Using ledbar to demonstrate flowing lamp.
  Auther      : www.freenove.com
  Modification: 2022/10/20
**********************************************************************/
byte ledPins[] = {21, 47, 48, 38, 39, 40, 41, 42, 2, 1};
int ledCounts;

void setup() {
  ledCounts = sizeof(ledPins);
  for (int i = 0; i < ledCounts; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < ledCounts; i++) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }
  for (int i = ledCounts - 1; i > -1; i--) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }
}

動かすとこうなります。可愛いですね~。フォンフォン言ってます。

動かなかったときは、LEDには極性があるという話を思い出してください。バーLEDアレイモジュールを逆さまにつけ直しましょう。

ちなみに、私は面倒くさがりなので、抵抗のリード線を切らずに長いまま刺していますが、ニッパー等で適度に短くしていただいた方が良いです。その方がショートする危険性も無いですし。(ショートすると、乾電池程度の電力でも発火することがありますのでお気をつけ下さい。経験者は語る)

目次

コード解説

まずは7行目を見てみましょう。

/**********************************************************************
  Filename    : FlowingLight
  Description : Using ledbar to demonstrate flowing lamp.
  Auther      : www.freenove.com
  Modification: 2022/10/20
**********************************************************************/
byte ledPins[] = {21, 47, 48, 38, 39, 40, 41, 42, 2, 1};
int ledCounts;

void setup() {
  ledCounts = sizeof(ledPins);
  for (int i = 0; i < ledCounts; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < ledCounts; i++) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }
  for (int i = ledCounts - 1; i > -1; i--) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }
}

これは配列というものです。LEDに接続した10個のGPIOピンをコンマ区切りで書いています。

先頭の『byte』は変数の型を定義しています。変数の型によってどのくらいのメモリを確保するかが変わります。byte型の場合は1バイトです。配列に10個の値を入れているので全部で10バイトです。1バイトで表現できる数字は0から255までです。1バイトは8ビットなので、2進数の00000000~11111111です。

8行目の『int』も変数の型で、int型です。日本語では整数型で、4バイトです。値の範囲は-2,147,483,648から2,147,483,647までです。7行目のピン番号程度であれば、せいぜい二桁なので、同じ整数とはいえど4バイトものメモリは必要ないですね。

つづいて11行目を見てみましょう。

  ledCounts = sizeof(ledPins);

sizeofは変数や配列のメモリをバイト数で返します。ledPins変数はバイト型で10個の配列なので、ledCountには10が格納されます。今後ledCountと出てくるところは、全て10と書いておいても良いですが、動的に数を数えることで、配列を増やしたときの書き換えの手間を減らせるので、バグが起きにくくなります。

続いて12~14行目です。

  for (int i = 0; i < ledCounts; i++) {
    pinMode(ledPins[i], OUTPUT);
  }

forは繰り返しです。繰り返しの条件が()内に書いてあります。

初期式; 継続条件式; 処理式;

という名称が教科書的な表現ですね。ここでは

『0からledCount(10)未満の間1ずつ足していく』

という意味になっています。

プログラムでは繰り返しのカウンターとしてiという変数をよく使います。

カウントアップするときは『i++』という書き方をします。やっていることは

『i=i+1』

と同じです。

10回繰り返しながら、ピンモードを初期化している処理ですね。

ledPins[i]はledPins配列のi番目という意味です。配列は0番から始まります。

次に18~27行目です。

  for (int i = 0; i < ledCounts; i++) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }
  for (int i = ledCounts - 1; i > -1; i--) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }

2つの繰り返しがありますね。

19行目でi番目のピンを点灯させています。

100ミリ秒待機して

21行目で消灯しています。

これを10個のピンに対して順に行います。

10個分繰り返したら23行目のforです。

今度は繰り返しの各式が変わっていますね。

初期式の『int i = ledCounts – 1』ではledCountsが10なので1引いて初期値9が設定されます。

継続条件式ではiが-1より大きい間という条件ですね。

最後は予測がつくでしょうか?iから1ずつ引くという意味ですね。

ですので9から0までの10回繰り返しです。

こうすることで、配列の9番目から0番目という順番で先程とは逆向きの動きを実現しています。

こういう考え方をするのが、いかにもプログラミングと言う感じです。

ピンの数が10個と決まっているなら、以下のようにベタ書きしても動作します。

digitalWrite(ledPins[0], HIGH);
delay(100);
digitalWrite(ledPins[0], LOW);
digitalWrite(ledPins[1], HIGH);
delay(100);
digitalWrite(ledPins[1], LOW);
digitalWrite(ledPins[2], HIGH);
delay(100);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[3], HIGH);
delay(100);
digitalWrite(ledPins[3], LOW);
digitalWrite(ledPins[4], HIGH);
delay(100);
digitalWrite(ledPins[4], LOW);
digitalWrite(ledPins[5], HIGH);
delay(100);
digitalWrite(ledPins[5], LOW);
digitalWrite(ledPins[6], HIGH);
delay(100);
digitalWrite(ledPins[6], LOW);
digitalWrite(ledPins[7], HIGH);
delay(100);
digitalWrite(ledPins[7], LOW);
digitalWrite(ledPins[8], HIGH);
delay(100);
digitalWrite(ledPins[8], LOW);
digitalWrite(ledPins[9], HIGH);
delay(100);
digitalWrite(ledPins[9], LOW);
digitalWrite(ledPins[9], HIGH);
delay(100);
digitalWrite(ledPins[9], LOW);
digitalWrite(ledPins[8], HIGH);
delay(100);
digitalWrite(ledPins[8], LOW);
digitalWrite(ledPins[7], HIGH);
delay(100);
digitalWrite(ledPins[7], LOW);
digitalWrite(ledPins[6], HIGH);
delay(100);
digitalWrite(ledPins[6], LOW);
digitalWrite(ledPins[5], HIGH);
delay(100);
digitalWrite(ledPins[5], LOW);
digitalWrite(ledPins[4], HIGH);
delay(100);
digitalWrite(ledPins[4], LOW);
digitalWrite(ledPins[3], HIGH);
delay(100);
digitalWrite(ledPins[3], LOW);
digitalWrite(ledPins[2], HIGH);
delay(100);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[1], HIGH);
delay(100);
digitalWrite(ledPins[1], LOW);
digitalWrite(ledPins[0], HIGH);
delay(100);
digitalWrite(ledPins[0], LOW);

まぁなんと長い!書いてて途中で嫌になっちゃいますね。

どちらで書いても良いですが、よりシンプルな方がミス(バグ)が減ります。

エンジニア的な表現でいうと、より美しく書くと言ったところです。

一つの動作をさせるプログラムの書き方は必ずしも一通りではないので、色々な書き方ができます。それをアルゴリズム(=手順)と言います。

プログラムを書くということは、アルゴリズムを考えることです。

そして、如何にして短く書くか、というのがプログラマーのスキルなんですね。もっとも、短くしようとしすぎたあまりバグが混入しているようでは、まだまだ青いわけですが。

次回はLEDの明るさを制御して『じわ~』っと点灯させてみましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

金重総合研究所の主席研究員。
子供の頃から研究者を目指し、ライフワークとして日々様々な研究をしています。
経営・マネジメント・金融・DXあたりが本職です。
私を採用したい人、私と一緒に働きたい人、一緒に知識を肥やしていきたい人はぜひお声がけ下さい。

コメント

コメントする

目次