Before you Start

If this is your first time using Pro Trinket, pause for a sec and head over to the Pro Trinket Intro guide.  That will walk you through getting your Arduino IDE set up and the Adafruit boards installed.  Once you can upload sample code to the Pro Trinket and everything appears to be working, come on back here.

FastLED Library

You will also need to install the FastLED library in Arduino (Sketch > Include Library > Manage Libraries...)

Upload Code

This code is based on Mark Miller's sample beat8 code for the FastLED library.  It creates a moving pixel with a comet tail that moves in a sinwave pattern around the neopixel strip.

When I press the button, the lights cycle through all the runes for a few seconds and then stop in a random spot, lighting up one (or sometimes two) of the layers of acrylic and highlighting a specific rune or "bound" rune combination (if it lands on a corner). 

The lit pixels can be controlled for speed, brightness, hue, and fade rate (via the fading "comet tail" effect).  The sinwave code "beatsin8" effectively mixes all these variables so that each button press gives me a totally unique experience -- one press, the pixels might cycle bright and fast, the next they cycle dim and slow, change colors quickly or subtly, or any of a vast number of combinations.

This makes for a feeling that the device is "listening" to the user and giving each button press due consideration before deciding on a message to relay. 

Download: file
// Viking Rune Artifact
// by Erin St. Blaine
// for Adafruit Industries
// Based on code by Marc Miller, March 2017

//  Full tutorial at https://learn.adafruit.com/glowing-viking-rune-artifact/introduction
//  Pro Trinket: https://www.adafruit.com/products/2000
//  Skinny Neopixels: https://www.adafruit.com/products/2970
//***************************************************************

#include "FastLED.h"
#define LED_TYPE WS2812
#define LED_PIN     3
#define BUTTON_PIN  4
#define BUTTON_LIGHT_PIN 5
#define NUM_LEDS    24
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

uint8_t moveSpeed;// Random number for movement speed - higher number cycles faster 
uint8_t fadeRate;  // Use lower value to give a fading tail.
const uint16_t startDelay = 100;  // Number of milliseconds before re-start
int analogSeedPin = 9;  // Any un-used analog pin.  Used for generating seed for random16.
int analogSeedPinB = 10;  // Any un-used analog pin.  Used for generating seed for random16.
bool oldState = HIGH;
static boolean frozen = true;  // [Initially set true!]
uint8_t gHue = 0;  // Used to cycle through rainbow.

uint8_t BRIGHTNESS = 200;
unsigned long timeDelay = startDelay;
unsigned long freezeTime = 10000000;  // Just something really large to prevent triggering on startup


//---------------------------------------------------------------
void setup() 
{
  Serial.begin(115200);  // Allows serial monitor output (check baud rate)
  //delay(3000);  // 3 second delay
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(BUTTON_LIGHT_PIN, OUTPUT); 
  digitalWrite(BUTTON_LIGHT_PIN, HIGH);       // turn on pullup resistors// set pin to output
}


//---------------------------------------------------------------
void loop() 
{
  EVERY_N_MILLISECONDS(random(1,8)) { gHue++;}  // Cycle through the rainbow randomly
  
  // Get current button state.
  bool newState = digitalRead(BUTTON_PIN);
// Check if state changed from high to low (button press).
  if (newState == LOW && oldState == HIGH) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if (newState == LOW) {

     frozen=false;  //unfreeze and start animation
     
     }
    }
    

  // Set the last button state to the old state.
  oldState = newState;
  timeDelay = startDelay;
  

  if (frozen) {  // [FROZEN]
    
    // This if statement delays the start of the moving pixel.
    if (millis() > timeDelay) {
      frozen = true;  // toggle frozen variable
      uint16_t seed = random16_get_seed();
      seed = seed + analogRead(analogSeedPin) + analogRead(analogSeedPinB);  // create a random seed
      random16_add_entropy(seed);
      seed = random16_get_seed();
        freezeTime = random16(2000,6000);  // set range of cycle times here
        moveSpeed= 5;     //movement speed variable
        BRIGHTNESS = random(200,255);  //randomize brightness
        fadeRate = 20;  // change this to change tail length
      Serial.print("freezeTime = "); Serial.print(freezeTime/1000.0); Serial.println(" seconds.");
      freezeTime = millis() + freezeTime;
    }
  }//end_of_FROZEN

  
  if (!frozen) {  // [IS NOT FROZEN]
    beat8_tail();  // Subroutine to move the pixel!
  }

  FastLED.show();  // Display the pixels.


  // Check to see if the random freeze time has been reached.
  // If true then stop the animation.
  if (millis() > freezeTime){
    frozen = true;  // toggle frozen variable
    timeDelay = millis() + startDelay;  // set new start time
    freezeTime = millis() + 1000000;  // To prevent re-triggering
  }

}//end main loop


//===============================================================
void beat8_tail()
{
  
  EVERY_N_MILLISECONDS( 3 ) {
   fadeToBlackBy( leds, NUM_LEDS, fadeRate);  // Fade out pixels.
   }
  uint16_t pos = beatsin8(moveSpeed, 100, 255) % NUM_LEDS;  // modulo the position to be within NUM_LEDS
  leds[pos] = CHSV( gHue, 255, BRIGHTNESS);

}

To change the way your LEDs act, play with the variables and random numbers in these lines of code:

Download: file
 freezeTime = random16(2000,6000);  // set range of cycle times here
        moveSpeed= 5;     //movement speed variable
        BRIGHTNESS = random(200,255);  //randomize brightness
        fadeRate = 20;  // change this to change tail length
  • freezeTime How long the animation runs before freezing.  Right now it's set to a random time between 2 and 6 seconds.
  • moveSpeed make the dot move faster or slower
  • BRIGHTNESS - I've randomized a bit to add interest and texture
  • fadeRate this controls the length of the tail, or, how many LEDs light up at once.
This guide was first published on Apr 18, 2017. It was last updated on Apr 18, 2017. This page (Code) was last updated on Sep 01, 2019.