Firmware System
Lighting it up
The NS_Rainbow
library
To control the LED matrices, we use the NS_Rainbow library that
accomodates the hardware we bought. On the 8x8 display, the cells are
numbered 0-63. The NS_Rainbow
API provides the following
methods:
show()
setBrightness(int val)
setColor(int cell, int r, int g, int b)
clear()
The Squares display Squares.ino
The Squares display lights up the LEDs with square patterns accoring
to beats detected by our audio processing. The Arduino reads in from Serial
the output of our audio analysis in real time. You can refer to
this section to see how Processing
outputs to Serial. After reading in
the encoded value from Processing into the variable
pattern
, the Arduino figures out to which pattern to
light up by deducting powers of 2 from pattern
. For
example, if the third bit is on, it will light up the BIG_SQUARE
:
if (pattern >= 8) {
lightUp(BIG_SQUARE, SIZES[0]);
pattern -= 8;
}
The displays are statically set, holding the indicies of the LEDs that should be lit. For example:
int SMALL_SQUARE[12] = {18,19,20,21,26,29,34,37,42,43,44,45};
lightUp
takes in the array that dictates which cell
to light up, as well as the size of that array. It then iteratively
lights up each cell. The colors int r, g, b
are
initialized to 50
. They are changed each time through
the loop()
.
The Waves display Waves.ino
The Waves display has four faces of the cube act as one continuous scrolling text marquee. This display is independent of any audio analysis.
The full pattern is hardcoded as an 8x32 2D array as it should appear originally across all 4 faces if the faces were in a line. Each element is a 0 or 1, corresponding to if that LED should initially be off or on. For example, this is the representation of a wave pattern:
int wave[8][32] = {
{0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}
};
scrollingTextArray(int pattern[][32])
takes as an input this hard coded pattern.
The goal is to have, for each row, every column shift to the next column, with the last column wrapping around
and going into the first column, and have this shifting continue until the column reaches its original
column once again.
This scrolling is accomplished by first looping through the width of the display:
the number of columns, in this case 32. The current iteration is saved as the i
th iteration.
Every increment of this loop represents the entire display being shifted over by one column.
Within this outer loop, the current shifted over light pattern needs to be displayed onto the
LED matrices. This is accomplished by looping through the 8 rows of the entire display.
Then, within the current row, the LEDs of that row are set to display what the hardcoded pattern
has as the display for the LED i
columns over from the current column. The shifted over pattern is
displayed after which matrix each LED belongs to is calculated.
void scrollingMarqueeArrays(int pattern[][32]) {
for (int i = totalWidth - 1; i >= 0; i--) { // loop through overall width
for (int j = 0; j < matrixDimen; j++) { // loop through every row of pattern
for (int k = 0; k < totalWidth; k++) { // loop through every pixel of row
int originalCol = k - i;
if (originalCol < 0) {
originalCol = totalWidth - 1 + originalCol;
}
int v = pattern[j][originalCol]; // value from original column
... // calculate which matrix the current pixel is a part of
}
}
... // display the current pattern on the matrices
}
}
One iteration of scrollingTextArray(int pattern[][32])
scrolls through the entire display once.
Thus, scrollingTextArray(int pattern[][32])
is called within loop()
to have the display
constantly scrolling.
DIY Matrix Controldiymatrix.ino
Although we did not use the LED matrix we soldered ourselves in the final version of Cube Lite, the DIY matrix did create the need for its own firmware, as it does not work with the NS_Rainbow library. The control system reflects how the hardware is implmemented for the electrical system of the DIY matrix.
The LEDs can be individually accessed by row and column number: each row, 0 through 7, contains 8 LEDs, also indexed 0 through 7. Thus, light patterns can be encoded as an array of numbers whose binary representation corresponds to the intended display, with 0 representing off and 1 on. The indices of the array represent the rows. For example, a small square that lights up the middle four LEDs can be encoded as:
const int SQUARE_1 [] = {0,0,0,24,24,0,0,0};
24 is 00011000
in binary, so this array translates to having the middle two LEDs of the middle
two rows lit.
Sending the desired pattern to the LEDs is done through displayPatterns(int pattern[])
,
called in loop()
. This function loops through pattern
to set the rows one
at a time. For each row, shiftOut
is used to shift the bits of the pattern for that row
to the Arduino output pin that is connected to the SERIAL data input pin of the electrical circuit's
shift register.
After shifting all of the bits, a clock signal is sent to the Arduino output pin that is connected
to the CLK pin of the circuit's decade counter to increment the counter's count, grounding the next
row of LEDs so its pattern can be set.