Brad Martin
Published © GPL3+

TinyLight

A tiny and feature rich NeoPixel controller.

IntermediateShowcase (no instructions)10 hours283
TinyLight

Things used in this project

Hardware components

Custom PCB
Custom PCB
Some design errors, but can share files if desired.
×1
Slide Switch
Slide Switch
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
×2
ATtiny85
Microchip ATtiny85
×1
Flora RGB Neopixel LEDs- Pack of 4
Adafruit Flora RGB Neopixel LEDs- Pack of 4
×1
SparkFun Pocket AVR Programmer
×1

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

Knob

Top

Bottom

Schematics

General Schematic

I cut some traces and added jumpers for this specific build.

Code

TinyLight

Arduino
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 1
#define Pixels 14
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixels, PIN, NEO_GRB + NEO_KHZ800);

byte lux; //Neopixel
byte red = 0; //On-board LED
byte sw1 = A1; byte pot2 = A2; byte pot1 = A3; //Analog Inputs
byte color1; byte color2;
byte lastMode; byte fader; boolean faded = false; //Menus
unsigned long previousMillis = 0; long interval; unsigned long currentMillis; //Delay
float redStates[Pixels]; float blueStates[Pixels]; float greenStates[Pixels]; float fadeRate = 0.96; //Twinkle

void setup() {
  #if defined (__AVR_ATtiny85__)
     if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  pinMode(red, OUTPUT); pinMode(pot1, INPUT); pinMode(pot2, INPUT); pinMode(sw1, INPUT);

  //Copied from Twinkle
  for (uint16_t l = 0; l < Pixels; l++) {
    redStates[l] = 0;
    greenStates[l] = 0;
    blueStates[l] = 0;
  }

  strip.begin();
  strip.setBrightness(10);
  strip.show();
}

void loop() {
  byte sw = digitalRead(sw1); //Important that this is digital NOT analog
  if (sw == LOW) {
    analogWrite(red, 25); //Can adjust red lux
    settings();
  }
  if (sw == HIGH) {
    analogWrite(red, 0);
    play();
  }
}

void settings() { //Set brightness and mixer color
  lux = map(analogRead(pot1), 0, 1023, 0, 255);
  strip.setBrightness(lux);
  color2 = map(analogRead(pot2), 0, 1023, 0, 255);
  for (byte i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, Wheel(color2 & 255));
  }
  strip.show();
}

void play() {
  byte mode = map(analogRead(pot1), 0, 1023, 0, 4);
  if (mode != lastMode) {
    lastMode = mode;
    analogWrite(red, 25); //Can adjust red lux
    delay(10);
    analogWrite(red, 0);
    fader = 0; //Used in leiu of 255 step for loops in order to not use delay()
    faded = false; //Workaround for delay()
    previousMillis = 0;
  }
  if (mode == 0) { //Solid color
    color1 = map(analogRead(pot2), 0, 1023, 0, 255);
    for (byte i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(color1 & 255));
    }
    strip.show();
  }
  if (mode == 1) { //Fade between solid and mixer colors
    const uint32_t fade1 = deWheel(color1);
    const uint32_t fade2 = deWheel(color2);
    if (faded == false) {
      crossFade(fade1, fade2);
    }
    else {
      crossFade(fade2, fade1);
    }
  }
  if (mode == 2) {
    rainbow();
  }
  if (mode == 3) {
    rainbowCycle();
  }
  if (mode == 4) {
    twinkle();
  }
}

void twinkle() {
  lux = map(analogRead(pot2), 0, 1023, 0, 255);
  strip.setBrightness(lux);
  if (random(20) == 1) {
    uint16_t i = random(Pixels);
    if (redStates[i] < 1 && greenStates[i] < 1 && blueStates[i] < 1) {
      redStates[i] = random(256);
      greenStates[i] = random(256);
      blueStates[i] = random(256);
    }
  }

  for (uint16_t l = 0; l < strip.numPixels(); l++) {
    if (redStates[l] > 1 || greenStates[l] > 1 || blueStates[l] > 1) {
      strip.setPixelColor(l, redStates[l], greenStates[l], blueStates[l]);

      if (redStates[l] > 1) {
        redStates[l] = redStates[l] * fadeRate;
      } else {
        redStates[l] = 0;
      }

      if (greenStates[l] > 1) {
        greenStates[l] = greenStates[l] * fadeRate;
      } else {
        greenStates[l] = 0;
      }

      if (blueStates[l] > 1) {
        blueStates[l] = blueStates[l] * fadeRate;
      } else {
        blueStates[l] = 0;
      }

    } else {
      strip.setPixelColor(l, 0, 0, 0);
    }
  }
  strip.show();
  delay(10);
}

void rainbow() {
  interval = map(analogRead(pot2), 0, 1023, 0, 10000);
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    for (byte i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i + fader) & 255));
    }
    strip.show();
    fader++;
    if (fader == 255) {
      fader = 0;
    }
  }
}

void rainbowCycle() {
  interval = map(analogRead(pot2), 0, 1023, 0, 10000);
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    for (byte i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + fader) & 255));
    }
    strip.show();
    fader++;
    if (fader == 256 * 5) {
      fader = 0;
    }
  }
}

void crossFade(const uint32_t startColor, const uint32_t endColor) {
  interval = map(analogRead(pot2), 0, 1023, 0, 10000);
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    byte startRed = (startColor >> 16) & 0xff;
    byte startGreen = (startColor >> 8) & 0xff;
    byte startBlue = startColor & 0xff;
    byte endRed = (endColor >> 16) & 0xff;
    byte endGreen = (endColor >> 8) & 0xff;
    byte endBlue = endColor & 0xff;
    byte red = map(fader, 0, 255, startRed, endRed);
    byte green = map(fader, 0, 255, startGreen, endGreen);
    byte blue = map(fader, 0, 255, startBlue, endBlue);
    for (byte i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, red, green, blue);
    }
    strip.show();
    fader++;
    if (fader == 255) {
      fader = 0;
      faded = !faded;
    }
  }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

uint32_t deWheel (byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return Adafruit_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return Adafruit_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return Adafruit_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

Credits

Brad Martin

Brad Martin

2 projects • 2 followers
I like making gizmos

Comments