Learned a lot and a lot to learn. 6X6X6 LED Light Cube

Intro:

For my senior project, I have built a 6X6X6 LED Light cube that is run off the Arduino Uno. I have built and designed everything myself though not without some errors. The way you see it in the videos is the final project for the class. The class is now over but I can still take this thing further and want to learn and understand the coding side even more. I will admit right now that coding is by far the hardest part of this project for me and it doesn’t come naturally for me. My professor has taught and assisted me so far.

The design:

The overview idea is to run the 216 LEDs off an Arduino Uno and use 595 chips to multiply the 12 outputs into 42 outputs(36 for the pillars and 6 for the layers). There are 6 595 chips in use that each controls their own verticle plain. And each layer goes straight back to the Arduino.

Big Mistake #1:

When I started this project I got the idea from some guy off the internet. He had a ‘How to’ tutorial video on how to build one. I followed it and built the LED cube part before even starting on anything else. When it was prototyping the circuit board design on breadboards, I found out that this dude had a ‘fatal error’/design flaw in the tutorial which was that all the LEDs were soldered backwards, which as most yall know doesn’t work. Silly me. Determined to not rebuild the entire cube again I redesigned my board(working out many other kinks).

Solution:

Inverters. I inverted each output from the 595 chips.

Big Mistake #2:

I then built my first custom board. I then ran into some issues where the outputs would turn on when told to but when turned off they would either stay on, delay-off or behave perfectly. After many hours of headbanging against the wall, we discovered that each input to the 04 inverters must be grounded. If not grounded they will act as mini resistors and latch on randomly for durations of time.

Solution:

Use 10K resistors on each 04 inverter input.

Where you guys come in:

My code:

The code that I am using for the majority of the time is just turning on and offsets of LEDs for periods of time in specific orders. But there are limits to the shapes and figures that I can create with this method. For example, if I wanted to create an “o” vertically in a 3X3 manner with the center LED off I could program it but it would display as just a 3X3 verticle block. Because the pillar used to turn on the top center and bottom center LEDs and the middle plain used to turn on the middle left and right LEDs would conflict to turn on the very center LED. So the goal code is to turn on each layer individually with the desired LEDs and then switch to the next layer. By doing so you no longer are limited to the figures that can be created on the Cube.

The first program situation:

In this program, I have created multiple functions each exploring a different concept. All the code is done the ‘simple way’ in program0() and program1(). program2() uses the animated method(aka Draw() in my program). The code works and the figure appears as anticipated but whenever I use the Draw() function the LEDs immediately below any LED turned on are also on but about half as bright. So any shape created has like this ghosting effect only on the LEDs directly below the activated ones. I don’t understand what is causing this and how(if possible) to resolve it. My best guess is that the previous layer isn’t turning off quick enough and getting caught up in the next layer?!

Code will be attached as Working_code

The second program situation:

I am trying to create a raining effect program. The idea is to have the top layer completely on and one by one the LEDs fall ‘randomly’ to the bottom and repeat when all 36 have fallen. In the following code, I have all the 36 LEDs in the top layer ‘randomly’ turning off. After each LED turns off there is the following code that simulates the falling rain. The issue is that during the simulating of the falling rain the entire top layer of remaining on LEDs turn off. Then they turn on for 50ms between each raindrop then off again. It is very nauseating and what would be the best way to keep the top layer on during the raindrop animating??

Code will be attached as Rain

Any pointers, advice, and corrections are greatly appreciated. And Thanks in advance.

PCB Layout V2.png

Rain.ino (18.2 KB)

Working_Code.ms14.ino (11.7 KB)

I took a look at your rain sketch and it could benefit from using arrays. Also, your layers() code relies on there being a direct mapping of layer 1-6 to pin 2-7 which could easily break things if you ever need to change pins.

Your button is wired up in the schematic such that you need it to be INPUT_PULLUP so it reads HIGH when not pressed. It currently reads random values since it is not connected to anything when not pressed.

I’m not sure about the flashing layers, probably something to do with enabling/disabling the latches which may cause the outputs to float or change.

Here’s a cleaned up version

const int latchPin = 8;
const int clockPin = 12;

const byte CUBE_SIZE = 6;
const int dataPins[CUBE_SIZE] = { A0, A1, A2, A3, A4, A5 };
const int levelPins[CUBE_SIZE] = { 2, 3, 4, 5, 6, 7 };

const int button = 10;
bool buttonState = 0;

int mode = 0;
bool modechange = false;
int counter = 0;

byte CubeData[6][6];
// (left, depth, layer)
//bool LED(6,6,6);

void setup()
{
  Serial.begin(19200);

  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

  for ( int i = 0; i < CUBE_SIZE; i++ ) {
    pinMode(dataPins[i], OUTPUT);
    pinMode(levelPins[i], OUTPUT);
  }

  pinMode(button, INPUT_PULLUP);
}


void loop() {
  rainTop1();

}

byte data[CUBE_SIZE];

void rainTop1()
{
  setData( 63, 63, 63, 63, 63, 63 );

  setLayer(0);
  shiftOutAll(data); //0
  delay(50);
  data[1] = 61;
  shiftOutAll(data); //1
  delay(50);

  setLayer(1);
  setData( 0, 2, 0, 0, 0, 0 );
  shiftOutAll(data);
  delay(75);
  setLayer(2);
  shiftOutAll(data);
  delay(75);
  setLayer(3);
  shiftOutAll(data);
  delay(75);
  setLayer(4);
  shiftOutAll(data);
  delay(75);
  setLayer(5);
  shiftOutAll(data);
  delay(75);
  setLayer(0);

  setData(63, 61, 63, 47, 63, 63);
  shiftOutAll(data);
  delay(50);
  setLayer(1);
  setData( 0, 0, 0, 16, 0, 0);
  shiftOutAll(data);
  delay(75);
  setLayer(2);
  shiftOutAll(data);
  delay(75);
  setLayer(3);
  shiftOutAll(data);
  delay(75);
  setLayer(4);
  shiftOutAll(data);
  delay(75);
  setLayer(5);
  shiftOutAll(data);
  delay(75);
  setLayer(0);

  setData(55, 61, 63, 47, 63, 63);
  shiftOutAll(data);
  delay(50);
  setLayer(1);
  setData(8, 0, 0, 0, 0, 0);
  shiftOutAll(data);
  delay(75);
  setLayer(2);
  shiftOutAll(data);
  delay(75);
  setLayer(3);
  shiftOutAll(data);
  delay(75);
  setLayer(4);
  shiftOutAll(data);
  delay(75);
  setLayer(5);
  shiftOutAll(data);
  delay(75);
  setLayer(0);

  setData(55, 29, 63, 47, 63, 61);
  shiftOutAll(data);
  delay(50);
  setLayer(1);
  setData(0, 0, 0, 0, 0, 2);
  shiftOutAll(data);
  delay(75);
  setLayer(2);
  shiftOutAll(data);
  delay(75);
  setLayer(3);
  shiftOutAll(data);
  delay(75);
  setLayer(4);
  shiftOutAll(data);
  delay(75);
  setLayer(5);
  shiftOutAll(data);
  delay(75);
  setLayer(0);
}

void setData(byte d0, byte d1, byte d2, byte d3, byte d4, byte d5)
{
  data[0] = d0;
  data[1] = d1;
  data[2] = d2;
  data[3] = d3;
  data[4] = d4;
  data[5] = d5;
}

void shiftOutAll(byte myData[CUBE_SIZE])
{
  digitalWrite(latchPin, LOW);

  for (int i = 7; i >= 0; i--)  {
    digitalWrite(clockPin, LOW);

    for (int idx = 0; idx < CUBE_SIZE; idx++) {
      if ( myData[idx] & (1 << i)) {
        digitalWrite(dataPins[idx], HIGH);
      }
      else {
        digitalWrite(dataPins[idx], LOW);
      }
    }
    digitalWrite(clockPin, HIGH);
  }

  digitalWrite(clockPin, LOW);
  digitalWrite(latchPin, HIGH);
}

void setLayer(int myLayer)
{
  for (int i = 0; i < CUBE_SIZE; i++) {
    if (myLayer == i) {
      digitalWrite(levelPins[i], HIGH);
    }
    else {
      digitalWrite(levelPins[i], LOW);
    }
  }
}

Thanks, I appreciate it. So that explains why the button was acting strange sometimes.

blh64:
Also, your layers() code relies on there being a direct mapping of layer 1-6 to pin 2-7 which could easily break things if you ever need to change pins.

My thinking is that I believe that this is the simplest way and redefining the pin numbers isn't difficult. Or is there a better way?

Isn't my shiftOutAll using arrays?

And the LEDs on the top layer still turn off when animating the falling raindrop.

The software is generally the hardest part for these cubes and, imho, not generally done particularly well. I designed a library for LED cubes that is relatively easy to port to other cube types - it was designed to be hardware independent - that has been ported to a few cubes now and I know works well. Once you have changed the 3-4 functions used to drive your cube design all the other example code will work 'out of the box'.

If you are interested you can find it at GitHub - MajicDesigns/MD_Cubo: LED Cube Library (hardware independent) or install it using the IDE library manager (MD_Cubo).

There are also a couple of blog articles that cover design aspects:

There is no word “alot” in English.

There is a word "allot; it is a verb, meaning to apportion or divide.

You have a lot to learn.

Ya English is not my specialty.