Thursday 28 December 2017

Basic LED strip control with ATtiny

Since my printer is currently in a good shape and simply printing useful things (and some less useful), I've thrown myself at another project I've had hanging around: Getting some LED strips up for lighting in the kitchen and living room. I have some bog-standard 5050 strips, unfortunately the colors that can be set with the standard controllers are god-awful. People, there are millions of colors available on these strips, how did you manage to pick all the worst ones?

Anyway, Arduino to the rescue. I set up a little breadboard to check that it works, using some IRLB8721 transistors to control power (following the nice Adafruit tutorial). In my limited knowledge, I initially tried using trimpots to control the light, which of course had limited success. Once I set up control via the Arduino using its PWM outputs, lights were fading happily in and out. Except for the red channel, which behaved a bit weirdly. But never mind that, I moved on to my real target: Using an ATtiny85 for controller.

I have this cute little USB-stick programmer for the ATtiny from Sparkfun, and a cheap CPU sounds like the right thing for controlling a bunch of LEDs in various places. So I hooked it up, and found the lights were being somewhat odd. After swapping out the transistor for the red channel, it behaved nicely, but blue was just going on/off. I tried swapping out all the parts to no avail, blue was simple bi-level. What was up?

Back to the ATtiny descriptions, and I see that only ports 0 and 1 are PWM. Oh noes! What's a poor programmer to do? Program, of course! Turns out there is while the usual delay() function uses millisecond delays, there is a delayMicroseconds function that has finer resolution, at the cost of not doing an actual sleep. When in doubt, add more power! I spent about half an hour figuring out how to get this to work, seeing some rather strange behaviours until I realized that both digitalWrite and delayMicroseconds each take several microseconds to execute. Annoying, but surmountable.

It should be noted here that one of the swap-outs I had tried earlier was moving blue output from pin 2 to pin 3. As I was investigating how long they actually took and reading some related pages, I ran across one forum where they said the ATtiny has 3 PWM outputs. Wut? That's not what SparkFun told me! Turns out there are two PWM timers, they can't fully interconnect, so there are three PWM outputs: Pins 0, 1, and - you guessed it - 4. If I had only happened to use pin 4 instead of pin 3 when swapping out, this would have worked yesterday.

So now my little ATtiny85 is lazily fading colors in and out, next step is to make a proper PCB instead of a breadboard and also use my camera to figure out what the right values for good daylight/warm white lights are.

Morale: WTF SparkFun? Also: When testing things, keep the tests as simple as possible - my initial test program faded the different RGB channels in over each other, making it harder to understand what went wrong. Here is my final program, modified from the Adafruit tutorial code:

// color swirl! connect an RGB LED to the PWM pins as indicated
// in the #defines
// public domain, enjoy!

#define REDPIN 0
#define GREENPIN 1
#define BLUEPIN 4  // Poorly documented third PWM pin

#define FADESPEED 1  // make this higher to slow down

int blue;

void setup() {
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
}

void setrgb(int r, int g, int b) {
    analogWrite(REDPIN, r);
    analogWrite(GREENPIN, g);
    analogWrite(BLUEPIN, b);
    blue=b;
}

void blink(int times) {
  setrgb(0,0,0);
  for (int i = 0; i < times; i++) {
    delay(50);
    setrgb(50, 50, 50);
    delay(50);
    setrgb(0,0,0);
  }
}

void loop() {
  blink(2);
  // Fade red in and out
  for (int r = 0; r < 256; r++) {
    setrgb(r,0,0);
    delay(FADESPEED);
  } 
  for (int r = 255; r > 0; r--) { 
    setrgb(r,0,0);
    delay(FADESPEED);
  } 
  delay(200);
  // Fade green in and out
  for (int g = 0; g < 256; g++) { 
    setrgb(0,g,0);
    delay(FADESPEED);
  } 
  for (int g = 255; g > 0; g--) { 
    setrgb(0,g,0);
    delay(FADESPEED);
  } 
  delay(200);
  // Fade blue in and out
  for (int b = 0; b < 256; b++) { 
    setrgb(0,0,b);
    delay(FADESPEED);
  }
  for (int b = 255; b > 0; b--) { 
    setrgb(0,0,b);
    delay(FADESPEED);
  }
}

No comments:

Post a Comment