2015年3月14日土曜日

arduinoで3x3x3 LEDキューブを作ってみる






LEDキューブを作ってみました。
youtubeには、フルカラーLEDや、大量のLEDを使ったものの動画がたくさんありますが、手始めに3x3x3から。
27個のLEDを制御しないといけないので、ダイナミック点灯しなければなりません。
LEDに9本、段の選択に3本のIOピンを使います。

UNOで4x4x4以上なら、シフトレジスタやLEDドライバICが必要になってきますね。
RX、TXも使えば、ギリ4x4x4もできるかも?
でもatmega328Pの最大電流200mAも考慮しないといけなくなります。
3x3x3がお手軽でいい。

このサイズであれば、arduinoシールドに収まります。


LEDの電流を20mAで計算するとトランジスタ1815では定格をオーバーするので、NchMOSFET 2N7000を使いましたが、手持ちのLEDで220Ωならギリギリ1815でもいけてたはず。
段ごとのFETはPWMを使えるピンにつなぎましたが、以下のスケッチではPWMを使っていません。

使ったLEDは3mm、間隔は約18mm
ダンボールに穴を開けて差し込みハンダ付けします。
基板は秋月のarduino用ユニバーサル基板

アノードは2箇所、カソードは1箇所で曲げ

カソードは全部接続できれば、つなぎ方はなんでもOK
アノードと接触しないように

3段分作り

上下のアノード同士を接続
 

電流制限抵抗を隙間から差し込むのは苦労します

各段からGNDを伸ばしFETに接続
スケッチでは1段のLEDをこの写真↑の角度から見て
678
345
012 と割り当てています。led[0]は左下のLEDが接続されているピン番号を示す。
level[]で各段のFETを接続されているピン番号を示す。level[0]は下段。

完成

基板の空きにatmega328P乗せられそう。



// 3x3x3 LED cube
//     http://cranberrytree.blogspot.jp/2015/03/arduino3x3x3-led.html
//         2015/3/14    by cranberry

const byte led[9]    = {3, 2, 8, 4, 5, 7, A2, A3, A1};//0~9番LEDが、どのピンにつながっているのか
const byte level[3]  = {11, 10, 9};                   //例)level[0]は下段のFETをONにするピン番号
bool state[3][9]     = {};                            //各LEDのON/OFFを保存

void setup(){
  Serial.begin(9600);
  for(byte i = 0; i < 9; i++){         // LEDを接続したピンの初期化
    pinMode(led[i], OUTPUT);
    digitalWrite(led[i], LOW);
  }
  for(byte i = 0; i < 3; i++){         // FETを接続したピンの初期化
    pinMode(level[i], OUTPUT);
    digitalWrite(level[i], LOW);
  }
  randomSeed(analogRead(0));
}

void loop(){
  all(1000);
  updown(5000);
  wall(5000);
  cycle(5000);
  random_poll(5000);
  random_3(5000);
  random_2(5000);
  random_led(5000);
}

void reflect_state(int val){       // state[][]の内容に従ってLEDをON/OFF   val:フレーム数
  int j = 0;
  while(j < val){
    for(byte z = 0; z < 3; z++){
      for(byte num = 0; num < 9; num++){
        digitalWrite(led[num], state[z][num]);
      }
      digitalWrite(level[z], HIGH);
      delay(1);
      digitalWrite(level[z], LOW);
    }
    j += 1;
  }
}

void init_state(){
  for(byte z = 0; z < 3; z++){     // 変数の初期化
    for(byte i = 0; i < 9; i++){
      state[z][i] = 0;
    }
  }
  for(byte i = 0; i < 9; i++){     // LEDを接続したピンを全部LOW
    digitalWrite(led[i], LOW);
  }
  for(byte i = 0; i < 3; i++){     // FETを接続したピンを全部LOW
    digitalWrite(level[i], LOW);
  }
}

void updown(int dur){              // dur:実行する時間 ms
  init_state();
  unsigned long st = millis();
  char z = 0;
  char a = 1;
  while(millis() - st < dur){
    for(byte i = 0; i < 9; i++){
      state[z][i] = 1;
    }
    reflect_state(50);
    for(byte i = 0; i < 9; i++){
      state[z][i] = 0;
    }
    z += a;
    if(z == 3){
      a = -1;
      z = 1;
    }
    else if(z == -1){
      a = 1;
      z = 1;
    }
  }
}

void wall(int dur){              // dur:実行する時間 ms
  init_state();
  unsigned long st = millis();
  char cnt = 0;
  char a = 1;
  while(millis() - st < dur){
    for(byte z = 0; z < 3; z++){
      if(cnt == 0){
        state[z][0] = 1;
        state[z][3] = 1;
        state[z][6] = 1;
      }
      if(cnt == 1){
        state[z][1] = 1;
        state[z][4] = 1;
        state[z][7] = 1;
      }
      if(cnt == 2){
        state[z][2] = 1;
        state[z][5] = 1;
        state[z][8] = 1;
      }
    }
    reflect_state(50);
    init_state();
    cnt += a;
    if(cnt == 3){
      cnt = 1;
      a = -1;
    }
    if(cnt == -1){
      cnt = 1;
      a = 1;
    }
  }
}

void cycle(int dur){              // dur:実行する時間 ms
  init_state();
  unsigned long st = millis();
  while(millis() - st < dur){
    byte num[8] = {0, 1, 2, 5, 8, 7, 6, 3};
    for(byte i = 0; i < 8; i++){
      digitalWrite(led[ num[i] ], HIGH);
      for(byte z = 0; z < 3; z++){
        digitalWrite(level[z], HIGH);
        delay(15);
        digitalWrite(level[z], LOW);
      }
      digitalWrite(led[ num[i] ], LOW);
    }
  }
}

void all(int dur){              // dur:実行する時間 ms
  init_state();
  unsigned long st = millis();
  for(byte num = 0; num < 9; num++){
    digitalWrite(led[num], HIGH);
  }
  while(millis() - st < dur){
    for(byte z = 0; z < 3; z++){
      digitalWrite(level[z], HIGH);
      delay(1);
      digitalWrite(level[z], LOW);
    }
  }
}

void random_led(int dur){              // dur:実行する時間 ms
  init_state();
  unsigned long st = millis();
  while(millis() - st < dur){
    for(byte z = 0; z < 3; z++){
      for(byte i = 0; i < 9; i++){
        state[z][i] = random(2);     // 0 or 1
      }
    }
    reflect_state(40);
  }
}

void random_poll(int dur){              // dur:実行する時間 ms
  init_state();
  unsigned long st = millis();
  while(millis() - st < dur){
    byte num = random(9);
    int j = 0;
    digitalWrite(led[num], HIGH);
    while(j < 30){
      for(byte z = 0; z < 3; z++){
        digitalWrite(level[z], HIGH);
        delay(1);
        digitalWrite(level[z], LOW);
      }
      j += 1;
    }
    digitalWrite(led[num], LOW);
  }
}

void random_2(int dur){
  init_state();
  unsigned long st = millis();
  while(millis() - st < dur){
    byte num = random(9);
    byte z = random(3);
    state[z][num] = 1;
    reflect_state(20);
  }
}

void random_3(int dur){
  init_state();
  unsigned long st = millis();
  while(millis() - st < dur){
    byte num = random(9);
    byte z = random(3);
    state[z][num] = 1;
    reflect_state(20);
    state[z][num] = 0;
  }
}





参考にしたスケッチはないですが、うまく書かないと明るさとちらつきのバランスがうまくいかないですね。
速度を上げる方法として、digitalWrite();ではなく、PORTレジスタを直接書き換える方法もあるようですが・・・




環境:arduinoUNO、arduinoIDE1.6.0、win7(64)

0 件のコメント:

コメントを投稿