INTRODUCTION
The LED Cube features an 8x8x8 grid of LED's that are lit up in different sequences, shapes and forms through the power of programming. This is an electrical advancement from the very first development of multiplexing in the 1800's with mechanical parts.
MATERIALS
Qty. Description
4 2 row X 8 pin vertical header receptacle, 16 position
1 1 row X 8 pin vertical header receptacle, 8 position
4 2 row X 8 pin vertical pin header, 16 position, 0.1"
2 1 row X 8 pin vertical pin header, 8 position, 0.1"
3 1 row X 6 pin vertical pin header, 6 position, 0.1"
10 20-pin IC socket, DIP
10 16-pin IC socket, DIP
8 74HC574N, DIP-20 IC, Tri-state octal D-type flip-flop
1 74HC138N, DIP-16 IC, 3-to-8 line decoder/demultiplexer
20 Transistor, PN2222A, NPN, TO-92
10 Monolithic capacitor, 0.1µF, 50V
1 Radial capacitor, 1000µF, 16V
10 Radial capacitor, 10µF, 50V
10 Radial capacitor, 100µF, 25V
100 Resistor, 1/4W, 100 Ω
1 2.1mm DC Power Jack, PCB mount
1 5V@1A wall adapter power supply
530 3mm diffused blue LEDs
1 Arduino Uno R3 microcontroller
1 Circuit board mounting hardware
1 TOP PCB (1 of 2), Base for LED cube
1 Bottom PCB (2 of 2), Control board for LED cube
PROCEDURE - (See picture below)
Step 1 - Set up a Jig
This is probably the most difficult part of the kit to assemble and requires a lot of patience. It is
highly recommended that you create a jig to maintain even spacing between LEDs and it will
hold them steady while you solder. The kit comes with 3mm LEDs but some have shorter leads
than the "standard" 1 inch length, so the PCB and template are designed for 1/2" spacing
between LEDs and layers. The best way to make a jig is with a piece of plywood (1/2" thick).
You can use the actual PCB and a fine pencil to mark the holes through the PCB onto your jig
template, or use the paper copy of a 1/2" grid (found at the end of this document) and cut it out.
(Some printers may resize the print so verify with a ruler that the holes have 1/2" spacing.) Tape
it to the piece of plywood and drill a small pilot hole through each pad or grid intersection, or use
a center punch to form a grid of 64 holes. Use the smallest bit you have so you can be sure the
hole is centered. Larger bits can wander before they actually bite and may move slightly off grid.
(You do not have to drill the eight off-grid holes because you will not be placing LEDs there.)
Use a bit that is about the same size as the LEDs (3mm or approx. 1/8") and make the 64 pilot
holes a little larger. Test fit an LED. A snug fit is helpful to keep the LEDs from moving around
while you arrange the leads and solder them together.
Step 2 - Build the First Layer
The LED cube is configured with anode (positive) columns and cathode (negative) layers. You
can confirm the polarity of the LED with a coin cell battery. By hand or with the LED in the jig
and the anode on the right, bend the cathode 90°. The cathode is usually the shorter lead. Bend
each LED the same way so they are all uniform. With the head of the LEDs in the jig holes,
arrange the leads of the right-most column so they are all pointing to the top row of your jig. The
unbent leads should point straight up, while the bent leads all touch each other on the same
lead and form a row. Place the rest of the LEDs in the holes but arrange the bent leads so they
all point right to the first column you set up. Carefully solder the point where the leads touch.
You should have a neat looking grid of LEDs where only the top-right LED has its lead sticking
out to the side of the grid. DO NOT clip this lead yet since it will be used to test that LEDs as
you go. You'll need to add some strength to the layer, so use a stripped piece of solid core wire
or use some remnants of other clipped leads you might have laying around. Solder these
support pieces across the cathodes of the left most column and another across the middle for
good support (shown as a blue line). Make sure the brace doesn't touch any anodes!
Step 3 - Build more Layers
You will need to repeat the layer building process seven more times so you have eight complete
layers. It is a good idea to test light each LED before or after completing each layer. It will be
very difficult to replace an LED once it's buried deep in the middle of the cube. You can use a
coin cell battery with some leads taped to it to test the LEDs. Clip the battery's cathode to the
lead sticking out the side of the layer and touch the anode lead to each column to make sure the
LEDs work.
Step 4 - Stack the Layers
Leave the last layer in the jig since it will support the cube as you build it. Spacing and
symmetry is key to having a nice looking cube. By definition, a cube has equal length sides and
with the 1/2" spacing between leads, you'll need 1/2" spacing vertically. You can use a wooden
dowel, a mini toggle switch you might have laying around, a battery or make something out of
sturdy paper to give yourself a way to support the next layer 1/2" above the one below. The
easiest way to connect the anode columns is to put a slight kink about 1/8" from the end of the
lead so it bends in to touch the anode of the LED above it. Solder a few points at the corners
and middle and check to make sure you are satisfied with the arrangement before you solder
the remaining anodes.
Step 5 - Install the Headers
The PCBs are sandwiched on top of each other and is basically like a giant shield for the
Arduino. Both PCBs have an arrow on the silkscreen at the edge and both should point the
same direction when assembled. The header socket receptacles will be installed on the topside
(component side) of the control board (p/n: 2172015), but the straight header pins will be
installed on the underside (solder side) of the cube base PCB (p/n: 2172014). The easiest way
to install them is to join the pins and sockets together and place them in the control board in
spaces J1 - J5. Place the cube base PCB on top of the pins making sure both arrows are facing
the same direction. (Both PCBs should be silkscreen side up. You will use four double-row
sockets and pin headers (16-position; p/n: 70721 and 109568) and one single-row (8-position;
p/n: 70755 and 153702). Solder all the pins before attempting to pull the boards apart because
you risk pulling some of the pins out of their housing. The single row six and eight position pin
headers are to connect the control board to the Arduino like a shield. Place the pin headers (p/n:
153702 and 153700) in your Arduino Uno. The 8-pin header goes in Arduino D0-D7 header and
the 6-pin headers go in D8-D13, Analog In, and Power. Place the control board PCB on top of
your Arduino so the arrow is pointing toward the USB & Power connectors. Solder the pins on
the topside of the control board.
Step 6 - Install the other Components
Solder the remaining components starting with the lowest profile component. Install the 0.1µF
capacitors (p/n: 25523) into the positions labeled C1 - C9 and solder in place. Clip the excess
leads. Install the IC sockets in U1 - U9. U1 is a 16-pin socket and the rest are 20-pin. Be sure
the notch on the socket matches the notch on the PCB silkscreen. You can use tape or self-
closing pliers to hold the socket in place while you solder the leads. Solder one lead at each
corner and verify the socket is flush with the PCB before soldering the rest. Install the 100Ω
resistors (p/n: 690620) vertically which means you only have to bend one lead. They go in
locations marked R1-R88. Install the PN2222A transistors (p/n: 178511) in spaces Q1 - Q16.
Depending on the package of the transistor, you may have to squeeze some of the pins closer
together to fit in the PCB. They don't need to be flush with the PCB, but as long as they are near
or below the height of the header receptacles, they won't interfere with anything. Install the DC
power jack (p/n: 101178) at the corner of the PCB and solder in place. Note: C10 is a tall
capacitor and will exceed the height of the top PCB. If you want to fit everything in an enclosure
you may have to get creative with the electrolytic capacitor installation. One suggestion is to
install C11 and C12 on the underside of the PCB and bend the leads of C10 so it lays flat on the
topside of the PCB. Install the power filter capacitors that are near the power jack. They are
polarized so there is only one right way to install them. One side of the capacitor illustrates the
negative lead and the PCB should have a "+" sign on it for the positive pin. C10 is the 1000µF
cap (p/n: 330722), C11 is 100µF (p/n: 93761) and C12 is 10µF (p/n: 29891). Install the ICs in
the appropriate sockets and be mindful of the notch orientation.
Step 7 - Install LED Cube
Before you install the LED cube to the PCB, you will need to decide what kind of enclosure you
want to use. When you have an enclosure, you will need to make note of the orientation of the
PCBs and connectors before drilling any holes. Measure twice, cut/drill once. The cleanest look
will require that you drill 72 holes through the lid. 64 holes in the grid perfectly spaced for the
LED anode columns and another eight holes for the leads that will connect each cathode layer
to the control board. Be aware of the final dimensions when the PCBs and Arduino are
assembled together when deciding where and how to place the cube and boards within your
enclosure. It will require a lot of patience to guide each lead through a hole in the lid of your
enclosure and just as much to guide each lead through the hole on the PCB. Again, you can
use the paper grid at the end of this document as a stencil for your enclosure. You can try to
tweak each lead and look at them from the side to get them all in straight rows to make it easier
to fit the leads in the PCB or enclosure. Some leads will end up being longer or shorter than
others and will make it tricky to get them through the holes. The easiest way to get the leads
through the holes may be to start with one row at the edge and gradually roll the cube guiding
one row of leads at a time. Use some kind of poking device, like a small screwdriver, to coax
each lead into its appropriate hole.
Step 8 - Connect the Cathode Layers
With the arrow on the PCB silkscreen facing you, you will see the eight holes running down the
left side of the PCB between the first and second columns (going from left to right). The hole
closest to you is for the top layer of the cube (layer 8), and the hole near the back edge of the
PCB is for the bottom layer (layer 1). See the figure below for layer identification. Use some
straightened solid core hookup wire and strip all the insulation away. Make a connection from
one point of the cathode layer and connect the other end to the appropriate position on the
PCB. See the figures above and below for reference. Make sure the wire only contacts the layer
you intend, otherwise two layers or LEDs may light at the same time.
Step 9 - Upload Code
I have provided sample code to get the cube up and running. Since the code was borrowed
from an Instructable, you will have to determine how to write additional sequences. One way to
learn is to comment out all light sequences except for one and change some of the number
values to see how it changes the sequence. Plug in the Arduino to your computer by itself or
with the LED cube installed on top of it. If you get a sync error, try removing the cube before
uploading code to it. NOTE: The PCBs are tied to the Vin pin on the Arduino, so do not supply
more than 5V to the cube. Power the cube with a USB cable to the Arduino OR with the
included 5VDC adapter, NOT both at the same time. The DC jack on the side of the PCB is also
tied to the Vin pin, so plugging in the 5V adapter will power the cube and Arduino at the same
time.
CODE:
______________________________________________________________________________________________________________________________________
#include <avr/interrupt.h>
#include <string.h>
#define AXIS_X 1
#define AXIS_Y 2
#define AXIS_Z 3
volatile unsigned char cube[8][8];
volatile int current_layer = 0;
void setup()
{
int i;
for(i=0; i<14; i++)
pinMode(i, OUTPUT);
// pinMode(A0, OUTPUT) as specified in the arduino reference didn't work. So I accessed the
registers directly.
DDRC = 0xff;
PORTC = 0x00;
// Reset any PWM configuration that the arduino may have set up automagically!
TCCR2A = 0x00;
TCCR2B = 0x00;
TCCR2A |= (0x01 << WGM21); // CTC mode. clear counter on TCNT2 == OCR2A
OCR2A = 10; // Interrupt every 25600th cpu cycle (256*100)
TCNT2 = 0x00; // start counting at 0
TCCR2B |= (0x01 << CS22) | (0x01 << CS21); // Start the clock with a 256 prescaler
TIMSK2 |= (0x01 << OCIE2A);
}
ISR (TIMER2_COMPA_vect)
{
int i;
// all layer selects off
PORTC = 0x00;
PORTB &= 0x0f;
PORTB |= 0x08; // output enable off.
for (i=0; i<8; i++)
{
PORTD = cube[current_layer][i];
PORTB = (PORTB & 0xF8) | (0x07 & (i+1));
}
PORTB &= 0b00110111; // Output enable on.
if (current_layer < 6)
{
PORTC = (0x01 << current_layer);
}
else if (current_layer == 6)
{
digitalWrite(12, HIGH);
}
else
{
digitalWrite(13, HIGH);
}
current_layer++;
if (current_layer == 8)
current_layer = 0;
}
void loop() //ALL VISUAL EFFECTS ARE STARTED FROM HERE
{
int i,x,y,z;
while (true)
{
effect_planboing(AXIS_Z, 500);
effect_planboing(AXIS_Y, 500);
effect_planboing(AXIS_X, 500);
effect_blinky2();
effect_random_filler(100,1);
effect_random_filler(100,0);
effect_rain(200);
for(int count=0; count<2; count++){
effect_boxside_randsend_parallel (AXIS_X, 0, 300, 1);
effect_boxside_randsend_parallel (AXIS_X, 1, 300, 1);
}
for(int count2=0; count2<2; count2++){
effect_boxside_randsend_parallel (AXIS_Y, 0, 300, 1);
effect_boxside_randsend_parallel (AXIS_Y, 1, 300, 1);
}
for(int count3=0; count3<2; count3++){
effect_boxside_randsend_parallel (AXIS_Z, 0, 300, 1);
effect_boxside_randsend_parallel (AXIS_Z, 1, 300, 1);
}
}
}
//
========================================================================
==================
// Effect functions
//
========================================================================
==================
void draw_positions_axis (char axis, unsigned char positions[64], int invert)
{
int x, y, p;
fill(0x00);
for (x=0; x<8; x++)
{
for (y=0; y<8; y++)
{
if (invert)
{
p = (7-positions[(x*8)+y]);
}
else
{
p = positions[(x*8)+y];
}
if (axis == AXIS_Z)
setvoxel(x,y,p);
if (axis == AXIS_Y)
setvoxel(x,p,y);
if (axis == AXIS_X)
setvoxel(p,y,x);
}
}
}
void effect_boxside_randsend_parallel (char axis, int origin, int delay, int mode)
{
int i;
int done;
unsigned char cubepos[64];
unsigned char pos[64];
int notdone = 1;
int notdone2 = 1;
int sent = 0;
for (i=0;i<64;i++)
{
pos[i] = 0;
}
while (notdone)
{
if (mode == 1)
{
notdone2 = 1;
while (notdone2 && sent<64)
{
i = rand()%64;
if (pos[i] == 0)
{
sent++;
pos[i] += 1;
notdone2 = 0;
}
}
}
else if (mode == 2)
{
if (sent<64)
{
pos[sent] += 1;
sent++;
}
}
done = 0;
for (i=0;i<64;i++)
{
if (pos[i] > 0 && pos[i] <7)
{
pos[i] += 1;
}
if (pos[i] == 7)
done++;
}
if (done == 64)
notdone = 0;
for (i=0;i<64;i++)
{
if (origin == 0)
{
cubepos[i] = pos[i];
}
else
{
cubepos[i] = (7-pos[i]);
}
}
delay_ms(delay);
draw_positions_axis(axis,cubepos,0);
}
}
void effect_rain (int iterations)
{
int i, ii;
int rnd_x;
int rnd_y;
int rnd_num;
for (ii=0;ii<iterations;ii++)
{
rnd_num = rand()%4;
for (i=0; i < rnd_num;i++)
{
rnd_x = rand()%8;
rnd_y = rand()%8;
setvoxel(rnd_x,rnd_y,7);
}
delay_ms(1000);
shift(AXIS_Z,-1);
}
}
// Set or clear exactly 512 voxels in a random order.
void effect_random_filler (int delay, int state)
{
int x,y,z;
int loop = 0;
if (state == 1)
{
fill(0x00);
}
else
{
fill(0xff);
}
while (loop<511)
{
x = rand()%8;
y = rand()%8;
z = rand()%8;
if ((state == 0 && getvoxel(x,y,z) == 0x01) || (state == 1 && getvoxel(x,y,z) == 0x00))
{
altervoxel(x,y,z,state);
delay_ms(delay);
loop++;
}
}
}
void effect_blinky2()
{
int i,r;
fill(0x00);
for (r=0;r<2;r++)
{
i = 750;
while (i>0)
{
fill(0x00);
delay_ms(i);
fill(0xff);
delay_ms(100);
i = i - (15+(1000/(i/10)));
}
delay_ms(1000);
i = 750;
while (i>0)
{
fill(0x00);
delay_ms(751-i);
fill(0xff);
delay_ms(100);
i = i - (15+(1000/(i/10)));
}
}
}
// Draw a plane on one axis and send it back and forth once.
void effect_planboing (int plane, int speed)
{
int i;
for (i=0;i<8;i++)
{
fill(0x00);
setplane(plane, i);
delay_ms(speed);
}
for (i=7;i>=0;i--)
{
fill(0x00);
setplane(plane,i);
delay_ms(speed);
}
}
//
========================================================================
==================
// Draw functions
//
========================================================================
==================
// Set a single voxel to ON
void setvoxel(int x, int y, int z)
{
if (inrange(x,y,z))
cube[z][y] |= (1 << x);
}
// Set a single voxel to ON
void clrvoxel(int x, int y, int z)
{
if (inrange(x,y,z))
cube[z][y] &= ~(1 << x);
}
// This function validates that we are drawing inside the cube.
unsigned char inrange(int x, int y, int z)
{
if (x >= 0 && x < 8 && y >= 0 && y < 8 && z >= 0 && z < 8)
{
return 0x01;
}
else
{
// One of the coordinates was outside the cube.
return 0x00;
}
}
// Get the current status of a voxel
unsigned char getvoxel(int x, int y, int z)
{
if (inrange(x,y,z))
{
if (cube[z][y] & (1 << x))
{
return 0x01;
}
else
{
return 0x00;
}
}
else
{
return 0x00;
}
}
// In some effect we want to just take bool and write it to a voxel
// this function calls the apropriate voxel manipulation function.
void altervoxel(int x, int y, int z, int state)
{
if (state == 1)
{
setvoxel(x,y,z);
}
else
{
clrvoxel(x,y,z);
}
}
// Flip the state of a voxel.
// If the voxel is 1, its turned into a 0, and vice versa.
void flpvoxel(int x, int y, int z)
{
if (inrange(x, y, z))
cube[z][y] ^= (1 << x);
}
// Makes sure x1 is alwas smaller than x2
// This is usefull for functions that uses for loops,
// to avoid infinite loops
void argorder(int ix1, int ix2, int *ox1, int *ox2)
{
if (ix1>ix2)
{
int tmp;
tmp = ix1;
ix1= ix2;
ix2 = tmp;
}
*ox1 = ix1;
*ox2 = ix2;
}
// Sets all voxels along a X/Y plane at a given point
// on axis Z
void setplane_z (int z)
{
int i;
if (z>=0 && z<8)
{
for (i=0;i<8;i++)
cube[z][i] = 0xff;
}
}
// Clears voxels in the same manner as above
void clrplane_z (int z)
{
int i;
if (z>=0 && z<8)
{
for (i=0;i<8;i++)
cube[z][i] = 0x00;
}
}
void setplane_x (int x)
{
int z;
int y;
if (x>=0 && x<8)
{
for (z=0;z<8;z++)
{
for (y=0;y<8;y++)
{
cube[z][y] |= (1 << x);
}
}
}
}
void clrplane_x (int x)
{
int z;
int y;
if (x>=0 && x<8)
{
for (z=0;z<8;z++)
{
for (y=0;y<8;y++)
{
cube[z][y] &= ~(1 << x);
}
}
}
}
void setplane_y (int y)
{
int z;
if (y>=0 && y<8)
{
for (z=0;z<8;z++)
cube[z][y] = 0xff;
}
}
void clrplane_y (int y)
{
int z;
if (y>=0 && y<8)
{
for (z=0;z<8;z++)
cube[z][y] = 0x00;
}
}
void setplane (char axis, unsigned char i)
{
switch (axis)
{
case AXIS_X:
setplane_x(i);
break;
case AXIS_Y:
setplane_y(i);
break;
case AXIS_Z:
setplane_z(i);
break;
}
}
void clrplane (char axis, unsigned char i)
{
switch (axis)
{
case AXIS_X:
clrplane_x(i);
break;
case AXIS_Y:
clrplane_y(i);
break;
case AXIS_Z:
clrplane_z(i);
break;
}
}
// Fill a value into all 64 byts of the cube buffer
// Mostly used for clearing. fill(0x00)
// or setting all on. fill(0xff)
void fill (unsigned char pattern)
{
int z;
int y;
for (z=0;z<8;z++)
{
for (y=0;y<8;y++)
{
cube[z][y] = pattern;
}
}
}
// Draw a box with all walls drawn and all voxels inside set
void box_filled(int x1, int y1, int z1, int x2, int y2, int z2)
{
int iy;
int iz;
argorder(x1, x2, &x1, &x2);
argorder(y1, y2, &y1, &y2);
argorder(z1, z2, &z1, &z2);
for (iz=z1;iz<=z2;iz++)
{
for (iy=y1;iy<=y2;iy++)
{
cube[iz][iy] |= byteline(x1,x2);
}
}
}
// Darw a hollow box with side walls.
void box_walls(int x1, int y1, int z1, int x2, int y2, int z2)
{
int iy;
int iz;
argorder(x1, x2, &x1, &x2);
argorder(y1, y2, &y1, &y2);
argorder(z1, z2, &z1, &z2);
for (iz=z1;iz<=z2;iz++)
{
for (iy=y1;iy<=y2;iy++)
{
if (iy == y1 || iy == y2 || iz == z1 || iz == z2)
{
cube[iz][iy] = byteline(x1,x2);
}
else
{
cube[iz][iy] |= ((0x01 << x1) | (0x01 << x2));
}
}
}
}
// Draw a wireframe box. This only draws the corners and edges,
// no walls.
void box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2)
{
int iy;
int iz;
argorder(x1, x2, &x1, &x2);
argorder(y1, y2, &y1, &y2);
argorder(z1, z2, &z1, &z2);
// Lines along X axis
cube[z1][y1] = byteline(x1,x2);
cube[z1][y2] = byteline(x1,x2);
cube[z2][y1] = byteline(x1,x2);
cube[z2][y2] = byteline(x1,x2);
// Lines along Y axis
for (iy=y1;iy<=y2;iy++)
{
setvoxel(x1,iy,z1);
setvoxel(x1,iy,z2);
setvoxel(x2,iy,z1);
setvoxel(x2,iy,z2);
}
// Lines along Z axis
for (iz=z1;iz<=z2;iz++)
{
setvoxel(x1,y1,iz);
setvoxel(x1,y2,iz);
setvoxel(x2,y1,iz);
setvoxel(x2,y2,iz);
}
}
// Returns a byte with a row of 1's drawn in it.
// byteline(2,5) gives 0b00111100
char byteline (int start, int end)
{
return ((0xff<<start) & ~(0xff<<(end+1)));
}
// Flips a byte 180 degrees.
// MSB becomes LSB, LSB becomes MSB.
char flipbyte (char byte)
{
char flop = 0x00;
flop = (flop & 0b11111110) | (0b00000001 & (byte >> 7));
flop = (flop & 0b11111101) | (0b00000010 & (byte >> 5));
flop = (flop & 0b11111011) | (0b00000100 & (byte >> 3));
flop = (flop & 0b11110111) | (0b00001000 & (byte >> 1));
flop = (flop & 0b11101111) | (0b00010000 & (byte << 1));
flop = (flop & 0b11011111) | (0b00100000 & (byte << 3));
flop = (flop & 0b10111111) | (0b01000000 & (byte << 5));
flop = (flop & 0b01111111) | (0b10000000 & (byte << 7));
return flop;
}
// Draw a line between any coordinates in 3d space.
// Uses integer values for input, so dont expect smooth animations.
void line(int x1, int y1, int z1, int x2, int y2, int z2)
{
float xy; // how many voxels do we move on the y axis for each step on the x axis
float xz; // how many voxels do we move on the y axis for each step on the x axis
unsigned char x,y,z;
unsigned char lasty,lastz;
// We always want to draw the line from x=0 to x=7.
// If x1 is bigget than x2, we need to flip all the values.
if (x1>x2)
{
int tmp;
tmp = x2;
x2 = x1;
x1 = tmp;
tmp = y2;
y2 = y1;
y1 = tmp;
tmp = z2;
z2 = z1;
z1 = tmp;
}
if (y1>y2)
{
xy = (float)(y1-y2)/(float)(x2-x1);
lasty = y2;
}
else
{
xy = (float)(y2-y1)/(float)(x2-x1);
lasty = y1;
}
if (z1>z2)
{
xz = (float)(z1-z2)/(float)(x2-x1);
lastz = z2;
}
else
{
xz = (float)(z2-z1)/(float)(x2-x1);
lastz = z1;
}
// For each step of x, y increments by:
for (x = x1; x<=x2;x++)
{
y = (xy*(x-x1))+y1;
z = (xz*(x-x1))+z1;
setvoxel(x,y,z);
}
}
// Delay loop.
// This is not calibrated to milliseconds,
// but we had allready made to many effects using this
// calibration when we figured it might be a good idea
// to calibrate it.
void delay_ms(uint16_t x)
{
uint8_t y, z;
for ( ; x > 0 ; x--){
for ( y = 0 ; y < 90 ; y++){
for ( z = 0 ; z < 6 ; z++){
asm volatile ("nop");
}
}
}
}
// Shift the entire contents of the cube along an axis
// This is great for effects where you want to draw something
// on one side of the cube and have it flow towards the other
// side. Like rain flowing down the Z axiz.
void shift (char axis, int direction)
{
int i, x ,y;
int ii, iii;
int state;
for (i = 0; i < 8; i++)
{
if (direction == -1)
{
ii = i;
}
else
{
ii = (7-i);
}
for (x = 0; x < 8; x++)
{
for (y = 0; y < 8; y++)
{
if (direction == -1)
{
iii = ii+1;
}
else
{
iii = ii-1;
}
if (axis == AXIS_Z)
{
state = getvoxel(x,y,iii);
altervoxel(x,y,ii,state);
}
if (axis == AXIS_Y)
{
state = getvoxel(x,iii,y);
altervoxel(x,ii,y,state);
}
if (axis == AXIS_X)
{
state = getvoxel(iii,y,x);
altervoxel(ii,y,x,state);
}
}
}
}
if (direction == -1)
{
i = 7;
}
else
{
i = 0;
}
for (x = 0; x < 8; x++)
{
for (y = 0; y < 8; y++)
{
if (axis == AXIS_Z)
clrvoxel(x,y,i);
if (axis == AXIS_Y)
clrvoxel(x,i,y);
if (axis == AXIS_X)
clrvoxel(i,y,x);
}
}
}
___________________________________________________END OF CODE_____________________________________________________________________
UNDERSTANDING
The complexity of all 512 LED's is broken down using various transistors. It gets broken down even further using only the pins on a standard Arduino Uno compiler. The Arduino is controlled entirely by using C programming from the Arduino software. The multiplexing works by only having one LED on at a certain point in time. The programming makes the cube LED's blink so quickly back and forth that it only seems as though it is one simple animation.
SAFTEY REGULATIONS
One must exercise extreme caution while handling a soldering iron. It is advised to wear gloves and eye protection to refrain from 1st and 2nd degree burns.