Skip to content

Instantly share code, notes, and snippets.

@petrihakkinen
Created November 24, 2014 19:30
Show Gist options
  • Save petrihakkinen/a13b4953069b85c3810a to your computer and use it in GitHub Desktop.
Save petrihakkinen/a13b4953069b85c3810a to your computer and use it in GitHub Desktop.
// 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);
}
}
@Thermaltech
Copy link

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!

@petrihakkinen
Copy link
Author

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