Christmas 2016 Ornament – Using Arduino

I created a Christmas ornament using an Arduino Uno and an 8×5 NeoPixel Shield.

In short it,

  • Displays one of seven messages randomly
  • Displays a set of bars that animates – Based on this thread
  • Displays a star that moves and cycles colours – Based on this tutorial

The code is, essentially, C and REALLY easy to develop, and the APIs from AdaFruit make this wicked fast to get code up and running quickly.  The language used for Arduino actually is based on Processing, but also accepts C and C++.

The Libraries used are:

  • AdaFruit GFX Library
  • AdaFruit NeoMatrix
  • AdaFruit NeoPixel

Here is the code:

#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
 
// MATRIX DECLARATION:
// Parameter 1 = width of NeoPixel matrix
// Parameter 2 = height of matrix
// Parameter 3 = pin number (most are valid)
// Parameter 4 = matrix layout flags, add together as needed:
// NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
// Position of the FIRST LED in the matrix; pick two, e.g.
// NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
// NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs are arranged in horizontal
// rows or in vertical columns, respectively; pick one or the other.
// NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns proceed
// in the same order, or alternate lines reverse direction; pick one.
// See example below for these values in action.
// Parameter 5 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

#define PIN 6
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(6, 8, PIN,
 NEO_MATRIX_BOTTOM + NEO_MATRIX_LEFT +
 NEO_MATRIX_COLUMNS + NEO_MATRIX_PROGRESSIVE,
 NEO_GRB + NEO_KHZ800);


// Global Variables
// matrix_x, y used to drive the size of the LED matrix
// text_pass used to change text colours after each pass
// starpos used to position the star when switching to different colours
// starpos_incdec is used to move the star back and forth based on the boundaries of the matrix
// rand_messages is used to randmize the messge that is shown
// text_colours is an array of colours to use for the text, star_rgb used for star color values, star_colour used to drive the actual colour of the star
int matrix_x = matrix.width();
int matrix_y = matrix.height();
int text_pass = 0;
int starpos = 0;
boolean starpos_incdec = 1;
int rand_messages = 0;
unsigned int star_rgb[3] = {255,255,255};
uint16_t star_colour = matrix.Color(star_rgb[0], star_rgb[1], star_rgb[2]);
const uint16_t text_colours[] = {matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(255, 255, 0),matrix.Color(0, 0, 255), matrix.Color(255, 0, 255), matrix.Color(0, 255, 255), matrix.Color(255, 255, 255)};

 // Merry Christmas Message 
String myMessages[]={"Merry Christmas", "You've been naughty", "Krampus is here", "Ho Ho Ho!", "Happy Holidays","Meet me under the mistletoe", "Home for the Holidays"}; 
int myMessagesSizes[]={-98,-120,-98,-80,-95,-170,-140};
// Code
void setup() 
{
 Serial.begin(9600);
 matrix.begin();
 matrix.setTextWrap(false);
 matrix.setBrightness(6);
 matrix.setTextColor(text_colours[0]);
}

void update_star()
{
 // Future code fix - Make dynamic based on matrix_x and matrix_y
 // In short, if the star hits the Y boundaries, move back
 if (starpos+4 == 7) { starpos_incdec = 0; } 
 if (starpos == 0) { starpos_incdec = 1; } 

 // Clear screen, draw star
 matrix.fillScreen(0);
 star_colour = matrix.Color(star_rgb[1], star_rgb[0], star_rgb[2]);
 matrix.drawLine(0, starpos, 4, starpos+4, star_colour);
 matrix.drawLine(0, starpos+4, 4, starpos, star_colour);
 matrix.drawLine(0, starpos+2, 4, starpos+2, star_colour);
 matrix.drawLine(2, starpos, 2, starpos+4, star_colour); 
 matrix.show(); 
 delay(1);
}

void color_morph(unsigned int* value, int get_brighter)
{
 // Updates the colour through updating the refence. 
 // Get brighter flag increments/decrements
 for (int i = 0; i < 255; i++)
 {
 if (get_brighter)
 (*value)--;
 else
 (*value)++;

 update_star();
 }
 if (starpos_incdec) { starpos++; } else { starpos--; } 
}

void rowColorWipe(uint32_t c1, uint32_t c2, uint32_t c3, uint16_t wait) 
{
 // Borrowed code to draw green, white and red bars
 // Clear screen
 matrix.fillScreen(0);

 // Draw the bars
 for(int j=0; j<2; j++) {
 for(int q=0; q<6; q++){
 for(int y=0; y <= matrix.height() + 10; y=y+6) {
 matrix.drawLine(0, y+q-11, 5, y+q-6, c3);
 matrix.drawLine(0, y+q-10, 5, y+q-5, c1);
 matrix.drawLine(0, y+q-9, 5, y+q-4, c1);
 matrix.drawLine(0, y+q-8, 5, y+q-3, c3);
 matrix.drawLine(0, y+q-7, 5, y+q-2, c2);
 matrix.drawLine(0, y+q-6, 5, y+q-1, c2);
 }
 matrix.show();
 delay(wait);
 }
 }
}

void loop()
{
 // The main Arduino loop
 // Displays the christmas message, then the Christmas Wrapping bars, and then the star animation
 // Easier to have the message scroll here rather than using a separate method/function
 
 // Clears screen and sets message
 matrix.fillScreen(0);
 matrix.setCursor(matrix_x, 0); 
 matrix.print(myMessages[rand_messages]);
 // matrix.print(F("Merry Christmas")); // If using a single message

 // Enter this only if the message has been fully displayed. It's displayed by moving the cursor
 if(--matrix_x <= myMessagesSizes[rand_messages]) {
 // Reset message scroll
 matrix_x = matrix.width();
 matrix.setCursor(matrix_x, 0);

 // Christmas Wrapping bars
 rowColorWipe(matrix.Color(255, 0, 0), matrix.Color(255, 255, 255), matrix.Color(0, 255, 0), 500);

 // Cycle through the star colours
 color_morph(&star_rgb[0], 1); // transition to red
 color_morph(&star_rgb[1], 1); // transition to yellow
 color_morph(&star_rgb[0], 0); // transition to green 
 color_morph(&star_rgb[2], 1); // transition to aqua 
 color_morph(&star_rgb[0], 1); // transition to white
 color_morph(&star_rgb[1], 0); // transition to violet
 color_morph(&star_rgb[0], 0); // transition to blue
 color_morph(&star_rgb[2], 0); // transition to black (all off)
 
 if(++text_pass >= 8) text_pass = 0;
 matrix.setTextColor(text_colours[text_pass]);
 rand_messages = random(0,7); // Random number between 0 and 7 (n-1)
 } 
 matrix.show();
 delay(100); 
}