その賢い方法は? というと、図1の様な方法だ。例えばLEDの1番と2番を同時に点灯したければ、4・5番ピンを同時に+5V、2番ピンを0Vにすればよい。こうすれば、2つのLEDがどちらも定格の輝度で点灯することになる。ついでに6番ピンも+5Vにすれば、1~3番が同時に点灯することになる。

図1:

ここで3番pinも0Vにすれば、理論上は1~6番の全部のLEDが点灯することになるのだが、実際はそうは問屋が卸さない。例えば図1のケースで3番ピンを0Vにすると、4番と5番のLEDも同時に点灯することになる。それが目的ならばかまわないが、例えば「4番LEDは点灯したいが5番LEDを点灯したくない」なんて場合はこの方式ではうまくいかない。

もうひとつの問題は、Arduinoが駆動できる電力と全体の供給電力の問題である。Arduinoに搭載されるATmega328の場合、Digital I/Oで出力できる最大の電力は40mAであり、またATmega328全体として5Vラインから供給できる電力は200mAとされている。なので、今回利用しているOSDR3133Aの場合、1つのピンに2つぶら下げるとそれだけで40mAだし、全体としては10個を同時に点灯するのがやっとという事になる。これを超えてLEDを駆動したい、なんて場合は外部に別途ドライバが必要になるだろう。というわけで、図1のケースでは1~3番と4~6番のLEDをそれぞれ時間差で駆動する形になるが、これだけでもだいぶ前回よりは改善されることになる。

ということで、List 1がこれのSketchである。ついにLoop()の中が4重ループになってしまい、見にくいこと夥しいのだがご容赦いただきたい。まずTableであるが、今度は持ち方を変えて「点灯するLEDが0~6個の場合、それぞれD04~06の何本をHIGHにするか」を、D02/03のそれぞれについて格納している。例えば4番目(LEDを3つ点灯)の場合、D02が0Vの場合はD04~06を全部5V、D03が0Vの場合はD04~D06は全部0Vを示す。5番目、つまりLEDが4つ点灯の場合は、D02が0VならD04~D06は全部5V、D03が0VならD04のみ5Vという意味だ。setup()は前回と同じだが、loop()の中はだいぶ変わっている。

List 1:

int Table[7][2]={{0,0},{1,0},{2,0},
                 {3,0},{3,1},{3,2},{3,3}};

void setup()
{
  int lpCnt;

  for(lpCnt=2; lpCnt<4; lpCnt++)  /* Pin 2~3が対象 */
  {
    pinMode(lpCnt, OUTPUT); /* 当該PinをDigital Outに設定 */
    digitalWrite(lpCnt, HIGH);  /* 初期値は消灯 */
  }

  for(lpCnt=4; lpCnt<7; lpCnt++)  /* Pin 4~6が対象 */
  {
    pinMode(lpCnt, OUTPUT); /* 当該PinをDigital Outに設定 */
    digitalWrite(lpCnt, LOW);  /* 初期値は消灯 */
  }
}

void loop()
{
  int lpCnt, lpCnt2, lpCnt3, lpCnt4;

  for(lpCnt=0; lpCnt < 7; lpCnt++)  /* 「同時」に点灯するLEDの数 */
  {
    for(lpCnt2=0; lpCnt2<500; lpCnt2++)  /* 繰り返し数 */
    {
      for(lpCnt3=0; lpCnt3 < 2; lpCnt3++) /* カソード側ピン番号 */
      {
        digitalWrite(lpCnt3+2, LOW);  /* カソード側を0Vに */
        for(lpCnt4=0; lpCnt4 < Table[lpCnt][lpCnt3]; lpCnt4++)
        {
          digitalWrite(lpCnt4+4, HIGH); /* アノード側を5Vに */
        }
        delay(1);                  /* 1ms待機 */
        for(lpCnt4=0; lpCnt4 < Table[lpCnt][lpCnt3]; lpCnt4++)
        {
          digitalWrite(lpCnt4+4, LOW); /* アノード側を0Vに */
        }
        digitalWrite(lpCnt3+2, HIGH);  /* カソード側を5Vに */
      }
    }
  }
}

基本的なパターンは、

D2を0Vにセット
  D4~D6を必要に応じて5Vにセット
  1ms待機
  5VにセットしたD4~D6を0Vに戻す
D2を5Vにセット
D3を0Vにセット
  D4~D6を必要に応じて5Vにセット
  1ms待機
  5VにセットしたD4~D6を0Vに戻す
D3を5Vにセット

というループで、D4~D6の0V/5Vの設定をlpCnt4という最内側のループで、D2/D3の0V/5Vの設定をlpCnt3という2番目のループで処理している。lpCnt2という3番目のループは待機時間である。lpCnt3までは一周1ms+α(ATMegaの処理時間+PinのdigitalWrite()に要する時間が掛かるから、多少増える。とはいえ2msになるほどではない)掛かるので、これを500回繰り返せば概ね0.5秒になる。最外周のlpCntは点灯するLEDの数を0~7個に順次切り替えている。

Movie01に実際に点灯している様子を示したが、0.5秒よりはもう少し周期が長いので、lpCnt2の繰り返し回数を少し減らしたほうがよさそうではあるが、それはともかくとして前回に比べると遥かに輝度が確保できていることがわかるだろう。

動画
Movie01:

この方式を使うことで、18pinのArduinoなら最大81個(9×9)のLEDを駆動することが可能である。ただ、実はもっと多数のLEDを駆動することも出来る、という話は次回。

(続く)