NaMaLiCS Tutorial Supplement 3, a working version for blinking lights

Since I've been discussing the code by inserting bits of tutorial between code snippets, it might be a little difficult to tell what is actually in the program.  And now that there is enough code to have a working version of NaMaLiCS, albeit with only blinking lights, I thought this would be a good time to present the code in it's entirety.

The code is written for a BrickPixel 9-LED Controller board, but it should work with ANY BrickPixel setup coming off the BrickPixel shield.  I have tested it on my system and it works.

Below is the .ino file included as text and attached is the same .ino in a zip file.  I have cleaned up the code and updated the comments.  If you have any problems, comments, questions or suggestions, please contact me.

/*
  LEGO National Mall Lighting Control System (NaMaLiCS)

  Code for controlling Brickstuff lights using the BrickPixel(tm)
     Arduino shield with BrickPixel(tm) adapter boards
  (c)2021, Bricktectonics

  Portions of this code are based on code developed by
    Brickstuff, Enthusiast Enterprises, LLC. [https://www.brickstuff.com]
    and Adafruit Industries, LLC. [https://www.adafruit.com]

  THIS CODE IS PROVIDED AS-IS WITH NO WARRANTY OR GUARANTEE OF ANY KIND

  HISTORY
  DD.MM.YYYY
  24.10.2021  Version 1.0   Created by Wayne R. Tyler

*/

// = = = = = = = = = = = = = = = = = = = = = = = = =
// NOTE: A BrickPixel pixel can refer to either an
//       individual Brickstuff light or string of
//       Brickstuff lights.
// = = = = = = = = = = = = = = = = = = = = = = = = =

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

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

// The BrickPixel Arduino shield send control commands
//  out on pins 7 & 8.  On the shield pin 7 is labeled
//  PIXEL 1 and pin 8 is labeled PIXEL 2.  The NaMaLiCS
//  testbed uses PIXEL 1.
#define PIN       7

// Minimum and maximum brightness values of a BrickPixel pixel
#define minBrightness 0
#define maxBrightness 255

/*
  The AdaFruit software is designed to work with a NeoPixel light which is
    actually a triplet of LEDs (R,G & B).  The BrickPixel hardware is
    designed to work with individual single color pixels. One Adafruit
    light is the same as three BrickPixel pixels.

  The translation between the two systems is handled by the NUMPIXELS
    definition.

  To calculate the NUMPIXELS, take the total number of BrickPixel pixels
    and divide by 3. If there is any remainder, increase NUMPIXELS by 1.

  For example, if there are 9 Brickstuff pixels attached, the calculation is
    9/3 = 3 with no remainder. So, 3 for the quotient + 0 for the remainder.
    Which means the value of NUMPIXELS is 3.

  REMEMBER: the number of BrickPixel pixels may not be the same as the
    number of Brickstuff lights, since it is possible to have a bank of
    Brickstuff lights connected to single BrickPixel pixel.
*/
#define NUMPIXELS 3

// Declare a NeoPixel object. This is used to control the BrickPixel pixels.
Adafruit_NeoPixel pixels ( NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800 );

// Argument 1 = Number of triplet groups of pixels
// Argument 2 = Arduino pin number of the BrickPixel socket being used
// Argument 3 = Pixel type flags, add together as needed (from the
//              Adafruit NeoPixel documentation):
//    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)

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

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

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

// Generally, 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() in each iteration of loop()
unsigned long currentMillis = 0;

// Will store last time a pixel was updated
//  Used in blinks and flickers on a BrickPixel 9-LED adapter
unsigned long previousPixelMillis[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};

// -------- SETUP --------------
// Setup is run once when the program is started
void setup()
{
  // Initialize the NeoPixel object (this is REQUIRED)
  pixels.begin();

  // Clear out any prior BrickPixel settings
  pixels.clear();

  // Set all pixels to minimum brightness
  for( int i=0; i<NUMPIXELS; i++ )
  {
    uint32_t color = pixels.Color(minBrightness, minBrightness, minBrightness);
    pixels.setPixelColor( i, color );
    pixels.show();
  }

  // Get start timing value used by blinking and flickering pixels
  startMillis = millis();
}

// -------- LOOP --------------

void loop() {
  // Refresh the current time each time through the loop
  //  This is used to calculate the timing needed to trigger
  //  events or the duration of an effect
  currentMillis = millis();

  // There are nine BrickPixel pixels in a BrickPixel 9-LED Controller
  //  board.  Have all nine pixels blink and the blink effect starts
  //  immediately.
  blinkPixel( 1, 0 );
  blinkPixel( 2, 0 );
  blinkPixel( 3, 0 );
  blinkPixel( 4, 0 );
  blinkPixel( 5, 0 );
  blinkPixel( 6, 0 );
  blinkPixel( 7, 0 );
  blinkPixel( 8, 0 );
  blinkPixel( 9, 0 );

  // Update the state of all the pixels.
  pixels.show();
}

// -------- BLINK EFFECT --------------

// Make a pixel blink

// Values passed into the function are:
//  1) the number of the socket in the pixel chain to which
//     a Brickstuff light or light string is attached
//  2) the amount of delay before the blink effect starts
void blinkPixel( uint8_t plugIdentifier, unsigned long delayEffectStart ) {

  // REMEMBER: BrickPixel starts counting with the number one.  Adafruit
  //  begins with the number zero.  The value of the plugIdentifier
  //  must be reduced by one before calculating the the pixelSet and
  //  pixelNumber.

  // Calculate the equivalent NeoPixel triplet the plug is in
  uint8_t pixelSetNumber = (plugIdentifier - 1) / 3;

  // Calculate the equivalent LED in the NeoPixel triplet the plug
  //  corresponds to
  uint8_t pixelNumber = (plugIdentifier - 1) % 3;

  // Get the brightness of the three pixels in the triplet
  uint32_t color = pixels.getPixelColor( pixelSetNumber );

  // Parse out the individual brightness values of the
  //  three pixels in the triplet
  uint8_t pixel01 = (uint8_t)( (color >> 16) & 0xff ),
          pixel02 = (uint8_t)( (color >> 8) & 0xff ),
          pixel03 = (uint8_t)( color & 0xff) ;

  // Check to see if enough time has elapsed to start the blink effect
  if( currentMillis - startMillis >= delayEffectStart )
  {

    // Check to see if enough time as elapsed to change the state of the
    //  pixel from on to off or off to on
    if( currentMillis - previousPixelMillis[plugIdentifier - 1] >=
      blinkInterval[(plugIdentifier - 1) % 9] )
    {

      // Change the state of the three pixels
      if( pixelNumber == 0 ) pixel01 ^= 0xff;
      if( pixelNumber == 1 ) pixel02 ^= 0xff;
      if( pixelNumber == 2 ) pixel03 ^= 0xff;

      // Update the pixel triplet with the new values
      color = pixels.Color( pixel01, pixel02, pixel03 );
      pixels.setPixelColor( pixelSetNumber, color );

      // Reset the blink counter
      previousPixelMillis[plugIdentifier - 1] +=
        (blinkInterval[(plugIdentifier - 1) % 9] - delayEffectStart);
    }
  }
}

Have fun!

-wrtyler-

Reply Oldest first
  • Oldest first
  • Newest first
  • Active threads
  • Popular
Like1 Follow
  • 1 Likes
  • 1 yr agoLast active
  • 8Views
  • 1 Following