NaMaLiCS Tutorial Part 3, B_GLOBALS

I'm going to go through the NaMaLiCS program tab by tab.  That means some information introduced up front won't be useful and perhaps not even understandable right away.  But that information will show up again in a later discussion which WILL make it clear as to why it exists and how it's used.

With that caveat, let's take a look at the Globals tab.  It starts with a note about nomenclature.

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// NOTE: I refer to both individual pico lights and strings of pico lights as pixels
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

This means when I call the function blinkPixel, it makes a pico light or a string of pico lights blink.  And the variable pixelNumber refers to a specific pico light or pico light string.

The first thing the program needs to do is load the Adafruit NeoPixel library.

// -------- LIBRARIES --------------
#include <Adafruit_NeoPixel.h>

There are two connectors on the BrickPixel Arduino shield that can be used to control the pixels in the lighting system.  This define statement indicates which is being used. 

// -------- CONSTANTS (won't change) --------------

// BrickPixel controls are on Pin 7 & 8
//   Pin 7 = PIXEL 1, Pin 8 = PIXEL 2
#define PIN       7

It's important to understand this next definition as it's key to using the Adafruit NeoPixel library with Brickstuff's BrickPixel system.

The single Adafruit NeoPixel LED actually contains three LEDs (a red, a green and a blue) inside one casing.  When using the library in its default configuration it wants to address three LEDs at a time.

A Brickstuff Pico light is a single LED.  So there needs to be a way to translate the native NeoPixel code into a form usable by the Brickstuff BrickPixel hardware.

To make this work, there are two concepts to understand.  A set of three pixels (Pico lights) is the same as one NeoPixel LED, so we will be working with pixelSets.  Within that pixelSet, there are three pixels; pixel01, pixel02 and pixel03.  To be able to manipulate a single pixel you will need to specify which pixelSet it is in and which pixel within that set it is.

But here's the twist.  The Adafruit NeoPixel library is zero-based. The BrickPixel hardware is one-based.  The mismatch is a surefire gotcha when programming BrickPixel hardware.  If the program you just finished isn't working, this is one of the first things to check!

The equivalents here are pixelSet 0 (zero) contains pixels 1, 2 and 3.  pixelSet 1 contains pixels 4, 5 and 6.  pixelSet 2 has pixels 7, 8 and 9.


When defining NUMPIXELS it is important to do the math correctly so that all the pixels you have wired up will be accessible.

// The AdaFruit software is designed to work with triplets of lights (R,G & B)
//   The Brickstuff hardware is designed to work with individual single color
//   lights (what I refer to as pixels). So, one Adafruit light is the same as
//   three Brickstuff lights, or three pixels.
// This is handled by the NUMPIXELS definition.
// To calculate the NUMPIXELS, take the total number of Brickstuff lights that
//   are connected and divide by 3. If there is any remainder, increase
//   NUMPIXELS by 1.
// In this example there are 6 Brickstuff lights attached.
//   6/3 = 2 with no remainder. So, 2 for the quotient + 0 for the remainder.
#define NUMPIXELS 3

// Declare a NeoPixel object. This is used to control the individual lights.
Adafruit_NeoPixel pixels ( NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800 );
// Argument 1 = Number of triplet groups of lights
// Argument 2 = Arduino pin number of the BrickPixel socket being used
// Argument 3 = Pixel type flags, add together as needed:
//    NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//    NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//    NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
//    NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/ WS2812 LEDs)
//    NEO_KHZ800  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)

// Minimum and maximum brightness values a pixel can have
#define minBrightness 0
#define maxBrightness 255

millis() returns the number of milliseconds that have passed since the currently running program started.  NOTE: millis() returns an unsigned long value, so if you are doing calculations with it make sure all variables used in the arithmetic are also unsigned longs, otherwise you will get errors.

// You should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store

// Stores the value of millis() when the program is started
unsigned long startMillis = 0;

// Interval at which to blink in milliseconds
// Random Prime Numbers so the blinks aren't synchronous
const unsigned long blinkInterval[] = {710, 371, 563, 281, 809, 151, 640, 173, 440};

// Number of millisecs that pixels are on when blinking
//  500 milliseconds = 1/2 second
const unsigned long blinkDuration = 500;

The NaMaLiCS control system has two phases.  The first is the initial light up portion.  How do the lights turn on?  Toggle on as if connect to a lightswitch?  FadeOn, like stadium or arena lights?  Do the lights flicker when turning on?  Do the lights even illuminate, or is the lightbulb dead?

The second part is what I call the maintenance portion.  After the lights are on, are there any changes to their illumination?  Do they flicker occasionally?  Do they dim and brighten?  Do they just burn out?

The loopCounter is a temporary approach to separating the startup portion from the maintenance portion.  During the initial light up phase, you don't want to be executing the maintenance code.  And after the startup code has finished, you don't want it to run again.

// A counter is used in loop() to get the pixels into their initial
//  illumination state (fadeOn, flickerOn, toggleOn, etc.), then allows
//  the program to skip over the initialization portion of the code
//  when the pixels are in their maintenance state
// It would be better if a flag were setup to signal when the last pixel
//  in the light chain is finished initializing.
// The number 250 is arbitrary for now.
uint8_t loopCounter = 250;

When I started working on NaMaLiCS, I was using the delay() function for getting the triggering of effects to happen at certain time.  However, when a delay is being run, the program can do nothing else, so I couldn't have two different lights with different lighting effects running simultaneously.

I had to change to what is called a non-blocking approach.  The Arduino is a single core CPU, so it cannot do true multitasking.  However, by using millis() and checking the time differences in a lighting effect, you can get the appearance of a multitasking system.

This set of variables is part of the bookkeeping necessary to run a non-blocking program.

// -------- VARIABLES (will change) --------------

// Stores the value of millis() in each iteration of loop()
unsigned long currentMillis = 0;

// Used by the flickerOn effect so the pixels don't flicker forever
uint8_t incrementCounter = 0;

// Stores the last time the pixel was updated
//    Used in blink and flicker effects
//  Currently set up for a BrickPixel 9-LED controller
unsigned long previousPixelMillis[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};

Flicking lights need some extra bookkeeping to determine flicker intervals and durations.

// Values used to in the flickering effect
unsigned long flickerMillis01 = 0;
unsigned long flickerMillis02 = 0;

// Values used to turn flickering effect on or off
bool flickerSwitch01 = false;
bool flickerSwitch02 = false;

// Values used to create two different flicker rates
unsigned long flickerInterval01 = 4000;
unsigned long flickerInterval02 = 2500;

And there you have it.  The basic pieces needed to program lighting effects.

Next, we'll take a look at what goes into setting up the starting conditions to run the NaMaLiCS program.


Reply Oldest first
  • Oldest first
  • Newest first
  • Active threads
  • Popular
Like Follow
  • 3 days agoLast active
  • 6Views
  • 1 Following