3x3x3 の Arduino LED CUBE Shield用スケッチ。

/**
 * BlueLEDCube 3x3x3 割り込みあり版
 * 
 * Timer1 ライブラリは http://playground.arduino.cc/code/timer1 よりダウンロードし、
 * IDEの環境設定にあるスケッチブックの保存先フォルダ内のlibrariesフォルダに展開したものをコピーする。
 * IDEを立ち上げ直し、ファイル→スケッチの例→TimerOneの表示が出ればOK。
 * 
 * Written:ohguma 2013-06-28
 */
#include <TimerOne.h>

//高さ(z軸)
#define NUM_HEIGHT 3
//奥行(y軸)
#define NUM_DEPTH 3
//幅(x軸)
#define NUM_WIDTH 3

#define NUM_ALL NUM_HEIGHT * NUM_DEPTH * NUM_WIDTH

//1パターンごとの表示時間(秒)
#define PERIOD 10

//縦列(Anode)に繋ぐピン設定。
byte pin_anode[NUM_DEPTH][NUM_WIDTH ] = {  
  {2,3,4},
  {5,6,7},
  {8,9,10},
};

//階層(Cathode)に繋ぐピン設定
//0 -> 1F, 1 -> 2F,  2 -> 3F
byte pin_cathode[NUM_HEIGHT] = {14, 15, 16};

//発光パターンのメモリ・その1
//パターン作成途中に割り込みの影響をうけないように、メモリを分ける
boolean led[NUM_HEIGHT][NUM_DEPTH][NUM_WIDTH];

//発光パターンのメモリ・その2
//こちらは割り込みのダイナミック点灯で使用する実際の発光パターン
boolean led4light[NUM_HEIGHT][NUM_DEPTH][NUM_WIDTH];


/**
 * 初期設定
 */
void setup()
{
  Serial.begin(9600);
  //ピン設定
  setUpPin();
  //ダイナミック点灯用(microsecond周期)
  Timer1.initialize((long) 1000); //1ms
  Timer1.attachInterrupt(dynamicLighting);
}


//TheLoop
void loop()
{
  static unsigned int pat_before = 999;
  unsigned int pat;
  unsigned long dt;
  boolean rst = false;
  
  //経過時間よりパターン決定
  pat = (millis() / 1000  / PERIOD) % 5;
  dt = getTimeSinceLastFrame();

  if (pat != pat_before) {
    //パターン切り替え時の処理
    lightNone();  
    delay(100);
    pat_before = pat;
    rst = true;
  }
  switch(pat) {
    case 4:
      twist(dt, rst);
      break;
    case 3:
      panel(dt, rst);
      break;
    case 2:
      wave(dt, rst);      //波
      break;
    case 1:
      increment(dt, rst); //一つづづ追加
      break;
    default:
      lightAll();         //全点灯
  }

  //発光パターンをコピー
  memcpy(&led4light, &led, sizeof(boolean) * NUM_ALL);
  //以下と同義。
  /*
  for (byte z = 0 ; z < NUM_HEIGHT; z++) {
    for (byte y = 0 ; y < NUM_DEPTH; y++) {
      for (byte x = 0 ; x < NUM_WIDTH; x++) {
        led4light[z][y][x] = led[z][y][x];
      }
    }
  }
  */
}


/**
 * ツイスト
 */
void twist(unsigned long dt, boolean rst)
{
  static float posTime = 0;
  //外周部分の縦列番号
  static byte xouter[(NUM_WIDTH + NUM_DEPTH - 2) * 2];
  static byte youter[(NUM_WIDTH + NUM_DEPTH - 2) * 2];
  byte num = (NUM_WIDTH + NUM_DEPTH - 2) * 2;
  byte x;
  byte y;
  byte i = 0;
  if (rst) {
    lightNone();
    posTime = 0;
    //CW
    for(x = 0 ; x < NUM_WIDTH - 1; x++) {
      xouter[i] = x;
      youter[i] = 0;
      i++;
    }
    for(y = 0 ; y < NUM_DEPTH - 1; y++) {			
      xouter[i] = NUM_WIDTH - 1;
      youter[i] = y;
      i++;
    }
    for(x = NUM_WIDTH - 1 ; x > 0; x--) {
      xouter[i] = x;
      youter[i] = NUM_DEPTH - 1;
      i++;
    }
    for(y = NUM_DEPTH - 1 ; y > 0; y--) {			
      xouter[i] = 0;
      youter[i] = y;
      i++;
    }   
  } else {
    posTime += 1.0*dt / 1000 / 50;
  }
  long pos = ((long) posTime) % num;
  byte zz;
  for(byte z = 0; z < NUM_HEIGHT; z ++) { 
    zz = (pos + z) % num; 
    for(byte y = 0 ; y < NUM_DEPTH ; y++) {			
      for(byte x = 0 ; x < NUM_WIDTH ; x++) {
        led[z][y][x] = (y == xouter[zz] && x == youter[zz]);        
      }
    }
  }
}
 

/**
 * 平面
 */
void panel(unsigned long dt, boolean rst)
{
  static float posTime = 0;
  if (rst) {
    posTime = 0;
  } else {
    posTime += 1.0*dt / 1000 / 50;
  }
  long pos = ((long) posTime) % (NUM_HEIGHT + 1);
  Serial.println(pos);
  for(byte z = 0; z < NUM_HEIGHT; z ++) { 
    for(byte y = 0 ; y < NUM_DEPTH ; y++) {			
      for(byte x = 0 ; x < NUM_WIDTH ; x++) {
        led[z][y][x] = (pos == z);        
      }
    }
  }
}


/**
 * 波
 */
void wave(unsigned long dt, boolean rst)
{
  static float runTime = 0;
  int half_width = int(0.5 * NUM_WIDTH);
  int half_depth = int(0.5 * NUM_DEPTH);
  float xfloat;
  float yfloat;
  float zfloat;
  int zint;
  if (rst) {
    runTime = 0;
  } else {  
    runTime += 1.0*dt / 1000 / 1000;
  }
  for(byte y = 0 ; y < NUM_DEPTH ; y++) {			
    yfloat = (y - half_depth);
    for(byte x = 0 ; x < NUM_WIDTH ; x++) {
      xfloat = (x - half_width);
      zfloat = (cos(xfloat * xfloat + yfloat * yfloat - runTime * 10) + 1) * .5 * NUM_HEIGHT;
      zint = constrain(int(zfloat + 0.5), 0, NUM_HEIGHT - 1);
      for (byte z = 0 ; z < NUM_HEIGHT; z++) {
        led[z][y][x] = (z == zint);
      }
    }		
  }
}


/**
 * 一つづづ追加
 */
void increment(unsigned long dt, boolean rst)
{
  static float posTime = 0;
  if (rst) {
    posTime = 0;
  } else {
    posTime += (NUM_ALL + 1.0) / PERIOD * dt / 1000 / 1000;
  }
  long pos = ((long) posTime) % (NUM_ALL + 1);
  if (pos == NUM_ALL) {
    lightNone();
  } else {
    byte x = pos % NUM_WIDTH;
    byte y = ((pos - x) / NUM_WIDTH % NUM_DEPTH);
    byte z = (pos - y * NUM_WIDTH - x) / (NUM_WIDTH * NUM_DEPTH);  
    led[z][y][x] = true;
  }
}


/**
 * 全点灯
 */
void lightAll()
{
  for (byte z = 0 ; z < NUM_HEIGHT; z++) {
    for (byte y = 0 ; y < NUM_DEPTH; y++) {
      for (byte x = 0 ; x < NUM_WIDTH; x++) {
        led[z][y][x] = true;
      }
    }
  }
}


/**
 * 全消灯
 */
void lightNone()
{
  for (byte z = 0 ; z < NUM_HEIGHT; z++) {
    for (byte y = 0 ; y < NUM_DEPTH; y++) {
      for (byte x = 0 ; x < NUM_WIDTH; x++) {
        led[z][y][x] = false;
      }
    }
  }
}


/**
 * 階層ごとのダイナミック表示
 * TimerOneの割り込みを使い、1msごとに表示階層を切り替える。
 */
void dynamicLighting()
{
  //現在表示中の階層
  //staticキーワードがあると関数が繰り返し呼ばれる間も値を保持する。
  static int current_layer = 0;
  //表示中の階層を消灯
  digitalWrite(pin_cathode[current_layer], LOW);
  //次の階層を選択
  current_layer++;
  current_layer %= NUM_HEIGHT;
  //次の階層のXY平面のパターンセット
  for (byte y = 0 ; y < NUM_DEPTH; y++) {
    for (byte x = 0 ; x < NUM_WIDTH; x++) {
      digitalWrite(pin_anode[y][x], led4light[current_layer][y][x]);
    }
  }
  //次の階層を点灯
  digitalWrite(pin_cathode[current_layer], HIGH);
}


/**
 * ピンの初期化
 */
void setUpPin()
{
  //縦列(Anode)に繋ぐのピンの初期化
  for (byte y = 0 ; y < NUM_DEPTH; y++) {
    for (byte x = 0 ; x < NUM_WIDTH; x++) {
      pinMode(pin_anode[y][x], OUTPUT);
    }
  }
  //階層(Cathode)に繋ぐピンの初期化
  for(byte z = 0; z < NUM_HEIGHT; z++){
    pinMode(pin_cathode[z], OUTPUT);
  }
}


/**
 * 最後にこの関数を呼んでからの時間(micro秒)を返す
 *
 * @return unsigned long  
 */
unsigned long getTimeSinceLastFrame()
{
  static unsigned long lastTime = 0;
  unsigned long dt = micros() - lastTime;
  lastTime = micros();
  return dt;
}


/* 以上 */