Introduction: 8x8x8 LED Cube With Arduino Mega (+Sound +PS Controller +Game)

About: Ja, ich bin ein krimineller. Mein Verbrechen ist die Neugierde. Mein Verbrechen ist es Menschen zu verurteilen nach dem was sie sagen und denken, nicht nachdem wie sie aussehen. Mein Verbrechen ist es schlauer…

This is a instructable which is based on the Cube
by Chr, ( https://www.instructables.com/id/Led-Cube-8x8x8/ )
by SuperTech-IT, ( https://www.instructables.com/id/CHRs-8X8X8-LED-Cu... )
and by das-labor.org, ( http://www.das-labor.org/wiki/Borg3d_Bauanleitung... )
but i think its better and easier.

I started this Project without any skills from soldering toprogramming.

First of all I apologize first for my poor English. Because of this parts of this instructable are German.
Maybe I translate it later.


this happens if you lose
[Video abspielen]

wining looks like this
[Video abspielen]


and these are the effects:
[Video abspielen]

Step 1: The Component List

Deutsch:
Für den Cube:
512x LEDs
10x Versilberter Draht 0.8mm für Platinen und LED Gitter, 7m SILBER 0,8MM

Für die Platinen:
2x Lochraster Platine 160x100 H25PR160

Platine 1, Säule:

3x 36pol. Stiftleiste, gerade,
10x 10pol. Buchsenleiste, gerade, RM 2,54 BL 1X10G8
1x 74HC138 IC
8x 8 fach D-Flipflop 74HCT574
8x Sockel D-Flipflops GS 20P
100x Widerstände 47 Ohm
9x Kondensator 100nF KERKO 100N
1x 16 pin IC Sockel

Platine 2, Ebenen:

8x Mosfet Transistor BUZ11
2x 36pol. Stiftleiste, gerade,
2x 10pol. Buchsenleiste, gerade, RM 2,54 BL 1X10G8

Für Musik:
Ähnlich wie hier: http://arduino.cc/en/Tutorial/tone
1x Arduino Uno
1x 100 Ohm Widerstände
1x Lautsprecher 8 Ohm
2x Widerstände zwischen 1,5 K und 47 K
1x Schalter 2 oder 3 Positionen
1x oder 2x 10K ohm Widerstände

Für den Controller:
1x Playstation controller

Für Gehäuse:
1x kleine Tube Plexiglas Kleber transparent
1x Plexiglas ca. 405x405mm (for the top)
4x Plexiglas ca. 400x400mm
Genug Holz für den Unterbau und die Schablone

Und:
1x Steckerschaltnetzteil SNT 2500 (5V)
1x Arduino Mega 2560 R3
Und natürlich eine Menge Lot Draht und Kleinzeug.



English:
for the cube:
512x LEDs
10x Silver plated wire 0.8mm for sinkers and LED grid

for the sinkers:
2x Breadboard 160x100 H25PR160

for sinker 1, pillar:
3x 36pol. Male connector, straight,
10x 10pol. Female connector, straight, RM 2,54 BL 1X10G8
1x 74HC138 IC
8x 8xD-Flipflop 74HCT574
8x socket D-Flipflops GS 20P
100x resistors 47 Ohm
9x capacitor 100nF KERKO 100N
1x 16 pin IC socket

for sinker 2, layers:
8x Mosfet Transistor BUZ11
2x 36pol Male connector, straight,
2x 10pol. Female connector, straight, RM 2,54 BL 1X10G8

for the sound:
similar to this: http://arduino.cc/en/Tutorial/tone
1x Arduino Uno
1x 100 Ohm resistor
1x Speaker 8 Ohm
2x resistor between 1,5 K and 47 K
1x switch 2 or 3-positions
1x or 2x 10K ohm resistor

for the controller:
1x Playstation controller

for the case:
1x small tube of adhesive acrylic glass transparent:
1x acrylic glass ca. 405x405mm (for the top)
4x acrylic glass ca. 400x400mm
Enough wood for the base and the template

and:
1x SNT 2500 (5. Female connector, straight power supply)
1x Arduino Mega 2560 R3
and a lot of wire, solder and other little things you find somwhere

Step 2: Build the Cube

Deutsch:
Den Cube baute ich nach der Anleitung von das Labor denn dies ist etwas einfacher als nach der Methode die hier in den Anleitungen kursieren.
http://www.das-labor.org/wiki/Borg3d_W%C3%BCrfel_...

1. Schablone für je 8x8 LEDs bauen
- Größe für den Cube überlegen
Ich entschied mich für 4cm Abstend zwichen den LEDs also eine gesamt größe von ca 28cm
Die Holzplatte zur Herstellung sollte dem entsprechend gößer sein.
- 8 Nuten senkrecht fräsen mit einer Tiefe von 7mm und einer Breite von ca 3mm
- 8 Nuten senkrecht fräsen mit einer Tiefe von 1- bis 2mm und einer Breite von ca 3mm
- Für die LEDs muss noch 2mm über jeder Kreuzung eine Vertiefung für die LED gemacht werden

English:
I build the cube itself after this:
http://www.das-labor.org/wiki/Borg3d_W%C3%BCrfel_B...
It's much cuter than intractables I’ve seen on this site.

1. Build a Template for 8x8 LEDs
- Consider the size for the cube
- I chose 4cm as the distance between the LEDs yielding to a total size of approx 28cm

The wooden plate for making should be bigger according to the following.
- 8 grooves milled vertically to a depth of 7 mm and a width of about 3mm
- 8 grooves milled vertically to a depth of 1 - to 2 mm and a width of about 3mm
- Still a 2mm recess for the LED needs to be done about every intersection for the LEDs

Step 3: Build the Sinkers

German:
Die Platine baute ich ebenfalls nach:
https://www.das-labor.org/wiki/Borg3d_Platinen_Bau...

Doch ich entschied mich später so um zubauen wie es bei chr (Step 9) beschrieben wurde.
Von der Platine mit mc nutze ich nur noch die Transistoren, denn als mc verwendete ich einen arduino uno bzw. mittlerweile einen arduino Mega.
Den Cube selbst kann ich wie auch schon bei chr beschieben mit allen Effeken auf einem arduino uno laufen lassen, allerdings wollte ich noch einen Playstation controller nachrüsten, deshalb änderte ich das Programm auf die Hardware für den Arduino Mega.



Englisch:

The board I built also by:
https://www.das-labor.org/wiki/Borg3d_Platinen_Bau...

But later I decided, however, to assemble the board with mc as described by chr in (Step 9).
From the board, I only use the transistor circuit, because as mc I used an arduino uno and now a arduino mega.
The Cube itself I can already run like chr with all effecs on arduino uno, but I still wanted a Playstation controller upgrade, so I changed the program to the hardware for the Arduino Mega.



On the wiring diagram i am still working. This will take some time and follows later. I changed too much too many times. It´s a mix from chr and das-labor. But easyer.




Step 4: PIN Wiring

Please check the pictures, how to connect the mega to the sinkers.

Step 5: Build the Case, Power Supply Etc...

see the pictures
the cube has a acrylic glass hood made with 5 pieces of acrylic glass and a bit glue

1x ca 405x405mm (for the top)
4x ca. 400x400mm
you will figure it out
but test it before gluing and read first how the glue works (my glue cures only by blacklight)

i made the rest out of boards laying around

Step 6: Programm (Arduino Mega Setup)

Vorerst hier nur die Änderung im setup für den Arduino Mega:
ursprungscode von chr
https://www.instructables.com/id/Led-Cube-8x8x8/ (step 70)

Here you find the changes I made to his code. (from Arduino UNO (like chr) to Arduino Mega)

void setup()
{ int i;
//Pins 22 bis 50 als Ausgänge festsetzen
for(i=22; i<50; 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;

// zähler, Uhr initialisieren
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); //Timer Interrupt Mask Register
}

//interrupt
ISR (TIMER2_COMPA_vect)
{
int i;
// PORTA = 8x Databus (8-Bit-Latches) PIN 22-30 (bei uno Pins 0-7 PortD)
// PORTL = 3x Adressbus + OE
// PORTC = 8x Ebenen (Layer)
// Char cube [ 8 ] enthält 64 Bits von Daten für die Halteanordnung
// all layer selects off
PORTC = 0x00;
PORTL &= 0x0f; // PortL 3xAdressbus
PORTL |= 0x08; // output enable off.

// Zählen bis 8
for (i=0; i<8; i++)
{
PORTA = cube[current_layer][i]; //(PortA = 8xDatabus) PIN 22-30 (bei uno Pins 0-7 PortD)
PORTL = (PORTL & 0xF8) | (0x07 & (i+1)); // (i+1) => 74HC138 erhält die folgende Sequenz: 1 2 3 4 5 6 7 0 (muss immer eins voraus sein)
}
PORTL &= 0b00110111; // Output enable on.

//ebenen
if (current_layer < 8)
{
PORTC = (0x01 << current_layer);
}
current_layer++;
if (current_layer == 8)
current_layer = 0;
}

Step 7: Programm PSX

#include psx

diese library kann man unter:
load it here:
http://playground.arduino.cc/Main/PSXLibrary


you have to change parts in this lib for the new Arduino IDE (I used 1.0.5) if you want to use a old Playstation controller!
you might also can use a ps2 or ps3 controller but then you need a other library.

Vor dem importieren muss allerdings eine Datei manuell angepasst werden da die PSXLibrary nicht für die Arduino IDE 1.0.5. angepasst wurde.

Because PSXLibrary ist not combatible with Arduino EDE 1.0.5 a file has to be adjusted before import like this:


Dazu die Herruntergeladene Datei öffnen - open the downloaded file

den ordner PSX öffnen - open the PSX

Die Datei PSX.h öffnen - open the PSX_h file

dort den Befehl #include "WConstants.h" - change #include "WConstants.h"

ändern zu #include "Arduino.h" - to #include "Arduino.h"

speichern - safe

nun sollte die Ardunio IDE keine Probleme mehr beim kompilieren machen.
after this it should compile.

Pin verdrahtung:

#define dataPin 50 //PS-Pin 1 brown

#define cmndPin 51 //PS-Pin 2 orange

#define attPin 52 //PS-Pin 6 yellow

#define clockPin 53 //PS-Pin 7 blue

//PS-Pin 4 GND black

//PS-Pin 5 VCC 3V red

Step 8: Programm (Arduino Mega Effekte)

Here is a sample of the code (effects)
you find the complete (and current) code in last step


void loop()
{
int i,x,y,z;



while (gamechoice == 0)
{

effect_count_up(); //AZ
effect_count_thru(); //AZ

effect_text(1000,0,13);
effect_text_up(5000,0,6);

effect_rain(50);

effect_random_filler(75,1);
effect_random_filler(75,0);

effect_planboing(AXIS_Z, 400);
effect_planboing(AXIS_Y, 400);
effect_planboing(AXIS_X, 400);

effect_boxside_randsend_parallel (AXIS_X, 0, 150, 1);
effect_boxside_randsend_parallel (AXIS_X, 1, 150, 1);
effect_boxside_randsend_parallel (AXIS_Y, 0, 150, 1);
effect_boxside_randsend_parallel (AXIS_Y, 1, 150, 1);
effect_boxside_randsend_parallel (AXIS_Z, 0, 150, 1);
effect_boxside_randsend_parallel (AXIS_Z, 1, 150, 1);
effect_fireworks(10,30,500);
effect_intro();
sinelines(4000,10);
linespin(1500,10);
mirror_ripples(600,400);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_X, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_X, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_Y, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Y, 550,5000,1);
side_ripples (300, 500);
effect_random_sparkle();
quad_ripples (600,300);

box_filled(2,2,2,5,5,5);
box_walls(2,2,2,5,5,5);
box_wireframe(2,2,2,5,5,5);

}
}

// ==========================================================================================
// 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);
}
}

}

// effect_count_up (AZ).
void effect_count_up ()
{
int i, ii, iii;
int x;
int y;
int z;

fill(0x00);
for (i=0; i<8; i++)
{
if (i <= 0)
{
x = 0;
y = 0;
z = 0;
}
for (ii=0; ii<8; ii++)
{

for (iii=0; iii<7; iii++)
{
setvoxel(x,y,z);
delay_ms(500);
z = z++;
}
setvoxel(x,y,z);
delay_ms(500);
y = y++;
z = 0;
}

setvoxel(x,y,z);
delay_ms(500);
x = x++;
y = 0;
}
}

// effect_count_thru (AZ).
void effect_count_thru ()
{
int i, ii, iii;
int x;
int y;
int z;

fill(0x00);
for (i=0; i<8; i++)
{
if (i <= 0)
{
x = 0;
y = 0;
z = 0;
}
for (ii=0; ii<8; ii++)
{

for (iii=0; iii<7; iii++)
{
setvoxel(x,y,z);
delay_ms(1000);
clrvoxel(x,y,z);
z = z++;
}
setvoxel(x,y,z);
delay_ms(1000);
clrvoxel(x,y,z);
y = y++;
z = 0;
}

setvoxel(x,y,z);
delay_ms(1000);
clrvoxel(x,y,z);
x = x++;
y = 0;
}
}


void effect_text_up (int delayt, int First, int Last){

const int charNum = 6;
char string[charNum] = {'S','U','P','E','R'};

fill(0x00);
for (int ltr = First; ltr < Last; ltr++){// For each letter in string array
for(int dist = 0; dist < 8; dist++) { //bring letter forward
fill(0x00);//blank cube
int rev = 0;
for (int rw = 7; rw >= 0; rw--) {//copy rows
// put this in for miswired backwards cube: cube[rev][dist] = bitswap(font_data[string[ltr]][rw]);
// cube[rev][dist] = font_data[string[ltr]][rw];
cube[dist][rev] = font[string[ltr]][rw];
// use above line for proper cubes
rev++;
}
delay_ms(delayt);
}
}
}


void effect_text(int delayt, int First, int Last){

const int charNum = 13;
char string[charNum] = {'P','r','e','s','s',' ','S','t','a','r','t','!',' '};

fill(0x00);
for (int ltr = First; ltr < Last; ltr++){// For each letter in string array
for(int dist = 0; dist < 8; dist++) { //bring letter forward
fill(0x00); //blank cube
int rev = 0;
for (int rw = 7; rw >= 0; rw--) {//copy rows
// put this in for normal cube:
cube[rev][dist] = bitswap(font[string[ltr]][rw]);
//cube[rev][dist] = font[string[ltr]][rw];
// cube[dist][rev] = font[string[ltr]][rw];
// use above line for backward ass cubes
rev++;
}
delay_ms(delayt);
}
}
}


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 {
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(1500);
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++;
}
}
}


// 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(5000);
}

for (i=7;i>=0;i--)
{
fill(0x00);
setplane(plane,i);
delay_ms(5000);
}
}

void effect_fireworks (int iterations, int n, int delay)
{
fill(0x00);

int i,f,e;

float origin_x = 3;
float origin_y = 3;
float origin_z = 3;

int rand_y, rand_x, rand_z;

float slowrate, gravity;

// Particles and their position, x,y,z and their movement, dx, dy, dz
float particles[n][6];

for (i=0; i {

origin_x = rand()%4;
origin_y = rand()%4;
origin_z = rand()%2;
origin_z +=5;
origin_x +=2;
origin_y +=2;

// shoot a particle up in the air
for (e=0;e {
setvoxel(origin_x,origin_y,e);
delay_ms(600+500*e);
fill(0x00);
}

// Fill particle array
for (f=0; f {
// Position
particles[f][0] = origin_x;
particles[f][1] = origin_y;
particles[f][2] = origin_z;

rand_x = rand()%200;
rand_y = rand()%200;
rand_z = rand()%200;

// Movement
particles[f][3] = 1-(float)rand_x/100; // dx
particles[f][4] = 1-(float)rand_y/100; // dy
particles[f][5] = 1-(float)rand_z/100; // dz
}

// explode
for (e=0; e<25; e++)
{
slowrate = 1+tan((e+0.1)/20)*10;

gravity = tan((e+0.1)/20)/2;

for (f=0; f {
particles[f][0] += particles[f][3]/slowrate;
particles[f][1] += particles[f][4]/slowrate;
particles[f][2] += particles[f][5]/slowrate;
particles[f][2] -= gravity;

setvoxel(particles[f][0],particles[f][1],particles[f][2]);


}

delay_ms(delay);
fill(0x00);
}

}

}

void effect_intro(){
int cnt,cnt_2,time;

//Bottom To Top

for(cnt=0;cnt<=7;cnt++){
box_wireframe(0, 0, 0, 7, 7, cnt);
delay_ms(2000);
}
for(cnt=0;cnt<7;cnt++){
clrplane_z(cnt);
delay_ms(2000);
}

//Shift Things Right
//1
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,6);
}
delay_ms(2000);
//2
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,5);
}
setvoxel(0,0,6);
setvoxel(7,0,6);
delay_ms(2000);
//3
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,4);
}
setvoxel(0,0,5);
setvoxel(7,0,5);
setvoxel(0,0,6);
setvoxel(7,0,6);
delay_ms(2000);

//4
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,3);
}
setvoxel(0,0,4);
setvoxel(7,0,4);
setvoxel(0,0,5);
setvoxel(7,0,5);
setvoxel(0,0,6);
setvoxel(7,0,6);
delay_ms(2000);

//5
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,2);
}
setvoxel(0,0,3);
setvoxel(7,0,3);
setvoxel(0,0,4);
setvoxel(7,0,4);
setvoxel(0,0,5);
setvoxel(7,0,5);
setvoxel(0,0,6);
setvoxel(7,0,6);
delay_ms(2000);

//6
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,1);
}
setvoxel(0,0,2);
setvoxel(7,0,2);
setvoxel(0,0,3);
setvoxel(7,0,3);
setvoxel(0,0,4);
setvoxel(7,0,4);
setvoxel(0,0,5);
setvoxel(7,0,5);
delay_ms(2000);


//7
shift(AXIS_Y,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,0,0);
}
setvoxel(0,0,1);
setvoxel(7,0,1);
setvoxel(0,0,2);
setvoxel(7,0,2);
setvoxel(0,0,3);
setvoxel(7,0,3);
setvoxel(0,0,4);
setvoxel(7,0,4);
setvoxel(0,0,5);
setvoxel(7,0,5);
delay_ms(2000);

//Right To Left
for(cnt=0;cnt<=7;cnt++){
box_wireframe(0, 0, 0, 7, cnt, 7);
delay_ms(2000);
}
for(cnt=0;cnt<7;cnt++){
clrplane_y(cnt);
delay_ms(2000);
}

//Shift to the bottom
for(cnt_2=6;cnt_2>=0;cnt_2--){
shift(AXIS_Z,-1);
for(cnt=0;cnt<=7;cnt++){
setvoxel(cnt,cnt_2,0);
}
for(cnt=6;cnt>cnt_2;cnt--){
setvoxel(0,cnt,0);
setvoxel(7,cnt,0);
}

delay_ms(2000);
}

//Make All Wall Box

for(cnt=0;cnt<=6;cnt++){
fill(0x00);
box_walls(0,0,0,7,7,cnt);
delay_ms(2000);
}

time = 2000;
for(cnt_2=0;cnt_2<5;cnt_2++){
time = time - 300;
//Make Box Smaller
for(cnt=0;cnt<=3;cnt++){
fill(0x00);
box_walls(cnt,cnt,cnt,7-cnt,7-cnt,7-cnt);
delay_ms(time);
}

//Make Box Bigger
for(cnt=0;cnt<=3;cnt++){
fill(0x00);
box_walls(3-cnt,3-cnt,3-cnt,4+cnt,4+cnt,4+cnt);
delay_ms(time);
}
}
for(cnt_2=0;cnt_2<5;cnt_2++){
time = time + 300;
//Make Box Smaller
for(cnt=0;cnt<=3;cnt++){
fill(0x00);
box_walls(cnt,cnt,cnt,7-cnt,7-cnt,7-cnt);
delay_ms(time);
}

//Make Box Bigger
for(cnt=0;cnt<=3;cnt++){
fill(0x00);
box_walls(3-cnt,3-cnt,3-cnt,4+cnt,4+cnt,4+cnt);
delay_ms(time);
}
}
delay_ms(2000);
}


void sinelines (int iterations, int delay)
{
int i,x;

float left, right, sine_base, x_dividor,ripple_height;

for (i=0; i {
for (x=0; x<8 ;x++)
{
x_dividor = 2 + sin((float)i/100)+1;
ripple_height = 3 + (sin((float)i/200)+1)*6;

sine_base = (float) i/40 + (float) x/x_dividor;

left = 4 + sin(sine_base)*ripple_height;
right = 4 + cos(sine_base)*ripple_height;
right = 7-left;

//printf("%i %i \n", (int) left, (int) right);

line_3d(0-3, x, (int) left, 7+3, x, (int) right);
//line_3d((int) right, 7, x);
}

// delay_ms(delay);
fill(0x00);
}
}

void linespin (int iterations, int delay)
{
float top_x, top_y, top_z, bot_x, bot_y, bot_z, sin_base;
float center_x, center_y;

center_x = 4;
center_y = 4;

int i, z;
for (i=0;i {

//printf("Sin base %f \n",sin_base);

for (z = 0; z < 8; z++)
{

sin_base = (float)i/50 + (float)z/(10+(7*sin((float)i/200)));

top_x = center_x + sin(sin_base)*5;
top_y = center_x + cos(sin_base)*5;
//top_z = center_x + cos(sin_base/100)*2.5;

bot_x = center_x + sin(sin_base+3.14)*10;
bot_y = center_x + cos(sin_base+3.14)*10;
//bot_z = 7-top_z;

bot_z = z;
top_z = z;

// setvoxel((int) top_x, (int) top_y, 7);
// setvoxel((int) bot_x, (int) bot_y, 0);

//printf("P1: %i %i %i P2: %i %i %i \n", (int) top_x, (int) top_y, 7, (int) bot_x, (int) bot_y, 0);

//line_3d((int) top_x, (int) top_y, (int) top_z, (int) bot_x, (int) bot_y, (int) bot_z);
line_3d((int) top_z, (int) top_x, (int) top_y, (int) bot_z, (int) bot_x, (int) bot_y);
}

// delay_ms(delay);
fill(0x00);
}

}

void mirror_ripples(int iterations, int delay)
{
// 16 values for square root of a^2+b^2. index a*4+b = 10*sqrt
// This gives the distance to 3.5,3.5 from the point
unsigned char sqrt_LUT[]={49,43,38,35,43,35,29,26,38,29,21,16,35,25,16,7};
//LUT_START // Macro from new tottymath. Commented and replaced with full code
unsigned char LUT[65];
init_LUT(LUT);
int i;
unsigned char x,y,height,distance;
for (i=0;i {
fill(0x00);
for (x=0;x<4;x++)
for(y=0;y<4;y++)
{
// x+y*4 gives no. from 0-15 for sqrt_LUT
distance=sqrt_LUT[x+y*4];// distance is 0-50 roughly
// height is sin of distance + iteration*4
//height=4+totty_sin(LUT,distance+i)/52;
height=(196+totty_sin(LUT,distance+i))/49;
// Use 4-way mirroring to save on calculations
setvoxel(x,y,height);
setvoxel(7-x,y,height);
setvoxel(x,7-y,height);
setvoxel(7-x,7-y,height);
setvoxel(x,y,7-height);
setvoxel(7-x,y,7-height);
setvoxel(x,7-y,7-height);
setvoxel(7-x,7-y,7-height);

}
delay_ms(delay);
}
}

void effect_axis_updown_randsuspend (char axis, int delay, int sleep, int invert)
{
unsigned char positions[64];
unsigned char destinations[64];

int i,px;

// Set 64 random positions
for (i=0; i<64; i++)
{
positions[i] = 0; // Set all starting positions to 0
destinations[i] = rand()%8;
}

// Loop 8 times to allow destination 7 to reach all the way
for (i=0; i<8; i++)
{
// For every iteration, move all position one step closer to their destination
for (px=0; px<64; px++)
{
if (positions[px] {
positions[px]++;
}
}
// Draw the positions and take a nap
draw_positions_axis (axis, positions,invert);
delay_ms(delay);
}

// Set all destinations to 7 (opposite from the side they started out)
for (i=0; i<64; i++)
{
destinations[i] = 7;
}

// Suspend the positions in mid-air for a while
delay_ms(sleep);

// Then do the same thing one more time
for (i=0; i<8; i++)
{
for (px=0; px<64; px++)
{
if (positions[px] {
positions[px]++;
}
if (positions[px]>destinations[px])
{
positions[px]--;
}
}
draw_positions_axis (axis, positions,invert);
delay_ms(delay);
}
}

void side_ripples(int iterations, int delay)
{
// 16 values for square root of a^2+b^2. index a*4+b = 10*sqrt
// This gives the distance to 3.5,3.5 from the point
unsigned char sqrt_LUT[]={49,43,38,35,43,35,29,26,38,29,21,16,35,25,16,7};
//LUT_START // Macro from new tottymath. Commented and replaced with full code
unsigned char LUT[65];
init_LUT(LUT);
int i;
unsigned char x,y,height,distance;
for (i=0;i {
fill(0x00);
for (x=0;x<4;x++)
for(y=0;y<4;y++)
{
// x+y*4 gives no. from 0-15 for sqrt_LUT
distance=sqrt_LUT[x+y*4];// distance is 0-50 roughly
// height is sin of distance + iteration*4
//height=4+totty_sin(LUT,distance+i)/52;
height=(196+totty_sin(LUT,distance+i))/49;
// Use 4-way mirroring to save on calculations
setvoxel(x,height,y);
setvoxel(7-x,height,y);
setvoxel(x,height,7-y);
setvoxel(7-x,height,7-y);
setvoxel(x,7-height,y);
setvoxel(7-x,7-height,y);
setvoxel(x,7-height,7-y);
setvoxel(7-x,7-height,7-y);

}
delay_ms(delay);
}
}

// blink 1 random voxel, blink 2 random voxels..... blink 20 random voxels
// and back to 1 again.
void effect_random_sparkle (void)
{
int i;

for (i=1;i<20;i++)
{
effect_random_sparkle_flash(5,i,200);
}

for (i=20;i>=1;i--)
{
effect_random_sparkle_flash(5,i,200);
}

}

void quad_ripples(int iterations, int delay)
{
// 16 values for square root of a^2+b^2. index a*4+b = 10*sqrt
// This gives the distance to 3.5,3.5 from the point
unsigned char sqrt_LUT[]={49,43,38,35,43,35,29,26,38,29,21,16,35,25,16,7};
//LUT_START // Macro from new tottymath. Commented and replaced with full code
unsigned char LUT[65];
init_LUT(LUT);
int i;
unsigned char x,y,height,distance;
for (i=0;i {
fill(0x00);
for (x=0;x<4;x++)
for(y=0;y<4;y++)
{
// x+y*4 gives no. from 0-15 for sqrt_LUT
distance=sqrt_LUT[x+y*4];// distance is 0-50 roughly
// height is sin of distance + iteration*4
//height=4+totty_sin(LUT,distance+i)/52;
height=(196+totty_sin(LUT,distance+i))/49;
// Use 4-way mirroring to save on calculations
setvoxel(x,y,height);
setvoxel(7-x,y,height);
setvoxel(x,7-y,height);
setvoxel(7-x,7-y,height);
setvoxel(x,y,7-height);
setvoxel(7-x,y,7-height);
setvoxel(x,7-y,7-height);
setvoxel(7-x,7-y,7-height);
setvoxel(x,height,y);
setvoxel(7-x,height,y);
setvoxel(x,height,7-y);
setvoxel(7-x,height,7-y);
setvoxel(x,7-height,y);
setvoxel(7-x,7-height,y);
setvoxel(x,7-height,7-y);
setvoxel(7-x,7-height,7-y);


}
delay_ms(delay);
}
}

// ==========================================================================================
// Draw functions
// ==========================================================================================


// Set a single voxel to ON (or)
void setvoxel(int x, int y, int z)
{
if (inrange(x,y,z))
cube[z][y] |= (1 << x);
}


// Set a single voxel to ON (and)
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);
}

}

unsigned char bitswap (unsigned char x)//Reverses a byte (so letters aren't backwards);
{ byte result;

asm("mov __tmp_reg__, %[in] \n\t"
"lsl __tmp_reg__ \n\t" /* shift out high bit to carry */
"ror %[out] \n\t" /* rotate carry __tmp_reg__to low bit (eventually) */
"lsl __tmp_reg__ \n\t" /* 2 */
"ror %[out] \n\t"
"lsl __tmp_reg__ \n\t" /* 3 */
"ror %[out] \n\t"
"lsl __tmp_reg__ \n\t" /* 4 */
"ror %[out] \n\t"

"lsl __tmp_reg__ \n\t" /* 5 */
"ror %[out] \n\t"
"lsl __tmp_reg__ \n\t" /* 6 */
"ror %[out] \n\t"
"lsl __tmp_reg__ \n\t" /* 7 */
"ror %[out] \n\t"
"lsl __tmp_reg__ \n\t" /* 8 */
"ror %[out] \n\t"

: [out] "=r" (result) : [in] "r" (x));
return(result);
}

// 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< }

// 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");
}
}
}
}

void line_3d (int x1, int y1, int z1, int x2, int y2, int z2)
{
int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc,
err_1, err_2, dx2, dy2, dz2;
int pixel[3];
pixel[0] = x1;
pixel[1] = y1;
pixel[2] = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
x_inc = (dx < 0) ? -1 : 1;
l = abs(dx);
y_inc = (dy < 0) ? -1 : 1;
m = abs(dy);
z_inc = (dz < 0) ? -1 : 1;
n = abs(dz);
dx2 = l << 1;
dy2 = m << 1;
dz2 = n << 1;
if ((l >= m) && (l >= n)) {
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++) {
//PUT_PIXEL(pixel);
setvoxel(pixel[0],pixel[1],pixel[2]);
//printf("Setting %i %i %i \n", pixel[0],pixel[1],pixel[2]);
if (err_1 > 0) {
pixel[1] += y_inc;
err_1 -= dx2;
}
if (err_2 > 0) {
pixel[2] += z_inc;
err_2 -= dx2;
}
err_1 += dy2;
err_2 += dz2;
pixel[0] += x_inc;
}
} else if ((m >= l) && (m >= n)) {
err_1 = dx2 - m;
err_2 = dz2 - m;
for (i = 0; i < m; i++) {
//PUT_PIXEL(pixel);
setvoxel(pixel[0],pixel[1],pixel[2]);
//printf("Setting %i %i %i \n", pixel[0],pixel[1],pixel[2]);
if (err_1 > 0) {
pixel[0] += x_inc;
err_1 -= dy2;
}
if (err_2 > 0) {
pixel[2] += z_inc;
err_2 -= dy2;
}
err_1 += dx2;
err_2 += dz2;
pixel[1] += y_inc;
}
} else {
err_1 = dy2 - n;
err_2 = dx2 - n;
for (i = 0; i < n; i++) {
setvoxel(pixel[0],pixel[1],pixel[2]);
//printf("Setting %i %i %i \n", pixel[0],pixel[1],pixel[2]);
//PUT_PIXEL(pixel);
if (err_1 > 0) {
pixel[1] += y_inc;
err_1 -= dz2;
}
if (err_2 > 0) {
pixel[0] += x_inc;
err_2 -= dz2;
}
err_1 += dy2;
err_2 += dx2;
pixel[2] += z_inc;
}
}
setvoxel(pixel[0],pixel[1],pixel[2]);
//printf("Setting %i %i %i \n", pixel[0],pixel[1],pixel[2]);
//PUT_PIXEL(pixel);
}

void init_LUT(unsigned char LUT[65])
{
unsigned char i;
float sin_of,sine;
for (i=0;i<65;i++)
{
sin_of=i*PI/64; // Just need half a sin wave
sine=sin(sin_of);
// Use 181.0 as this squared is <32767, so we can multiply two sin or cos without overflowing an int.
LUT[i]=sine*181.0;
}
}

int totty_sin(unsigned char LUT[65],int sin_of)
{
unsigned char inv=0;
if (sin_of<0)
{
sin_of=-sin_of;
inv=1;
}
sin_of&=0x7f; //127
if (sin_of>64)
{
sin_of-=64;
inv=1-inv;
}
if (inv)
return -LUT[sin_of];
else
return LUT[sin_of];
}

int totty_cos(unsigned char LUT[65],int cos_of)
{
unsigned char inv=0;
cos_of+=32;// Simply rotate by 90 degrees for COS
cos_of&=0x7f;//127
if (cos_of>64)
{
cos_of-=64;
inv=1;
}
if (inv)
return -LUT[cos_of];
else
return LUT[cos_of];
}

void effect_random_sparkle_flash (int iterations, int voxels, int delay)
{
int i;
int v;
for (i = 0; i < iterations; i++)
{
for (v=0;v<=voxels;v++)
setvoxel(rand()%8,rand()%8,rand()%8);

delay_ms(delay);
fill(0x00);
}
}

// 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);
}
}
}

Step 9: Programm (Game)

I wrote this part all by myself and changed it so many times that I almost got crazy.
You will find it in last step, and if you now it better please text me.
I know it’s not the finest work but it’s ok for me.

If you have some tips for me, or a new game or effect, or something, please text me.

Step 10: Add Sound With Arduino Uno

We need

to make sound:
1x Arduino uno
1x 8 ohm small speaker
1x 100 ohm resistor

see like this:
http://arduino.cc/en/Tutorial/tone


to communicate:
wire
2x resistor (between between 1,5 K and 47 Kohm)

see like this:
https://www.instructables.com/id/I2C-between-Ardui...

you'll find the code in the last step
the sounds based on song by: run against the wall, Zweifaktorentheorie der Intelligenz
I translate the notation from Midi data (see picture).

Step 11: The Final Code

Have fun!

If you have any questions please aks, after you googled it.

If you have some tips for me, or a new game or effect, or something, please text me.

I noticed that the code is only found only on the https://www.instructables.com and not on .de page.

Anred Zynch

123D Circuits Contest

Finalist in the
123D Circuits Contest

Supercharged Contest

Participated in the
Supercharged Contest