Created
November 24, 2014 19:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Multiplexed PWM RGB Led Demo | |
// By Petri Hakkinen | |
// 24th November 2014 | |
// | |
// Arduino Uno driving a single RGB led with only one resistor. | |
// | |
// Make the following connections: | |
// * Connect Arduino pins D2,D3,D3 to anodes of a RGB led. | |
// * Connect cathode of the RGB led to 330 ohm resistor. | |
// * Connect the other end of the resistor to ground. | |
// | |
// A multiplexed PWM signal is generated by a timer interrupt routine. | |
// | |
// Uses TimerOne library, download from here: | |
// http://playground.arduino.cc/Code/Timer1 | |
#include <TimerOne.h> | |
volatile uint8_t color[3]; // R,G,B led intensities in range [0,255] | |
volatile uint8_t phase = 0; // phase of the PWM signal, counts from 0 to 255 | |
volatile uint8_t led = 0; // which led to update, counts from 0 to 2 | |
// Look up table of sin values for mega demo effect. | |
uint8_t sintab[64]; | |
// The interrupt routine that updates the states of leds. | |
void interruptRoutine() | |
{ | |
// turn all leds off | |
PORTD &= B11100011; | |
// sample pwm and turn on one led | |
if(phase < color[led]) | |
PORTD |= 1<<(led+2); | |
led = (led + 1) & 3; | |
phase++; | |
} | |
void setup() | |
{ | |
pinMode(2, OUTPUT); | |
pinMode(3, OUTPUT); | |
pinMode(4, OUTPUT); | |
// attach interrupt routine | |
Timer1.initialize(50); | |
Timer1.attachInterrupt(interruptRoutine); | |
// init sin table for mega demo effect | |
for(uint8_t i = 0; i < 64; i++) | |
sintab[i] = (uint8_t)(sin(i * M_PI * 2 / 64) * 127.0f + 128.0f); | |
} | |
void loop() | |
{ | |
const uint8_t speed = 13; | |
color[0] = 0; | |
color[1] = 0; | |
color[2] = 0; | |
// fade red | |
for(int i = 0; i < 256; i++) { | |
color[0] = i; | |
delay(speed); | |
} | |
// fade green | |
for(int i = 0; i < 256; i++) { | |
color[1] = i; | |
delay(speed); | |
} | |
// fade blue | |
for(int i = 0; i < 256; i++) { | |
color[2] = i; | |
delay(speed); | |
} | |
// mega demo effect | |
for(int i = 0; i < 500; i++) { | |
color[0] = sintab[i & 63]; | |
color[1] = sintab[(i*2 + 123) & 63]; | |
color[2] = sintab[(i*2/3 + 35) & 63]; | |
delay(speed); | |
} | |
} |
Hi! It's been awhile :) so I don't think I have any videos anymore, but it's easy to wire this up if you happen to have an Arduino Uno (or any AVR microcontroller). I don't remember there being any issues but it was more of a proof of concept, not a real world application. Color accuracy probably depends very much on the RGB LED being used. Getting accurate rendering would probably require calibrating the code with the particular LED being used. That could be done, for example, with a precomputed LUT table for each R,G,B component. The LUT would map the linear RGB values to the calibrated RGB values for the LED to get linear response. Cheers!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
HI Petri,
How did this project work out for you? Were you able to get accurate color rendering using this method? I am thinking of working on a similar project, albeit with different electronics, but using a method similar to yours where a single current source can drive all three channels (R / G / B) of a LED. Understandably, LED output would be limited to duty cycle and time division of the multiplex, but I see several advantages to this method if it works. Any input would be appreciated. If you have any video of the tests, it would be great to see. Thanks, and cheers!