Project tutorial
LED Cube 4x4x4 very easy code with shift registers

LED Cube 4x4x4 very easy code with shift registers © GPL3+

How to make diffrent patterns for LED Cube 4x4x4 with shift registers

  • 997 views
  • 0 comments
  • 4 respects

Components and supplies

Necessary tools and machines

About this project

When I started to work with Arduino I was fascinating about LED Cube but it went very hard to make it for me. After a time I found out that it can be very easy.

In this article I focus mainly on very easy code for LED Cube 4x4x4 with shift registers and how to make diffrent patterns for the cube. I did not like codes I saw in such projects so I had to create it my own way.

Construction of the LED Cube

I am not going to explain how to join leds to make a cube 4x4x4 because there is a lot of videos on youtube how you can build it. For example: https://www.youtube.com/watch?v=hjrfa04KPYI

If you already have it after some moment of peace and patience you get a cube that has 16 legs and 4 rows. Les´s call these rows layers. The easiest way how to join those 16 legs to Arduino and not to occupy all its pins is to use the shift register 75HC595.

I joined the first 8 legs (1-8) of the cube to the first shift register (pins Q0-Q7) and other 8 legs (9-16) to another one as shown in the table from the top view:

The next step is to connect pins of the shift registers with Arduino as following:

  • PIN 8 (both shift registers / GND) to GROUND pin of Arduino
  • PIN 9 (Q7´) of the first shift register to PIN 14 (DATA) of the second shift register
  • PIN 10 (both shift registers / RESET) to PIN 8 of Arduino
  • PIN 11 (both shift registers / CLOCK) to PIN 9 of Arduino
  • PIN 12 (both shift registers / LATCH) to PIN 10 of Arduino
  • PIN 14 (first shift register / DATA) to PIN 11 of Arduino
  • PIN 16 (both shift registers / VCC) to 5V pin of Arduino

The last step is to connect layers of the cube with Arduino:

  • PIN 4 - Layer 0 (through 100ohm resistor)
  • PIN 5 - Layer 1 (through 100ohm resistor)
  • PIN 6 - Layer 2 (through 100ohm resistor)
  • PIN 7 - Layer 3 (through 100ohm resistor)

How to control leds

The alfa and omega of the project is to understand how we can control any led in the cube independantly from others. One layer contains 16 leds what leads us to an idea about setting 16 bits of an unsigned int. Shortly, every led in a layer is represented by a number as in this table:

So if we want to turn on the second led in the second row of the layer, we will set layer = 32. To turn on first 2 leds, layer = 1 + 2 = 3. To turn on first row of leds, layer = 1 + 2 + 4 + 8 = 15.

If we would like to move the light in the loop through all the leds in the layer, in the first step we set layer = B0000000000000001 = 1 and then in the loop we will shift this bit by setting layer = layer << 1. Or we can set layer = (1 << count) and increase "count" within the loop. For more information about setting and shifting bits in c++ use google.

The main LOOP

Now, when we know how to set leds in a layer we want to control 4 layers. Whereas we can send to our 2 shift registers information about 1 layer only, we use the main loop of Arduino to turn on and off layers in the cycle very quickly so our eyes evaluate it as they would be all changed at the same moment. The code to display values of layers is very simple:

 SetShiftReg(layer[k]);    //send layer data to shift registers
 bitClear(PORTD, 4 + k);   //turn ON layer k
 delay(1);                 //important for brightness of leds
 PORTD |= B11110000;       //turn OFF layers
 k++; if (k > 3) k = 0;    //take another layer in the loop

In my project I use the button (joined with ground and pin 2 of Arduino) to change patterns I created. Pushing the button sets the boolean "start". This start takes and initializes the next pattern.

Then the loop launches the selected pattern after every time in milliseconds that is set in the value "speedTime".

The tab about the main loop and the button:

#define buttonPin 2
unsigned int layer[4] = {0, 0, 0, 0};   //65535 filled layer
byte k = 0;
bool start = true;
unsigned long delayTime;
int speedTime = 0;
int count;
void setup() {
 InitializeShiftReg();
 InitializeMyLedCube();
}
void InitializeMyLedCube() {
 DDRD = B11110000;         //pins D0-D3 as INPUTS, D4-D7 as OUTPUTS
 PORTD |= B11110000;       //turn OFF layers
 pinMode(buttonPin, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
 delayTime = millis();
}
byte patternNum = 28;
byte pattern = patternNum - 1;
void loop() {
 if (start) {
   detachInterrupt(digitalPinToInterrupt(buttonPin));
   delay(500);   //wait for releasing PushButton
   pattern++; 
   if (pattern > patternNum) pattern = 1;
   attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
   count = 0;
 }
 if (((millis() - delayTime) > speedTime) || start) { 
   switch (pattern) {
     case 1: LayersUpDown(); break;
     case 2: FallingDot(); break;
     case 3: Rain(); break;
     case 4: AllCube(); break;
     case 5: Cut(); break;
     case 6: Cube(); break;
     case 7: Diagonal(); break;
     case 8: Mixer(); break;
     case 9: Random(); break;
     case 10: FallingLayer(); break;
     case 11: LayerCut(); break;
     case 12: Circle(); break;
     case 13: RandomWay(); break;
     case 14: SmallCube(); break;
     case 15: RandomWayCube(); break;
     case 16: GrowingCube(); break;
     case 17: FallingLayers(); break;
     case 18: GrowingLine(); break;
     case 19: CircleEdges(); break;
     case 20: CircleSide(); break;
     case 21: RandomWayLine(); break;
     case 22: RandomWaySide(); break;
     case 23: DJCube(); break;
     case 24: FillingCube(); break;
     case 25: NanoBuilding(); break;
     case 26: Curve(); break;
     case 27: Snake(); break;
     case 28: Julka(); break;
     default: break;
   }
   delayTime = millis();
 }
 //this part displays layers as they are set in functions
 SetShiftReg(layer[k]);    //send layer data to shift registers
 bitClear(PORTD, 4 + k);   //turn ON layer k
 delay(1);                 //important for brightness of leds
 PORTD |= B11110000;       //turn OFF layers
 k++; if (k > 3) k = 0;    //take another layer in the loop
}
void PushButton() {
 start = true;
}

The "ShiftRegister" tab:

#define latchPin 10   //PORT B2
#define clockPin 9    //PORT B1
#define dataPin 11    //PORT B3
#define resetPin 8    //PORT B0
void InitializeShiftReg() {
 DDRB |= B1111;  //pins D8-D11 as OUTPUTS
 PORTB |= B0001; //resetPin to HIGH 
}
void SetShiftReg(unsigned int value) {
  bitClear(PORTB, 2);   //digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, value >> 8); 
  shiftOut(dataPin, clockPin, MSBFIRST, value);      
  bitSet(PORTB, 2);    //digitalWrite(latchPin, HIGH);
}

Creating patterns

Creating patterns is very easy and the cube became as a big fun to think about new ones and how to make them. As you can see, the code about a pattern is usually very simple.

We must only understand that the main loop of Arduino launches the selected pattern after every time that we set in the start of the pattern in the value "speedTime". In other words, the function for a pattern always changes layers once only, but the main loop repeats it many times.

Let's look at the pattern Rain() as an example:

void Rain() {
 if (start) {
   start = false; speedTime = 200;
   ClearLayers();
 }
 layer[0] = layer[1];
 layer[1] = layer[2];
 layer[2] = layer[3];
 layer[3] = 1 << random(16);
}

The "start" part launches once only when we turn on the pattern. It sets the speedTime and turns off all leds. Then we always turn on 1 of 16 leds on the top layer randomly and within the loop we move it to lower layers.

Below you can find the code for patterns I created and some samples are in the video. HAVE FUN!

The "Patterns" tab:

bool direct;
unsigned int actualValue;
byte lay, xVal, yVal;
byte place;
void SetLayers(unsigned int value) {    //helpful function
 layer[0] = value; layer[1] = value; layer[2] = value; layer[3] = value;
}
void InversLayers() {    //helpful function
 layer[0] = 65535 - layer[0];
 layer[1] = 65535 - layer[1];
 layer[2] = 65535 - layer[2];
 layer[3] = 65535 - layer[3];
}
void ClearLayers() {    //helpful function
 SetLayers(0);
}
void LayersUpDown() {    
 if (start) {
   start = false;                                                                                                                                                                                                                                              speedTime = 500;
   direct = true;
 }
 ClearLayers();
 layer[count] = 65535;
 if (direct) {
  count++; 
  if (count > 3) { 
    direct = false;
    count = 2;
  }
 } else {
   count--; if (count < 1) direct = true;
 }
}
void FallingDot() {
 if (start) {
   start = false; speedTime = 100;
   count = 4;
   actualValue = 1;
   direct = true;
 }
 count--;
 ClearLayers();
 layer[count] = actualValue;
 if (count == 0) {
   count = 4;
   actualValue = actualValue << 1;
   if (actualValue == 0) actualValue = 1;
 }
}
void Rain() {
 if (start) {
   start = false; speedTime = 200;
   ClearLayers();
 }
 layer[0] = layer[1];
 layer[1] = layer[2];
 layer[2] = layer[3];
 layer[3] = 1 << random(16);
}
void Random() {
 if (start) {
   start = false; speedTime = 200;
 }
 layer[0] = random(65536);
 layer[1] = random(65536);
 layer[2] = random(65536);
 layer[3] = random(65536);
}
void AllCube() {
 if (start) {
   start = false; speedTime = 2000;
 }
 ClearLayers();
 switch (count) {
   case 0:
     SetLayers(65535);
     break;
   case 1:
     layer[1] = 1632; 
     layer[2] = 1632;  
     break; 
 }
 count++; if (count > 1) count = 0;
}
void Cut() {
 if (start) {
   start = false; speedTime = 2000;
   layer[0] = 4369; 
   layer[1] = 13107; 
   layer[2] = 30583; 
   layer[3] = 65535;
 }
 InversLayers();
}
void Cube() {
 if (start) {
   start = false; speedTime = 2000;
   layer[0] = 15+16+128+256+2048+4096+8192+16384+32768; 
   layer[1] = 1+8+4096+32768; 
   layer[2] = layer[1]; 
   layer[3] = layer[0];
 }
 InversLayers();
}
void Diagonal() {
 if (start) {
   start = false; speedTime = 2000;
   layer[0] = 33825; 
   layer[1] = 33825; 
   layer[2] = 33825; 
   layer[3] = 33825;
 }
 InversLayers();
}
void Mixer() {
 if (start) {
   start = false; speedTime = 100;
 }
 switch (count) {
   case 0: actualValue = 33825; break;
   case 1: actualValue = 17442; break;
   case 2: actualValue = 8772; break;
   case 3: actualValue = 4680; break;
   case 4: actualValue = 960; break;
   case 5: actualValue = 3120; break;
 }
 SetLayers(actualValue); 
 count++;
 if (count > 5) count = 0;
}
void FallingLayer() {
 if (start) {
   start = false; speedTime = 100;
   actualValue = 0;
   direct = false;
 }
 if (actualValue == 0) {
   actualValue = 1;
   ClearLayers();
   direct = !direct;
   layer[3 - (direct? 0:3)] = 65535;
 }
 switch (count) {
   case 0:
     layer[3 - (direct? 0:3)] -= actualValue;
     layer[2 - (direct? 0:1)] = actualValue;
     break;
   case 1:
     layer[1 + (direct? 0:1)] = layer[2  - (direct? 0:1)];
     layer[2 - (direct? 0:1)] = 0;
     break;
   case 2:
     layer[0 + (direct? 0:3)] += layer[1 + (direct? 0:1)];
     layer[1 + (direct? 0:1)] = 0;
     actualValue = actualValue << 1;
     break;
 }
 count++; if (count > 2) count = 0;
}
void LayerCut() {
 if (start) {
   start = false; speedTime = 100;
 }
 if (count) layer[0] = layer[0] << 1;
 else layer[0] = 4369;
 SetLayers(layer[0]);
 count++;
 if (count > 20) count = 0;
}
void Circle() {
 if (start) {
   start = false; speedTime = 100;
   lay = 3;
 }
 switch (count) {
   case 0: ClearLayers(); layer[lay] = 1; break;
   case 1: layer[lay] = 2; break;
   case 2: layer[lay] = 4; break;
   case 3: layer[lay] = 8; break;
   case 4: layer[lay] = 128; break;
   case 5: layer[lay] = 2048; break;
   case 6: layer[lay] = 32768; break;
   case 7: layer[lay] = 16384; break;
   case 8: layer[lay] = 8192; break;
   case 9: layer[lay] = 4096; break;
   case 10: layer[lay] = 256; break;
   case 11: layer[lay] = 16; break;
   case 12: layer[lay] = 1; break;
 }
 count++;
 if (count > 12) {
   count = 0;
   if (lay == 0) lay = 3;
   else lay--;
 }
}
void RandomWay() {
 if (start) {
   start = false; speedTime = 200;
   lay = random(4);
   xVal = random(4);
   yVal = random(4);
 }
 switch (random(7)) {
   case 0: if ((lay + 1) <= 3) lay++; break;
   case 1: if ((lay - 1) >= 0) lay--; break;
   case 2: if ((xVal + 1) <= 3) xVal++; break;
   case 3: if ((xVal - 1) >= 0) xVal--; break;
   case 4: if ((yVal + 1) <= 3) yVal++; break;
   case 5: if ((yVal - 1) >= 0) yVal--; break;
   default: break;
 }
 ClearLayers();
 layer[lay] = (1 << xVal) << (4 * yVal);
}
void SmallCube() {
 if (start) {
   start = false; speedTime = 200;
 }
 switch (count) {
   case 0: lay = random(3); ClearLayers(); actualValue = 51; break;
   case 1: actualValue = actualValue << 1; break;
   case 2: actualValue = actualValue << 1; break;
   case 3: actualValue = actualValue << 4; break;
   case 4: actualValue = actualValue << 4; break;
   case 5: actualValue = actualValue >> 1; break;
   case 6: actualValue = actualValue >> 1; break;
   case 7: actualValue = actualValue >> 4; break;
   case 8: actualValue = actualValue >> 4; break;
 }
 layer[lay] = actualValue;
 layer[lay+1] = actualValue;
 count++; if (count > 8) count = 0;
}
void RandomWayCube() {
 if (start) {
   start = false; speedTime = 200;
   lay = random(3);
   xVal = random(3);
   yVal = random(3);
 }
 switch (random(7)) {
   case 0: if ((lay + 1) < 3) lay++; break;
   case 1: if ((lay - 1) >= 0) lay--; break;
   case 2: if ((xVal + 1) < 3) xVal++; break;
   case 3: if ((xVal - 1) >= 0) xVal--; break;
   case 4: if ((yVal + 1) < 3) yVal++; break;
   case 5: if ((yVal - 1) >= 0) yVal--; break;
   default: break;
 }
 ClearLayers();
 layer[lay] = (51 << xVal) << (4 * yVal);
 layer[lay+1] = layer[lay];
}
void GrowingCube() {
 if (start) {
   start = false; speedTime = 1000;
 }
 switch (count) {
   case 0: ClearLayers(); layer[0] = 1; break;
   case 1: layer[0] = 51; layer[1] = 51; break;
   case 2: layer[0] = 1911; layer[1] = 1911; layer[2] = 1911; break;
   case 3: SetLayers(65535); break;
   default: break;
 }
 count++; if (count > 4) count = 0;
}
void FallingLayers() {
 if (start) {
   start = false; speedTime = 200;
   actualValue = 0;
   lay = 4;
 }
 if (actualValue == 0) {
   lay--; if (lay < 1) lay = 3;
   actualValue = 1;
   ClearLayers();
   layer[lay] = 65535;
 }
 layer[lay] -= actualValue;
 layer[lay-1] += actualValue;
 actualValue = actualValue << 1;
}
void GrowingLine() {
 if (start) {
   start = false; speedTime = 100;
 }
 switch (count) {
   case 0:
     ClearLayers();
     layer[0] = 1;
     lay = 0; xVal = 0; yVal = 0;
     while ((lay == 0) && (xVal == 0) && (yVal == 0)) {
       lay = random(2);
       xVal = random(2);
       yVal = random(2);
     }
     break;
   case 1: layer[lay] += ((xVal==0)?1:2) << (4 * yVal); break;
   case 2: layer[2 * lay] += ((xVal==0)?1:4) << (8 * yVal); break;
   case 3: layer[3 * lay] += ((xVal==0)?1:8) << (12 * yVal); break; 
   case 4: layer[3 * lay] -= ((xVal==0)?1:8) << (12 * yVal); break; 
   case 5: layer[2 * lay] -= ((xVal==0)?1:4) << (8 * yVal); break;
   default: break;     
 }
 count++; if (count > 5) count = 0;
}
void CircleEdges() {
 if (start) {
   start = false; speedTime = 100;
   lay = 3;
   ClearLayers();
 }
 switch (count) {
   case 0: layer[lay] = 1; break;
   case 1: layer[lay] += 2; break;
   case 2: layer[lay] += 4; break;
   case 3: layer[lay] += 8; break;
   case 4: layer[lay] += 128; break;
   case 5: layer[lay] += 2048; break;
   case 6: layer[lay] += 32768; break;
   case 7: layer[lay] += 16384; break;
   case 8: layer[lay] += 8192; break;
   case 9: layer[lay] += 4096; break;
   case 10: layer[lay]+= 256; break;
   case 11: layer[lay] += 16; break;
   default: break;
 }
 count++;
 if (count > 12) {
   count = 0;
   if (lay == 0) {
     lay = 3;
     ClearLayers();
   }
   else lay--;
 }
}
void CircleSide() {
 if (start) {
   start = false; speedTime = 1000;
 }
 switch (count) {
   case 0: SetLayers(15); break;
   case 1: SetLayers(34952); break;
   case 2: SetLayers(61440); break;
   case 3: SetLayers(4369); break;
   case 4: ClearLayers(); layer[0] = 65535; break;
   case 5: SetLayers(34952); break;
   case 6: ClearLayers(); layer[3] = 65535; break;
   case 7: SetLayers(4369); break;
 }
 count++;
 if (count > 7) count = 0;
}
void RandomWayLine() {
 if (start) {
   start = false; speedTime = 200;
   lay = random(3);
   yVal = random(3);
 }
 switch (random(5)) {
   case 0: if ((lay + 1) <= 3) lay++; break;
   case 1: if ((lay - 1) >= 0) lay--; break;
   case 2: if ((yVal + 1) <= 3) yVal++; break;
   case 3: if ((yVal - 1) >= 0) yVal--; break;
   default: break;
 }
 ClearLayers();
 layer[lay] = 15 << (4 * yVal);
}
void RandomWaySide() {
 if (start) {
   start = false; speedTime = 200;
   xVal = random(3);
 }
 switch (random(3)) {
   case 0: if ((xVal + 1) <= 3) xVal++; break;
   case 1: if ((xVal - 1) >= 0) xVal--; break;
   default: break;
 }
 ClearLayers();
 actualValue = 4369 << xVal;
 switch (random(2)) {
   case 0: SetLayers(actualValue); break;
   case 1: layer[1] = actualValue; layer[2] = actualValue; break;
 }
}
void DJCube() {
 if (start) {
   start = false; speedTime = 200;
   xVal = random(3);
 }
 switch (random(3)) {
   case 0: if ((xVal + 1) <= 3) xVal++; break;
   case 1: if ((xVal - 1) >= 0) xVal--; break;
   default: break;
 }
 switch (xVal) {
   case 0: SetLayers(4369); break;
   case 1: SetLayers(13107); break;
   case 2: SetLayers(30583); break;
   case 3: SetLayers(65535); break;
 }
}
void FillingCube() {
 if (start) {
   start = false; speedTime = 200;
   count = 4;
   actualValue = 1;
 }
 if ((count == 4) && (actualValue == 1)) ClearLayers();
 count--;
 layer[count] += actualValue;
 if (count == 0) {
   count = 4;
   actualValue = actualValue << 1;
   if (actualValue == 0) actualValue = 1;
 }
}
void NanoBuilding() {
 if (start) {
   start = false; speedTime = 150;
   actualValue = 0;
   place = 1;
   direct = true;
 }
 if (direct) {
   direct = false;
   while ((actualValue < place) && (place < 64)) {
     lay = random(4);
     xVal = random(4);
     yVal = random(4);     
     actualValue = xVal + (yVal * 4) + (lay * 16);
   }
 }
 actualValue = 0;
 int xValP = xVal;
 int yValP = yVal;
 int layP = lay;
 while ((actualValue < place) && (place < 64)) {
   xVal = xValP;
   yVal = yValP;
   lay = layP;
   switch (random(7)) {
     case 0: if ((lay + 1) <= 3) lay++; break;
     case 1: if ((lay - 1) >= 0) lay--; break;
     case 2: if ((xVal + 1) <= 3) xVal++; break;
     case 3: if ((xVal - 1) >= 0) xVal--; break;
     case 4: if ((yVal + 1) <= 3) yVal++; break;
     case 5: if ((yVal - 1) >= 0) yVal--; break;
     default: break;
   }
   actualValue = xVal + (yVal * 4) + (lay * 16);
 }
 if (actualValue == place) {
   place++;
   direct = true;
 }
 ClearLayers();
 if (place < 16) layer[0] = (1 << place) - 1;
 else {
   if (place < 32) {
     layer[1] = (1 << (place - 16)) - 1;
     layer[0] = 65535;
   } else {
     if (place < 48) {
       layer[2] = (1 << (place - 32)) - 1;
       layer[0] = 65535;
       layer[1] = 65535;
     } else {
       if (place < 64) {
         SetLayers(65535);
         layer[3] = (1 << (place - 48)) - 1;
       } else place = 1;
     }
   }
 }
 layer[lay] |= ((1 << xVal) << (4 * yVal));
}
void Curve() {
 int line[4] = {4369, 8738, 17476, 34952};
 byte pos[12] = {0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3};
 if (start) {
   start = false; speedTime = 100;
 }
 layer[0] = ((pos[count] == 0) ? line[0]: 0) + ((pos[count+1] == 0) ? line[1]: 0) + ((pos[count+2] == 0) ? line[2]: 0) + ((pos[count+3] == 0) ? line[3]: 0);
 layer[1] = ((pos[count] == 1) ? line[0]: 0) + ((pos[count+1] == 1) ? line[1]: 0) + ((pos[count+2] == 1) ? line[2]: 0) + ((pos[count+3] == 1) ? line[3]: 0);
 layer[2] = ((pos[count] == 2) ? line[0]: 0) + ((pos[count+1] == 2) ? line[1]: 0) + ((pos[count+2] == 2) ? line[2]: 0) + ((pos[count+3] == 2) ? line[3]: 0);
 layer[3] = ((pos[count] == 3) ? line[0]: 0) + ((pos[count+1] == 3) ? line[1]: 0) + ((pos[count+2] == 3) ? line[2]: 0) + ((pos[count+3] == 3) ? line[3]: 0);
 count++; if (count > 7) count = 0; 
}
struct snake {
 byte x, y, z;
} obj[7]; 
void Snake() {
 int k;
 byte c = 7;
 if (start) {
   start = false; speedTime = 200;
   for (k = 0; k < c; k++) {
     obj[k].x = 0;
     obj[k].y = 0;
     obj[k].z = 0;
   }
   lay = 0;
   xVal = 0;
   yVal = 0;
 }
 int xValP = xVal;
 int yValP = yVal;
 int layP = lay;
 direct = true;
 while (direct) {
   xVal = xValP;
   yVal = yValP;
   lay = layP;
   switch (random(6)) {
     case 0: if ((lay + 1) <= 3) lay++; break;
     case 1: if ((lay - 1) >= 0) lay--; break;
     case 2: if ((xVal + 1) <= 3) xVal++; break;
     case 3: if ((xVal - 1) >= 0) xVal--; break;
     case 4: if ((yVal + 1) <= 3) yVal++; break;
     case 5: if ((yVal - 1) >= 0) yVal--; break;
     default: break;
   }
   direct = false;
   for (k = 0; k < c; k++) {
     if ((xVal == obj[k].x) && (yVal == obj[k].y) && (lay == obj[k].z)) direct = true;
   }
 }
 for (k = c-2; k >= 0; k--) {
   obj[k+1].x = obj[k].x;
   obj[k+1].y = obj[k].y;
   obj[k+1].z = obj[k].z;
 }
 obj[0].x = xVal;
 obj[0].y = yVal;
 obj[0].z = lay;
 ClearLayers();
 for (k = 0; k < c; k++) {
   layer[obj[k].z] += (1 << obj[k].x) << (4 * obj[k].y);  
 }
}
void Julka() {
 int letters[5] = {59556, 43694, 8750, 58446, 60138};
 if (start) {
   start = false; speedTime = 1000;
   ClearLayers();
 }
 layer[3] = letters[count];
 count++;
 if (count == 5) count = 0;
}
Samples of patterns

Code

The main loopArduino
#define buttonPin 2

unsigned int layer[4] = {0, 0, 0, 0};   //65535 filled layer
byte k = 0;
bool start = true;
unsigned long delayTime;
int speedTime = 0;
int count;

void setup() {
  InitializeShiftReg();
  InitializeMyLedCube();
}

void InitializeMyLedCube() {
  DDRD = B11110000;         //pins D0-D3 as INPUTS, D4-D7 as OUTPUTS
  PORTD |= B11110000;     //turn OFF layers
  pinMode(buttonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
  delayTime = millis();
}

byte patternNum = 28;
byte pattern = patternNum - 1;

void loop() {
  if (start) {
    detachInterrupt(digitalPinToInterrupt(buttonPin));
    delay(500);   //wait for releasing PushButton
    pattern++; 
    if (pattern > patternNum) pattern = 1;
    attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
    count = 0;
  }
  if (((millis() - delayTime) > speedTime) || start) { 
    switch (pattern) {
      case 1: LayersUpDown(); break;
      case 2: FallingDot(); break;
      case 3: Rain(); break;
      case 4: AllCube(); break;
      case 5: Cut(); break;
      case 6: Cube(); break;
      case 7: Diagonal(); break;
      case 8: Mixer(); break;
      case 9: Random(); break;
      case 10: FallingLayer(); break;
      case 11: LayerCut(); break;
      case 12: Circle(); break;
      case 13: RandomWay(); break;
      case 14: SmallCube(); break;
      case 15: RandomWayCube(); break;
      case 16: GrowingCube(); break;
      case 17: FallingLayers(); break;
      case 18: GrowingLine(); break;
      case 19: CircleEdges(); break;
      case 20: CircleSide(); break;
      case 21: RandomWayLine(); break;
      case 22: RandomWaySide(); break;
      case 23: DJCube(); break;
      case 24: FillingCube(); break;
      case 25: NanoBuilding(); break;
      case 26: Curve(); break;
      case 27: Snake(); break;
      case 28: Julka(); break;
      default: break;
    }
    delayTime = millis();
  }

  //this part displays layers as they are set in functions
  SetShiftReg(layer[k]);    //send layer data to shift registers
  bitClear(PORTD, 4 + k);   //turn ON layer k
  delay(1);                 //important for brightness of leds
  PORTD |= B11110000;       //turn OFF layers
  k++; if (k > 3) k = 0;    //take another layer in the loop
}

void PushButton() {
  start = true;
}
ShiftRegister TabArduino
#define latchPin 10   //PORT B2
#define clockPin 9    //PORT B1
#define dataPin 11    //PORT B3
#define resetPin 8    //PORT B0

void InitializeShiftReg() {
  DDRB |= B1111;  //pins D8-D11 as OUTPUTS
  PORTB |= B0001; //resetPin to HIGH 
}

void SetShiftReg(unsigned int value) {
   bitClear(PORTB, 2);   //digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, MSBFIRST, value >> 8);   //shift out high byte, alternative: LSBFIRST / MSBFIRST
   shiftOut(dataPin, clockPin, MSBFIRST, value);        //shift out low byte, alternative: LSBFIRST / MSBFIRST
   bitSet(PORTB, 2);    //digitalWrite(latchPin, HIGH);
}
The Patterns TabArduino
bool direct;
unsigned int actualValue;
byte lay, xVal, yVal;
byte place;

void SetLayers(unsigned int value) {
  layer[0] = value; layer[1] = value; layer[2] = value; layer[3] = value;
}

void InversLayers() {
  layer[0] = 65535 - layer[0];
  layer[1] = 65535 - layer[1];
  layer[2] = 65535 - layer[2];
  layer[3] = 65535 - layer[3];
}

void ClearLayers() {
  SetLayers(0);
}

void LayersUpDown() {
  if (start) {
    start = false;                                                                                                                                                                                                                                              speedTime = 500;
    direct = true;
  }
  ClearLayers();
  layer[count] = 65535;
  if (direct) {
   count++; 
   if (count > 3) { 
     direct = false;
     count = 2;
   }
  } else {
    count--; if (count < 1) direct = true;
  }
}

void FallingDot() {
  if (start) {
    start = false; speedTime = 100;
    count = 4;
    actualValue = 1;
    direct = true;
  }
  count--;
  ClearLayers();
  layer[count] = actualValue;
  if (count == 0) {
    count = 4;
    actualValue = actualValue << 1;
    if (actualValue == 0) actualValue = 1;
  }
}

void Rain() {
  if (start) {
    start = false; speedTime = 200;
    ClearLayers();
  }
  layer[0] = layer[1];
  layer[1] = layer[2];
  layer[2] = layer[3];
  layer[3] = 1 << random(16);
}

void Random() {
  if (start) {
    start = false; speedTime = 200;
  }
  layer[0] = random(65536);
  layer[1] = random(65536);
  layer[2] = random(65536);
  layer[3] = random(65536);
}

void AllCube() {
  if (start) {
    start = false; speedTime = 2000;
  }
  ClearLayers();
  switch (count) {
    case 0:
      SetLayers(65535);
      break;
    case 1:
      layer[1] = 1632; 
      layer[2] = 1632;  
      break; 
  }
  count++; if (count > 1) count = 0;
}

void Cut() {
  if (start) {
    start = false; speedTime = 2000;
    layer[0] = 4369; 
    layer[1] = 13107; 
    layer[2] = 30583; 
    layer[3] = 65535;
  }
  InversLayers();
}

void Cube() {
  if (start) {
    start = false; speedTime = 2000;
    layer[0] = 15+16+128+256+2048+4096+8192+16384+32768; 
    layer[1] = 1+8+4096+32768; 
    layer[2] = layer[1]; 
    layer[3] = layer[0];
  }
  InversLayers();
}

void Diagonal() {
  if (start) {
    start = false; speedTime = 2000;
    layer[0] = 33825; 
    layer[1] = 33825; 
    layer[2] = 33825; 
    layer[3] = 33825;
  }
  InversLayers();
}

void Mixer() {
  if (start) {
    start = false; speedTime = 100;
  }
  switch (count) {
    case 0: actualValue = 33825; break;
    case 1: actualValue = 17442; break;
    case 2: actualValue = 8772; break;
    case 3: actualValue = 4680; break;
    case 4: actualValue = 960; break;
    case 5: actualValue = 3120; break;
  }
  SetLayers(actualValue); 
  count++;
  if (count > 5) count = 0;
}

void FallingLayer() {
  if (start) {
    start = false; speedTime = 100;
    actualValue = 0;
    direct = false;
  }
  if (actualValue == 0) {
    actualValue = 1;
    ClearLayers();
    direct = !direct;
    layer[3 - (direct? 0:3)] = 65535;
  }
  switch (count) {
    case 0:
      layer[3 - (direct? 0:3)] -= actualValue;
      layer[2 - (direct? 0:1)] = actualValue;
      break;
    case 1:
      layer[1 + (direct? 0:1)] = layer[2  - (direct? 0:1)];
      layer[2 - (direct? 0:1)] = 0;
      break;
    case 2:
      layer[0 + (direct? 0:3)] += layer[1 + (direct? 0:1)];
      layer[1 + (direct? 0:1)] = 0;
      actualValue = actualValue << 1;
      break;
  }
  count++; if (count > 2) count = 0;
}

void LayerCut() {
  if (start) {
    start = false; speedTime = 100;
  }
  if (count) layer[0] = layer[0] << 1;
  else layer[0] = 4369;
  SetLayers(layer[0]);
  count++;
  if (count > 20) count = 0;
}

void Circle() {
  if (start) {
    start = false; speedTime = 100;
    lay = 3;
  }
  switch (count) {
    case 0: ClearLayers(); layer[lay] = 1; break;
    case 1: layer[lay] = 2; break;
    case 2: layer[lay] = 4; break;
    case 3: layer[lay] = 8; break;
    case 4: layer[lay] = 128; break;
    case 5: layer[lay] = 2048; break;
    case 6: layer[lay] = 32768; break;
    case 7: layer[lay] = 16384; break;
    case 8: layer[lay] = 8192; break;
    case 9: layer[lay] = 4096; break;
    case 10: layer[lay] = 256; break;
    case 11: layer[lay] = 16; break;
    case 12: layer[lay] = 1; break;
  }
  count++;
  if (count > 12) {
    count = 0;
    if (lay == 0) lay = 3;
    else lay--;
  }
}

void RandomWay() {
  if (start) {
    start = false; speedTime = 200;
    lay = random(4);
    xVal = random(4);
    yVal = random(4);
  }
  switch (random(7)) {
    case 0: if ((lay + 1) <= 3) lay++; break;
    case 1: if ((lay - 1) >= 0) lay--; break;
    case 2: if ((xVal + 1) <= 3) xVal++; break;
    case 3: if ((xVal - 1) >= 0) xVal--; break;
    case 4: if ((yVal + 1) <= 3) yVal++; break;
    case 5: if ((yVal - 1) >= 0) yVal--; break;
    default: break;
  }
  ClearLayers();
  layer[lay] = (1 << xVal) << (4 * yVal);
}

void SmallCube() {
  if (start) {
    start = false; speedTime = 200;
  }
  switch (count) {
    case 0: lay = random(3); ClearLayers(); actualValue = 51; break;
    case 1: actualValue = actualValue << 1; break;
    case 2: actualValue = actualValue << 1; break;
    case 3: actualValue = actualValue << 4; break;
    case 4: actualValue = actualValue << 4; break;
    case 5: actualValue = actualValue >> 1; break;
    case 6: actualValue = actualValue >> 1; break;
    case 7: actualValue = actualValue >> 4; break;
    case 8: actualValue = actualValue >> 4; break;
  }
  layer[lay] = actualValue;
  layer[lay+1] = actualValue;
  count++; if (count > 8) count = 0;
}

void RandomWayCube() {
  if (start) {
    start = false; speedTime = 200;
    lay = random(3);
    xVal = random(3);
    yVal = random(3);
  }
  switch (random(7)) {
    case 0: if ((lay + 1) < 3) lay++; break;
    case 1: if ((lay - 1) >= 0) lay--; break;
    case 2: if ((xVal + 1) < 3) xVal++; break;
    case 3: if ((xVal - 1) >= 0) xVal--; break;
    case 4: if ((yVal + 1) < 3) yVal++; break;
    case 5: if ((yVal - 1) >= 0) yVal--; break;
    default: break;
  }
  ClearLayers();
  layer[lay] = (51 << xVal) << (4 * yVal);
  layer[lay+1] = layer[lay];
}

void GrowingCube() {
  if (start) {
    start = false; speedTime = 1000;
  }
  switch (count) {
    case 0: ClearLayers(); layer[0] = 1; break;
    case 1: layer[0] = 51; layer[1] = 51; break;
    case 2: layer[0] = 1911; layer[1] = 1911; layer[2] = 1911; break;
    case 3: SetLayers(65535); break;
    default: break;
  }
  count++; if (count > 4) count = 0;
}

void FallingLayers() {
  if (start) {
    start = false; speedTime = 200;
    actualValue = 0;
    lay = 4;
  }
  if (actualValue == 0) {
    lay--; if (lay < 1) lay = 3;
    actualValue = 1;
    ClearLayers();
    layer[lay] = 65535;
  }
  layer[lay] -= actualValue;
  layer[lay-1] += actualValue;
  actualValue = actualValue << 1;
}

void GrowingLine() {
  if (start) {
    start = false; speedTime = 100;
  }
  switch (count) {
    case 0:
      ClearLayers();
      layer[0] = 1;
      lay = 0; xVal = 0; yVal = 0;
      while ((lay == 0) && (xVal == 0) && (yVal == 0)) {
        lay = random(2);
        xVal = random(2);
        yVal = random(2);
      }
      break;
    case 1: layer[lay] += ((xVal==0)?1:2) << (4 * yVal); break;
    case 2: layer[2 * lay] += ((xVal==0)?1:4) << (8 * yVal); break;
    case 3: layer[3 * lay] += ((xVal==0)?1:8) << (12 * yVal); break; 
    case 4: layer[3 * lay] -= ((xVal==0)?1:8) << (12 * yVal); break; 
    case 5: layer[2 * lay] -= ((xVal==0)?1:4) << (8 * yVal); break;
    default: break;     
  }
  count++; if (count > 5) count = 0;
}

void CircleEdges() {
  if (start) {
    start = false; speedTime = 100;
    lay = 3;
    ClearLayers();
  }
  switch (count) {
    case 0: layer[lay] = 1; break;
    case 1: layer[lay] += 2; break;
    case 2: layer[lay] += 4; break;
    case 3: layer[lay] += 8; break;
    case 4: layer[lay] += 128; break;
    case 5: layer[lay] += 2048; break;
    case 6: layer[lay] += 32768; break;
    case 7: layer[lay] += 16384; break;
    case 8: layer[lay] += 8192; break;
    case 9: layer[lay] += 4096; break;
    case 10: layer[lay]+= 256; break;
    case 11: layer[lay] += 16; break;
    default: break;
  }
  count++;
  if (count > 12) {
    count = 0;
    if (lay == 0) {
      lay = 3;
      ClearLayers();
    }
    else lay--;
  }
}

void CircleSide() {
  if (start) {
    start = false; speedTime = 1000;
  }
  switch (count) {
    case 0: SetLayers(15); break;
    case 1: SetLayers(34952); break;
    case 2: SetLayers(61440); break;
    case 3: SetLayers(4369); break;
    case 4: ClearLayers(); layer[0] = 65535; break;
    case 5: SetLayers(34952); break;
    case 6: ClearLayers(); layer[3] = 65535; break;
    case 7: SetLayers(4369); break;
  }
  count++;
  if (count > 7) count = 0;
}

void RandomWayLine() {
  if (start) {
    start = false; speedTime = 200;
    lay = random(3);
    yVal = random(3);
  }
  switch (random(5)) {
    case 0: if ((lay + 1) <= 3) lay++; break;
    case 1: if ((lay - 1) >= 0) lay--; break;
    case 2: if ((yVal + 1) <= 3) yVal++; break;
    case 3: if ((yVal - 1) >= 0) yVal--; break;
    default: break;
  }
  ClearLayers();
  layer[lay] = 15 << (4 * yVal);
}

void RandomWaySide() {
  if (start) {
    start = false; speedTime = 200;
    xVal = random(3);
  }
  switch (random(3)) {
    case 0: if ((xVal + 1) <= 3) xVal++; break;
    case 1: if ((xVal - 1) >= 0) xVal--; break;
    default: break;
  }
  ClearLayers();
  actualValue = 4369 << xVal;
  switch (random(2)) {
    case 0: SetLayers(actualValue); break;
    case 1: layer[1] = actualValue; layer[2] = actualValue; break;
  }
}

void DJCube() {
  if (start) {
    start = false; speedTime = 200;
    xVal = random(3);
  }
  switch (random(3)) {
    case 0: if ((xVal + 1) <= 3) xVal++; break;
    case 1: if ((xVal - 1) >= 0) xVal--; break;
    default: break;
  }
  switch (xVal) {
    case 0: SetLayers(4369); break;
    case 1: SetLayers(13107); break;
    case 2: SetLayers(30583); break;
    case 3: SetLayers(65535); break;
  }
}

void FillingCube() {
  if (start) {
    start = false; speedTime = 200;
    count = 4;
    actualValue = 1;
  }
  if ((count == 4) && (actualValue == 1)) ClearLayers();
  count--;
  layer[count] += actualValue;
  if (count == 0) {
    count = 4;
    actualValue = actualValue << 1;
    if (actualValue == 0) actualValue = 1;
  }
}

void NanoBuilding() {
  if (start) {
    start = false; speedTime = 150;
    actualValue = 0;
    place = 1;
    direct = true;
  }
  if (direct) {
    direct = false;
    while ((actualValue < place) && (place < 64)) {
      lay = random(4);
      xVal = random(4);
      yVal = random(4);     
      actualValue = xVal + (yVal * 4) + (lay * 16);
    }
  }
  actualValue = 0;
  int xValP = xVal;
  int yValP = yVal;
  int layP = lay;
  while ((actualValue < place) && (place < 64)) {
    xVal = xValP;
    yVal = yValP;
    lay = layP;
    switch (random(7)) {
      case 0: if ((lay + 1) <= 3) lay++; break;
      case 1: if ((lay - 1) >= 0) lay--; break;
      case 2: if ((xVal + 1) <= 3) xVal++; break;
      case 3: if ((xVal - 1) >= 0) xVal--; break;
      case 4: if ((yVal + 1) <= 3) yVal++; break;
      case 5: if ((yVal - 1) >= 0) yVal--; break;
      default: break;
    }
    actualValue = xVal + (yVal * 4) + (lay * 16);
  }
  if (actualValue == place) {
    place++;
    direct = true;
  }
  ClearLayers();
  if (place < 16) layer[0] = (1 << place) - 1;
  else {
    if (place < 32) {
      layer[1] = (1 << (place - 16)) - 1;
      layer[0] = 65535;
    } else {
      if (place < 48) {
        layer[2] = (1 << (place - 32)) - 1;
        layer[0] = 65535;
        layer[1] = 65535;
      } else {
        if (place < 64) {
          SetLayers(65535);
          layer[3] = (1 << (place - 48)) - 1;
        } else place = 1;
      }
    }
  }
  layer[lay] |= ((1 << xVal) << (4 * yVal));
}

void Curve() {
  int line[4] = {4369, 8738, 17476, 34952};
  byte pos[12] = {0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3};
  
  if (start) {
    start = false; speedTime = 100;
  }
  layer[0] = ((pos[count] == 0) ? line[0]: 0) + ((pos[count+1] == 0) ? line[1]: 0) + ((pos[count+2] == 0) ? line[2]: 0) + ((pos[count+3] == 0) ? line[3]: 0);
  layer[1] = ((pos[count] == 1) ? line[0]: 0) + ((pos[count+1] == 1) ? line[1]: 0) + ((pos[count+2] == 1) ? line[2]: 0) + ((pos[count+3] == 1) ? line[3]: 0);
  layer[2] = ((pos[count] == 2) ? line[0]: 0) + ((pos[count+1] == 2) ? line[1]: 0) + ((pos[count+2] == 2) ? line[2]: 0) + ((pos[count+3] == 2) ? line[3]: 0);
  layer[3] = ((pos[count] == 3) ? line[0]: 0) + ((pos[count+1] == 3) ? line[1]: 0) + ((pos[count+2] == 3) ? line[2]: 0) + ((pos[count+3] == 3) ? line[3]: 0);
  count++; if (count > 7) count = 0; 
}

struct snake {
  byte x, y, z;
} obj[7]; 

void Snake() {
  int k;
  byte c = 7;
  if (start) {
    start = false; speedTime = 200;
    for (k = 0; k < c; k++) {
      obj[k].x = 0;
      obj[k].y = 0;
      obj[k].z = 0;
    }
    lay = 0;
    xVal = 0;
    yVal = 0;
  }
  int xValP = xVal;
  int yValP = yVal;
  int layP = lay;
  direct = true;
  while (direct) {
    xVal = xValP;
    yVal = yValP;
    lay = layP;
    switch (random(6)) {
      case 0: if ((lay + 1) <= 3) lay++; break;
      case 1: if ((lay - 1) >= 0) lay--; break;
      case 2: if ((xVal + 1) <= 3) xVal++; break;
      case 3: if ((xVal - 1) >= 0) xVal--; break;
      case 4: if ((yVal + 1) <= 3) yVal++; break;
      case 5: if ((yVal - 1) >= 0) yVal--; break;
      default: break;
    }
    direct = false;
    for (k = 0; k < c; k++) {
      if ((xVal == obj[k].x) && (yVal == obj[k].y) && (lay == obj[k].z)) direct = true;
    }
  }
  for (k = c-2; k >= 0; k--) {
    obj[k+1].x = obj[k].x;
    obj[k+1].y = obj[k].y;
    obj[k+1].z = obj[k].z;
  }
  obj[0].x = xVal;
  obj[0].y = yVal;
  obj[0].z = lay;
  ClearLayers();
  for (k = 0; k < c; k++) {
    layer[obj[k].z] += (1 << obj[k].x) << (4 * obj[k].y);  
  }
}

void Julka() {
  int letters[5] = {59556, 43694, 8750, 58446, 60138};
  if (start) {
    start = false; speedTime = 1000;
    ClearLayers();
  }
  layer[3] = letters[count];
  count++;
  if (count == 5) count = 0;
}

Comments

Similar projects you might like

4x4x4 LED cube with Arduino Uno and 1sheeld

Project tutorial by Hassan Ibrahim

  • 42,005 views
  • 6 comments
  • 71 respects

LED Cube

Project tutorial by Praditha Alwis

  • 23,310 views
  • 2 comments
  • 31 respects

3 Pins, 32 LEDs, 4 Shift Registers [74HC595]

Project tutorial by HeathenHacks

  • 16,692 views
  • 16 comments
  • 19 respects

4*4*4 LED Cube Using Arduino Embedded Prototyping Platform

Project tutorial by STEMpedia

  • 6,250 views
  • 2 comments
  • 14 respects

Interactive 4x4x4 LED cube

Project tutorial by Tong Xin Hua

  • 4,867 views
  • 0 comments
  • 1 respect

LED CUBE 4x4x4

Project showcase by MakerRobotics

  • 62,094 views
  • 9 comments
  • 95 respects
Add projectSign up / Login