Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 |
I wanted to make a small LED cube that I could leave on my desk displaying animations. I also wanted to control the brightness so that at night time I can turn it down.
The cube ends up having Negative on one side and Positive on the other.
I found this Pandora box which happened to be about the right size for the cube. The wires go through the lid where I drilled some small holes.
I am still working on a way to make the brightness control more responsive. At the moment when you twist the knob you have to wait for the current animation to finish, then it will read the knob and set the new brightness and start the next animation. If it tries to read the knob during the animation it makes the LEDs flicker. Still trying to find a way to improve this.
Also I want to add a push button to manually select which animation to play. I'm sure there is a very simple way to do it, I just haven't found a way that works yet.
The design and code I got from here, so credit to Doug Domke thanks. https://www.hackster.io/doug-domke/another-5x5x5-rgb-led-cube-82fdd8#team
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#define PIN 10 // data pin
#define POTENTIOMETER_PIN A0 // brightness knob
//int // set brightness here 0-256 with 10 for easy on eyes
int potentiometerValue = analogRead(POTENTIOMETER_PIN);
int brightness = map(potentiometerValue, 0, 1023, 0, 255);
//#define BUTTON_PIN 7
//int buttonState = 0; // Holds the readout from the button
//int counter = 3; // Holds the number as we cycle through them on the display
//bool offed = true; // To check if the button has been released after pushing
// (otherwise it will get pushed tens of times a second)
//int numberOfModes = 6;
// create instance of neo_matrix configured for this display
Adafruit_NeoMatrix cube = Adafruit_NeoMatrix(5, 5, 5, 1, PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
NEO_RGB + NEO_KHZ800);
// Color Management
// these are colors that can be specified by GetColor() routine
// calling this routine from 1 to 42 gives you a 42 step rainbow pallette
#define White 43
#define Black 0
#define Red 1
#define Orange 4
#define Yellow 9
#define Green 15
#define Aqua 20
#define Blue 29
#define Purple 34
uint32_t mycolor;
const byte color [44][3] PROGMEM = { // the color pallette table
{0, 0, 0}, //Black
{7, 0, 0}, {7, 1, 0}, {6, 1, 0}, {6, 2, 0}, {5, 2, 0}, {5, 3, 0}, {4, 3, 0}, {4, 4, 0}, {3, 4, 0}, {3, 5, 0}, {2, 5, 0}, {2, 6, 0}, {1, 6, 0}, {1, 7, 0}, // Red to Green
{0, 7, 0}, {0, 7, 1}, {0, 6, 1}, {0, 6, 2}, {0, 5, 2}, {0, 5, 3}, {0, 4, 3}, {0, 4, 4}, {0, 3, 4}, {0, 3, 5}, {0, 2, 5}, {0, 2, 6}, {0, 1, 6}, {0, 1, 7}, // Green to Blue
{0, 0, 7}, {1, 0, 7}, {1, 0, 6}, {2, 0, 6}, {2, 0, 5}, {3, 0, 5}, {3, 0, 4}, {4, 0, 4}, {4, 0, 3}, {5, 0, 3}, {5, 0, 2}, {6, 0, 2}, {6, 0, 1}, {7, 0, 1}, // Blue to Red
{7, 7, 7} // White
};
byte myloc[3] = {2, 2, 2};
const byte cubetPath [50][3] PROGMEM = { // cubet path
{0, 0, 3}, {0, 1, 3}, {0, 2, 3}, {0, 3, 3}, {1, 3, 3}, {2, 3, 3}, {3, 3, 3}, {3, 2, 3}, {3, 1, 3}, {3, 0, 3}, {2, 0, 3}, {1, 0, 3}, {0, 0, 3},
{0, 2, 0}, {0, 2, 1}, {0, 2, 2}, {0, 2, 3}, {1, 2, 3}, {2, 2, 3}, {3, 2, 3}, {3, 2, 2}, {3, 2, 1}, {3, 2, 0}, {2, 2, 0}, {1, 2, 0}, {0, 2, 0},
{0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {3, 0, 2}, {3, 1, 2}, {3, 2, 2}, {3, 3, 2}, {2, 3, 2}, {1, 3, 2}, {0, 3, 2}, {0, 2, 2}, {0, 1, 2}, {0, 0, 2},
{2, 0, 1}, {1, 0, 1}, {0, 1, 1}, {0, 2, 1}, {1, 3, 1}, {2, 3, 1}, {3, 1, 1}, {3, 2, 1}, {2, 0, 1}
};
void setup() {
cube.begin();
// Serial.begin(9600);
cube.setTextWrap(false);
cube.setBrightness(30);
// Button stuff
//pinMode(BUTTON_PIN, INPUT_PULLUP);
// TIMER 1 Setup for interrupt frequency 67 Hz = 15 ms refresh rate
cli(); // stop interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 67.00167504187604 Hz increments
OCR1A = 29849; // = 16000000 / (8 * 67.00167504187604) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 8 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
delay(7000);
}
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#define PIN 10 // data pin
#define POTENTIOMETER_PIN A0 // brightness knob
//int // set brightness here 0-256 with 10 for easy on eyes
int potentiometerValue = analogRead(POTENTIOMETER_PIN);
int brightness = map(potentiometerValue, 0, 1023, 0, 255);
//#define BUTTON_PIN 7
//int buttonState = 0; // Holds the readout from the button
//int counter = 3; // Holds the number as we cycle through them on the display
//bool offed = true; // To check if the button has been released after pushing
// (otherwise it will get pushed tens of times a second)
//int numberOfModes = 6;
// create instance of neo_matrix configured for this display
Adafruit_NeoMatrix cube = Adafruit_NeoMatrix(5, 5, 5, 1, PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
NEO_RGB + NEO_KHZ800);
// Color Management
// these are colors that can be specified by GetColor() routine
// calling this routine from 1 to 42 gives you a 42 step rainbow pallette
#define White 43
#define Black 0
#define Red 1
#define Orange 4
#define Yellow 9
#define Green 15
#define Aqua 20
#define Blue 29
#define Purple 34
uint32_t mycolor;
const byte color [44][3] PROGMEM = { // the color pallette table
{0, 0, 0}, //Black
{7, 0, 0}, {7, 1, 0}, {6, 1, 0}, {6, 2, 0}, {5, 2, 0}, {5, 3, 0}, {4, 3, 0}, {4, 4, 0}, {3, 4, 0}, {3, 5, 0}, {2, 5, 0}, {2, 6, 0}, {1, 6, 0}, {1, 7, 0}, // Red to Green
{0, 7, 0}, {0, 7, 1}, {0, 6, 1}, {0, 6, 2}, {0, 5, 2}, {0, 5, 3}, {0, 4, 3}, {0, 4, 4}, {0, 3, 4}, {0, 3, 5}, {0, 2, 5}, {0, 2, 6}, {0, 1, 6}, {0, 1, 7}, // Green to Blue
{0, 0, 7}, {1, 0, 7}, {1, 0, 6}, {2, 0, 6}, {2, 0, 5}, {3, 0, 5}, {3, 0, 4}, {4, 0, 4}, {4, 0, 3}, {5, 0, 3}, {5, 0, 2}, {6, 0, 2}, {6, 0, 1}, {7, 0, 1}, // Blue to Red
{7, 7, 7} // White
};
byte myloc[3] = {2, 2, 2};
const byte cubetPath [50][3] PROGMEM = { // cubet path
{0, 0, 3}, {0, 1, 3}, {0, 2, 3}, {0, 3, 3}, {1, 3, 3}, {2, 3, 3}, {3, 3, 3}, {3, 2, 3}, {3, 1, 3}, {3, 0, 3}, {2, 0, 3}, {1, 0, 3}, {0, 0, 3},
{0, 2, 0}, {0, 2, 1}, {0, 2, 2}, {0, 2, 3}, {1, 2, 3}, {2, 2, 3}, {3, 2, 3}, {3, 2, 2}, {3, 2, 1}, {3, 2, 0}, {2, 2, 0}, {1, 2, 0}, {0, 2, 0},
{0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {3, 0, 2}, {3, 1, 2}, {3, 2, 2}, {3, 3, 2}, {2, 3, 2}, {1, 3, 2}, {0, 3, 2}, {0, 2, 2}, {0, 1, 2}, {0, 0, 2},
{2, 0, 1}, {1, 0, 1}, {0, 1, 1}, {0, 2, 1}, {1, 3, 1}, {2, 3, 1}, {3, 1, 1}, {3, 2, 1}, {2, 0, 1}
};
void setup() {
cube.begin();
// Serial.begin(9600);
cube.setTextWrap(false);
cube.setBrightness(30);
// Button stuff
//pinMode(BUTTON_PIN, INPUT_PULLUP);
// TIMER 1 Setup for interrupt frequency 67 Hz = 15 ms refresh rate
cli(); // stop interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 67.00167504187604 Hz increments
OCR1A = 29849; // = 16000000 / (8 * 67.00167504187604) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 8 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
delay(7000);
}
// Sets intensity of all three colors of one LED to generate a specified color
void LED(int x, int y, int z, uint32_t mycolor2){
if (z%2) cube.drawPixel((z+1)*5-x-1, 4-y, GetColor(mycolor2));
else cube.drawPixel(x+(z*5),y, GetColor(mycolor2));
}
void clearCube(){
cube.fill(Black);
}
// This routine generates 42 different colors around the color wheel using our 3 bit BAM
uint32_t GetColor(int thecolor) {
byte myred = 36*pgm_read_byte_near(&color[thecolor][0]);
byte mygreen = 36* pgm_read_byte_near(&color[thecolor][1]);
byte myblue = 36*pgm_read_byte_near(&color[thecolor][2]);
return cube.Color(myred,mygreen, myblue);
}
// show cube for a multiples of 10 ms before clearing it.
void showCube(int mytime) {
delay(20 * mytime);
clearCube();
}
void pause() { // pause between animations
clearCube();
delay(500);
}
// get a random color from color definitions
uint32_t randomColor() {
uint32_t mycolor;
switch (1 + random(7)) {
case 1:
mycolor = Red;
return mycolor;
break;
case 2:
mycolor = Green;
return mycolor;
break;
case 3:
mycolor = Blue;
return mycolor;
break;
case 4:
mycolor = Yellow;
return mycolor;
break;
case 5:
mycolor = Aqua;
return mycolor;
break;
case 6:
mycolor = Purple;
return mycolor;
break;
case 7:
mycolor = White;
return mycolor;
break;
}
}
// the next 3 subroutines are used by swings, but otherwise serve no real purpose
void redON(int x, int y, int z) {
LED(x,y,z,Red);
}
void greenON(int x, int y, int z) {
LED(x,y,z,Green);
}
void blueON(int x, int y, int z) {
LED(x,y,z,Blue);
}
// ******************************* Start of Refresh Timer Interrupt ************************
// this cube doesn't requre refresh, so an ISR really isn't necessary. It only serves to avoid
// typing a lot of .show()s in the various animations.
ISR(TIMER1_COMPA_vect) {
cube.show();
}
Comments
Please log in or sign up to comment.