diff --git a/FrameBuffer.cpp b/FrameBuffer.cpp new file mode 100644 index 0000000..dee2e8e --- /dev/null +++ b/FrameBuffer.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2018, Lionel Adrien Sambuc + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#include "FrameBuffer.h" + +/* All the code assumes dimensions are below 127, as signed chars are used to + * store positions and indices. */ +#define MAX_X 4 +#define MAX_Y 4 +#define MAX_Z 4 + +#define BRIGHTNESS_LEVELS 16 +#define BRIGHTNESS_MAX 256 + +// Positions (x,y) to pin, same for all layers. +static char position2pin[MAX_X][MAX_Y] = { + {13, 12, 11, 10}, + { 9, 8, 7, 6}, + { 5, 4, 3, 2}, + { 1, 0, A5, A4} +}; + +// z-coordinate position to pin. +static char layer[MAX_Z] = { A0, A1, A2, A3 }; + +static unsigned char font[][4][4] = { + // a + { + {0,0,0,0}, + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,1}, + }, + // b + { + {1,0,0,0}, + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,0}, + }, + // c + { + {0,0,0,0}, + {1,1,1,0}, + {1,0,0,0}, + {1,1,1,0}, + }, + // d + { + {0,0,1,0}, + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,0}, + }, + // e + { + {1,1,1,0}, + {1,1,1,0}, + {1,0,0,0}, + {1,1,1,0}, + }, + // f + { + {1,1,1,0}, + {1,0,0,0}, + {1,1,0,0}, + {1,0,0,0}, + }, + // g + { + {1,1,1,1}, + {1,0,0,0}, + {1,0,1,1}, + {1,1,1,1}, + }, + // h + { + {1,0,0,0}, + {1,0,0,0}, + {1,1,1,0}, + {1,0,1,0}, + }, + // i + { + {0,1,0,0}, + {0,0,0,0}, + {0,1,0,0}, + {0,1,0,0}, + }, + // j + { + {0,0,1,0}, + {0,0,1,0}, + {1,0,1,0}, + {1,1,1,0}, + }, + // k + { + {1,0,0,0}, + {1,0,1,0}, + {1,1,0,0}, + {1,0,1,0}, + }, + // l + { + {0,1,0,0}, + {0,1,0,0}, + {0,1,0,0}, + {0,1,1,0}, + }, + // M + { + {1,0,0,1}, + {1,1,1,1}, + {1,0,0,1}, + {1,0,0,1}, + }, + // n + { + {0,0,0,0}, + {1,0,1,1}, + {0,1,0,1}, + {0,1,0,1}, + }, + // o + { + {0,0,0,0}, + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,0}, + }, + // p + { + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,0}, + {1,0,0,0}, + }, + // q + { + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,0}, + {0,0,1,0}, + }, + // r + { + {1,1,1,0}, + {1,0,1,0}, + {1,1,1,0}, + {1,0,0,1}, + }, + // s + { + {1,1,1,0}, + {0,1,0,0}, + {0,0,1,0}, + {1,1,1,0}, + }, + // T + { + {1,1,1,0}, + {0,1,0,0}, + {0,1,0,0}, + {0,1,0,0}, + }, + // u + { + {0,0,0,0}, + {1,0,1,0}, + {1,0,1,0}, + {1,1,1,0}, + }, + // v + { + {0,0,0,0}, + {1,0,1,0}, + {1,0,1,0}, + {0,1,0,0}, + }, + // Ww + { + {1,0,0,1}, + {1,0,0,1}, + {1,1,1,1}, + {1,0,0,1}, + }, + // x + { + {0,0,0,0}, + {1,0,1,0}, + {1,1,1,0}, + {1,0,1,0}, + }, + // y + { + {0,0,0,0}, + {1,0,1,0}, + {0,1,0,0}, + {0,1,0,0}, + }, + // z + { + {1,1,1,1}, + {0,0,1,0}, + {0,1,0,0}, + {1,1,1,1}, + } + +}; + +#define FRAMEBUFFER_POINTERS 1 /* Either 1 (Enabled) or 0 (disabled) */ +#if FRAMEBUFFER_POINTERS +struct Frame frames[2]; + +struct FrameBuffer { + unsigned char intensity = 0; + Frame *front = &frames[0]; + Frame *back = &frames[1]; +} FrameBuffer; +#else +struct FrameBuffer { + unsigned char visible = 0; + unsigned char intensity = 0; + Frame frames[2]; +} FrameBuffer; +#endif + +extern char position2pin[MAX_X][MAX_Y]; +extern char layer[MAX_Z]; + +void FrameBufferSwitch(void) { +#if FRAMEBUFFER_POINTERS + Frame * t = FrameBuffer.back; + FrameBuffer.back = FrameBuffer.front; + FrameBuffer.front = t; +#else + FrameBuffer.visible = (FrameBuffer.visible + 1) & 0x1; +#endif +} + +Frame *FrameBufferGetFront(void) { +#if FRAMEBUFFER_POINTERS + return FrameBuffer.front; +#else + return &FrameBuffer.frames[FrameBuffer.visible]; +#endif +} + +Frame *FrameBufferGetBack(void) { +#if FRAMEBUFFER_POINTERS + return FrameBuffer.back; +#else + return &FrameBuffer.frames[(FrameBuffer.visible + 1) & 0x1]; +#endif +} + +void FrameBufferWrite(char x, char y, char z, unsigned char val) { + FrameBufferGetBack()->data[x][y][z] = val; +} + +static void letter(char l, char brightness) { + memset(FrameBufferGetBack(), 0, FRAME_SIZE()); + for (char x = 0; x < MAX_X; x++) { + for (char y = 0; y < MAX_Y; y++) { + FrameBufferGetBack()->data[3][y][3-x] = + font[l - 'a'][x][y] * brightness; + } + } + FrameBufferSwitch(); + delay(200); +} + +void printAllSymbols() { + for(char c = 0; c < sizeof(font)/sizeof(font[0]); c++) { + letter(c+'a', 127); + delay(500); + } +} + +void FrameBufferWriteStr(char * str, const short delayPerLetter, + const unsigned char brightness) { + unsigned char *c = str; + while(*c != 0) { + if (*c == ' ') { + memset(FrameBufferGetBack(), 0, FRAME_SIZE()); + FrameBufferSwitch(); + } else { + letter(*c, brightness); + } + + delay(delayPerLetter); + + // Make sure there is a white space between font + memset(FrameBufferGetBack(), 0, FRAME_SIZE()); + FrameBufferSwitch(); + delay(delayPerLetter/4); + + c++; + } +} + +void FrameBufferRefresh(void) { + Frame *f = FrameBufferGetFront(); +#if BRIGHTNESS_INCREMENT + FrameBuffer.intensity = + (FrameBuffer.intensity + BRIGHTNESS_INCREMENT) % BRIGHTNESS_MAX; +#else + FrameBuffer.intensity = 128; +#endif + +#if DEBUG_FB_REFRESH + static int timeStartRefresh = micros(); + static int timeLastRefresh = 0; +#endif + + for (char z = 0; z < MAX_Z; z++) { + // 1. Set up the layer leds to be turned on / off + for (char x = 0; x < MAX_X; x++) { + for (char y = 0; y < MAX_Y; y++) { + if (f->data[x][y][z] > FrameBuffer.intensity) { + digitalWrite(position2pin[x][y], HIGH); + } else { + digitalWrite(position2pin[x][y], LOW); + } + } + } + + // 2. Turn the power on on the layer + digitalWrite(layer[z], LOW); + + // Let it display +#if BRIGHTNESS_LEVELS + delayMicroseconds(FRAME_PERIOD / (MAX_Z * BRIGHTNESS_LEVELS)); +#else + delayMicroseconds(FRAME_PERIOD / MAX_Z); +#endif + + // 3. Turn the power off on the layer + digitalWrite(layer[z], HIGH); + } + +#if DEBUG_FB_REFRESH + Serial.print("Time Since last refresh: "); + Serial.println((timeStartRefresh - timeLastRefresh), DEC); + + timeLastRefresh = micros(); + + Serial.print("Period Refresh Time: "); + Serial.println((timeLastRefresh - timeStartRefresh), DEC); +#endif +} + +void FrameBufferInit(void) { + // Setting rows to ouput + for (char x = 0; x < MAX_X; x++) { + for (char y = 0; y < MAX_Y; y++) { + pinMode(position2pin[x][y], OUTPUT); + digitalWrite(position2pin[x][y], LOW); + } + } + + // Setting layers to output + for (char z = 0; z < MAX_Z; z++) { + pinMode(layer[z], OUTPUT); + digitalWrite(layer[z], HIGH); + } + + // Initialize FrameBuffers + memset(FrameBufferGetFront(), 0, FRAME_SIZE()); + memset(FrameBufferGetBack(), 0, FRAME_SIZE()); + +#if BRIGHTNESS_LEVELS + MsTimer2::set(FRAME_PERIOD / (1000 * BRIGHTNESS_LEVELS), + FrameBufferRefresh); +#else + MsTimer2::set(FRAME_PERIOD / (1000), FrameBufferRefresh); +#endif + MsTimer2::start(); +} diff --git a/FrameBuffer.h b/FrameBuffer.h new file mode 100644 index 0000000..39cd821 --- /dev/null +++ b/FrameBuffer.h @@ -0,0 +1,115 @@ +#ifndef FRAMEBUFFER_H +#define FRAMEBUFFER_H +/* + * Copyright (c) 2018, Lionel Adrien Sambuc + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Either 1 (Enabled) or 0 (disabled) */ +#define DEBUG 0 +#if DEBUG +#define DEBUG_FB_REFRESH 1 +#endif + +/* All the code assumes dimensions are below 127, as signed chars are used to + * store positions and indices. */ +#define MAX_X 4 +#define MAX_Y 4 +#define MAX_Z 4 + +#define BRIGHTNESS_LEVELS 16 +#define BRIGHTNESS_MAX 256 + +struct Frame { + unsigned char data[MAX_X][MAX_Y][MAX_Z]; +}; + +extern struct FrameBuffer FrameBuffer; + +#define FRAME_SIZE() sizeof(struct Frame) + +#if BRIGHTNESS_LEVELS +#define BRIGHTNESS_INCREMENT (BRIGHTNESS_MAX / BRIGHTNESS_LEVELS) +#define FRAME_PERIOD (40000 / BRIGHTNESS_LEVELS) /* [us] */ +#else +#define FRAME_PERIOD (40000) /* [us] */ +#endif + +/** + * Switch the back and front buffers. + * + */ +void FrameBufferSwitch(void); + +/** + * Returns the current front (visible) frame buffer + */ +Frame *FrameBufferGetFront(void); + + +/** + * Returns the current back (invisible) frame buffer + */ +Frame *FrameBufferGetBack(void); + +/** + * Write the brightness ``val'' to the led at position (x,y,z), in the back + * buffer. + * + * In order to make the value visible, a call to FrameBufferSwitch is needed, + * once the drawing of the frame is complete. + */ +void FrameBufferWrite(char x, char y, char z, unsigned char val); + +/** + * Print the string, a letter at a time, showing each for delayPerLetter time, + * with the associated brightness. + * + * This has minimal checks, only lowercase font, space and zero to terminate + * the string. + */ +void FrameBufferWriteStr(char * str, const short delayPerLetter, + const unsigned char brightness); + +/** + * Print all symbols available, one after the other. + */ +void printAllSymbols(void); + +/** + * Draw the front frame on the ``screen''. + */ +void FrameBufferRefresh(void); + +/** + * Initialize the framebuffer, and start the timer to refresh the ``screen''. + */ +void FrameBufferInit(void); + +#endif /* FRAMEBUFFER_H */ diff --git a/LEDCube.jpg b/LEDCube.jpg new file mode 100644 index 0000000..0d39cba Binary files /dev/null and b/LEDCube.jpg differ diff --git a/LEDCubeBottomWired.jpg b/LEDCubeBottomWired.jpg new file mode 100644 index 0000000..9a808f9 Binary files /dev/null and b/LEDCubeBottomWired.jpg differ diff --git a/LEDCubeRessitors.jpg b/LEDCubeRessitors.jpg new file mode 100644 index 0000000..3f9226d Binary files /dev/null and b/LEDCubeRessitors.jpg differ diff --git a/LEDCubeWireTooBig.jpg b/LEDCubeWireTooBig.jpg new file mode 100644 index 0000000..df7813b Binary files /dev/null and b/LEDCubeWireTooBig.jpg differ diff --git a/LEDCubeWired.jpg b/LEDCubeWired.jpg new file mode 100644 index 0000000..58a7c06 Binary files /dev/null and b/LEDCubeWired.jpg differ diff --git a/LICENSE b/LICENSE index 06effcf..25b6c60 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,19 @@ -BSD 3-Clause License - -Copyright (c) 2018, Lionel Sambuc +Copyright (c) 2018, Lionel Adrien Sambuc All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/LedCube.ino b/LedCube.ino new file mode 100644 index 0000000..9520da6 --- /dev/null +++ b/LedCube.ino @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2018, Lionel Adrien Sambuc + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This program was created from a mix of several sources for the inspiration + * on how to implement the system. I especially followed: + * http://www.instructables.com/id/4x4x4-LED-Cube-Arduino-Uno/ for the + * construction of the hardware. + * + * The main idea is to keep two memory frame (3d) buffer. In order to refresh + * those we use a handler triggered through a timer, set for a period of + * ``FRAME_PERIOD''. Every period the whole cube needs to be redrawn, but as + * we have multiplexing, this means that each layer has only a fourth of the + * frame period to be turned on for the maximum brightness. In order to + * provide multiple brightness levels, a PWM-like signal is manually + * generated, per led, per layer, by turning it on for a percentage of the + * layer time only. + */ + +/* Either 1 (Enabled) or 0 (disabled) */ +#define DEBUG 0 +#if DEBUG +#define DEBUG_SETUP 1 +#define DEBUG_LOOP 1 +#endif + +#include "FrameBuffer.h" + + +/******************************* ANIMATIONS ********************************/ + +/* Taken from PWMallPins.pde by Paul Badger, 2007; + * formatted by Seth Wolf, 2015 */ +// Preset 256 values of a binary conversions of a sine wave +unsigned char sinewave[] = { + 0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae, + 0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8, + 0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5, + 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7, + 0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc, + 0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3, + 0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83, + 0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51, + 0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27, + 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a, + 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, + 0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23, + 0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c, + 0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c +}; + +/** + * Increase by steps the luminosity, then dim by steps the whole cube. + * + * Mainly useful as a test of the led cube. + */ +void levels(void) { + for(int i = 0; i < BRIGHTNESS_MAX; i++) { + memset(FrameBufferGetBack(), i, FRAME_SIZE()); + FrameBufferSwitch(); + delay(100); + } + + for(int i = BRIGHTNESS_MAX; i >= 0; i--) { + memset(FrameBufferGetBack(), i, FRAME_SIZE()); + FrameBufferSwitch(); + delay(100); + } +} + +/** + * Increase by steps the luminosity, then dim by steps the whole cube. + * + * Mainly useful as a test of the led cube. + */ +void testfreq(void) { + memset(FrameBufferGetBack(), 255, FRAME_SIZE()); + FrameBufferSwitch(); + delay(200); + + memset(FrameBufferGetBack(), 1, FRAME_SIZE()); + FrameBufferSwitch(); + delay(200); +} + +/** + * Blinks the whole cube on and off with a period `period`. + */ +void blinkWholeCube(int period /* [ms] */) { + memset(FrameBufferGetBack(), 255, FRAME_SIZE()); + FrameBufferSwitch(); + delay(period >> 1); + + memset(FrameBufferGetBack(), 0, FRAME_SIZE()); + FrameBufferSwitch(); + delay(period >> 1); +} + +/** + * Fade in and out following a sine curve with a period `period`. + */ +void sine(int period /* [ms] */) { + for(short int i = 0; i < BRIGHTNESS_MAX; i++) { + memset(FrameBufferGetBack()->data, sinewave[i], FRAME_SIZE()); + FrameBufferSwitch(); + delay(period / BRIGHTNESS_MAX); + } +} + +/** + * Fade in and out following a sine curve with a period `period`, but only a + * small 2x2x2 cube in the center. + */ +void sine2(int period /* [ms] */) { + for(short int i = 0; i < BRIGHTNESS_MAX; i++) { + memset(FrameBufferGetBack(), 0, FRAME_SIZE()); + + for (char x = 1; x < 3; x++) { + for (char y = 1; y < 3; y++) { + for (char z = 1; z < 3; z++) { + FrameBufferGetBack()->data[x][y][z] = sinewave[i]; + } + } + } + + FrameBufferSwitch(); + delay(period / BRIGHTNESS_MAX); + } +} + +/** + * Fade in and out following a sine curve with a period `period` the entire + * cube, but with the center 2x2x2 cube dephased by 180°. + */ +void sine3(int period /* [ms] */) { + for(int i = 0; i < 256; i++) { + memset(FrameBufferGetBack()->data, 0, FRAME_SIZE()); + for (char x = 1; x < 3; x++) { + for (char y = 1; y < 3; y++) { + for (char z = 1; z < 3; z++) { + FrameBufferGetBack()->data[x][y][z] = sinewave[i]; + } + } + } + + for (char x = 0; x < MAX_X; x++) { + for (char y = 0; y < MAX_Y; y++) { + for (char z = 0; z < MAX_Z; z++) { + if ( ((x == 0) || (x == 3)) + ||((y == 0) || (y == 3)) + ||((z == 0) || (z == 3))) { + FrameBufferGetBack()->data[x][y][z] = sinewave[(i+128)%256]; + } + } + } + } + + FrameBufferSwitch(); + delay(period / BRIGHTNESS_MAX); + } +} + +/** + * Random rain drpos fall to the bottom of the cube + */ +void randomRain() { + for (char a = MAX_Z; a > 0; a--) { + // animation of 4 steps, requiring computing 4 full frames + for (char x = 0; x < MAX_X; x++) { + for (char y = 0; y < MAX_Y; y++) { + FrameBufferGetBack()->data[x][y][3] = (random(0, 4) == 0) ? 1 : random(0, BRIGHTNESS_MAX); + FrameBufferGetBack()->data[x][y][2] = FrameBufferGetFront()->data[x][y][3]; + FrameBufferGetBack()->data[x][y][1] = FrameBufferGetFront()->data[x][y][2]; + FrameBufferGetBack()->data[x][y][0] = FrameBufferGetFront()->data[x][y][1]; + } + } + + FrameBufferSwitch(); + delay(500); + } +} + +/********************************** BODY ***********************************/ + +void setup() +{ +#if DEBUG_SETUP + static long timeStartSetup = micros(); +#endif + + // Seeding random for random pattern + randomSeed(analogRead(10)); + +#if DEBUG + Serial.begin(9600); + Serial.println("\nSetup DONE"); +#endif + + FrameBufferInit(); + +#if DEBUG_SETUP + Serial.print("Setup Time: "); + Serial.println((micros() - timeStartSetup), DEC); +#endif +} + +void loop() { + static char a = -1; + +#if DEBUG_LOOP + static long timeStartLoop = micros(); +#endif + + a = ((a+1) % 9); + for (int j = 0; j < 10; j++) { + switch(a) { + case 0: sine2(2000); break; + case 1: randomRain(); break; + case 2: sine3(2000); break; + case 3: blinkWholeCube(1000); break; + case 4: sine(2000); break; + case 5: printAllSymbols(); break; + case 6: FrameBufferWriteStr("hello world", 250, 255); + delay(1000); + break; + case 7: testfreq(); break; + case 8: levels(); break; + default: break; + } + } + + +#if DEBUG_LOOP + Serial.print("Loop Time: "); + Serial.println((micros() - timeStartLoop), DEC); +#endif +} + diff --git a/README.md b/README.md index a5e13b3..79b1e49 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,33 @@ # LedCube -Arduino Sketch for a LED cubes +Arduino Sketch for LED cubes + +The following sketch is currently split into a (3D) FrameBuffer implementation and the main "Sketch", which contains a couple of simple animations. + +The goal is for the FrameBuffer implementation to grow and allow in the future to support multi-color leds, as well as bigger LED Cubes. + +It is implemented in such away to allow for now about 16 levels of brightness + +## Hardware + +1. Arduino UNO +2. a home-made LED cube :) + +To be improved for the next model: + + * Use thinner wiring cables, this has unnecessarily complicated the soldering job + * Improve my soldering technic oO + +### Led Cube alone. +![Image](LEDCube.jpg) + +### Bottom, before wiring. +![Image](LEDCubeRessitors.jpg) + +### Bottom after wiring. +![Image](LEDCubeBottomWired.jpg) + +### My wiring cables where too big, AWG 18, which is about the same width as the hole pitch of my board. +![Image](LEDCubeWireTooBig.jpg) + +### Led Cube wired to the Arduino UNO +![Image](LEDCubeWired.jpg)