【arduino】3 * 3 LED Cube 【光らせてみた】
こんばんは.1000chです. iOSのprovisioningfileを更新しますがなかなか終わらない->実はchromeだとできないよ☆ という流れに唖然としています. せめてアラートだしてくださいよappleさん...
さて,今回は前回作ったLEDキューブの制御プログラム紹介です! 大量のLEDを制御する参考になればと思います. なお,LEDキューブの作り方自体は前回の記事を参考にしてください.
それではいきます.
ダイナミック点灯とは
arduinoを使ってLEDを制御するにはどうすればよいでしょう?
答えは簡単.抵抗とLEDをつなぎ,アノード側をarduinoのdigital pinに,カソード側をGNDにつなぎ,digital pinのHIGH/LOWを切り替えるだけ.
では,LEDキューブのように大量のLEDを同時に制御するにはどうすればよいでしょう?
大量のdigital pinがあれば話は簡単なのですが,333でも27個のpinが必要になります. こりゃーとてもじゃないが対応できない.
このような話は何もLEDキューブに限った話ではありません. 例えばこんなやつ.
いわゆる"7セグ"とよばれるLEDです.これ,数字の各辺が1つ1つのLEDになっており,それら7つ+小数点の8つのLEDのon/offを制御することで数字を表現しているんですね. この例では4桁なので,8 * 4 = 32個ものLEDを制御する必要があります. ...これ,1つ1つ全制御するのはなかなか大変ですね.
このように大量のLEDを制御するための手法が,”ダイナミック点灯”というものです.
一言で言うと,「各桁を高速に,交互に点灯させる」という手法です.
人間の目には光学的に慣性が働くので(この表現が正しいかは置いといて),高速に様々なモノが光った場合,そのすべてが常時点灯しているように見るのです. よく漫画などで「早すぎて分身しているようにみえる..」なんてのがありますね,ようはそれのことです.
写真の例で言うと,まず9を点灯,次に9を消灯して1 を点灯,そして,4,0,また9.. と続けて行く感じです. これは,各桁の8つのLEDのうち,アノード側を共有し,カソード側を独立させることで実現できます(その逆もあります).点灯させたい側のカソードだけをLOWに,他をHIGHにすることで,アノード側を共有していても,対象となる桁だけが点灯できる,という仕組みですね.
詳しくは様々に解説しているサイトがありますので,ググってみてください.
LED Cube 制御プログラム
さて今回の場合,各段でカソードを共有し,縦に重ねた3つのLED間でアノードを共有しています.
回路図はこんな感じです. 1段目だけ制御したいときはBase-1をLOW,Base-2/3をHIGHにしてLED1~9を制御します. 1段目を微小時間点灯したのち,次に2段目,3段目と順に制御します. あとはこれをひたすら繰り返します. これら一連の流れが行われたとき,すべての段が同時に点灯しているように見える,ということになります.
さて,以下が制御プログラムになります.
/* * LEDCude * created_at:2014_04_14_01:17:05. * Last Change:2014_04_22_23:36:42. */ // 各pinの設定.定義後配列化しておく int BASE_0 = 12; int BASE_1 = 13; int BASE_2 = 2; int LED_0 = 3; int LED_1 = 4; int LED_2 = 5; int LED_3 = 6; int LED_4 = 7; int LED_5 = 8; int LED_6 = 9; int LED_7 = 10; int LED_8 = 11; int BASE_LIST[3] = {BASE_0,BASE_1,BASE_2}; int LED_LIST[9] = {LED_0,LED_1,LED_2,LED_3,LED_4,LED_5,LED_6,LED_7,LED_8}; // LEDキューブの状態.HIGH or LOWを格納 int led_state[3][3][3]; int LED_NUM = 27; int COUNT_MAX = 30; int count = 0; void setup(){ // 各pinのIN/OUT設定 pinMode(BASE_0,OUTPUT); pinMode(BASE_1,OUTPUT); pinMode(BASE_2,OUTPUT); pinMode(LED_0 ,OUTPUT); pinMode(LED_1 ,OUTPUT); pinMode(LED_2 ,OUTPUT); pinMode(LED_3 ,OUTPUT); pinMode(LED_4 ,OUTPUT); pinMode(LED_5 ,OUTPUT); pinMode(LED_6 ,OUTPUT); pinMode(LED_7 ,OUTPUT); pinMode(LED_8 ,OUTPUT); // LEDキューブの状態初期化 int i=0,j=0,k=0; for(i=0; i<3; i++){ for(j=0; j<3; j++){ for(k=0; k<3; k++){ led_state[i][j][k] = LOW; } } } randomSeed(analogRead(0)); } // openFrameworks風にループ内を分割 void loop(){ update(); action(); } // 状態の更新 void update(){ if(count >= COUNT_MAX){ // ランダムに状態変化 led_toggle(random(LED_NUM)); count = 0; } else { count++; } } // 状態の反映 void action(){ blink_cube(); } // **今回のポイント** // LEDキューブをダイナミック点灯 void blink_cube(){ int i=0,j=0,k=0; for(i=0; i<3; i++){ // i番目の段以外はHIGH digitalWrite(BASE_0,HIGH); digitalWrite(BASE_1,HIGH); digitalWrite(BASE_2,HIGH); digitalWrite(BASE_LIST[i],LOW); // 同一段内の9つのLEDを制御 for(j=0; j<3; j++){ for(k=0; k<3; k++){ digitalWrite(LED_LIST[j+k*3], led_state[i][j][k]); } } // 気持ち程度delay.なくてもok delay(2); } } // 指定番号のLEDの状態をトグル void led_toggle(int num){ int i,j,k; i = num / 9; j = (num % 9) / 3; k = num % 3; if(led_state[i][j][k] == HIGH){ led_state[i][j][k] = LOW; } else { led_state[i][j][k] = HIGH; } }
こんなかんじでうごいてます.
コレだけって地味だ!!w まぁ動作確認ということで.
arduinoは一度setup関数を呼んだ後,loop関数をひたすら繰り返してくれます. 今回はloop関数内にupdate/actionという二つの関数を用意し,openFrameworks風の制御構造にしてみました.
LED Cube点灯のポイントはblink_cube関数です.対象となる段のカソードのみLOWにして9つのLEDを制御,を繰り返しています. 一応delayを挟んでいますが,特に必要ないかもしれません. delay無しにしてtoggleの周期も短くしたりすると,全体常時点灯のようにみえるかもしれませんねw
それではみなさん,楽しい電子工作ライフを〜