■
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; } /* 以上 */