I've been working on a LED coffee table , with 112 RGB led's underneath a frosted glass top. This is accomplished by multiplexing the common cathode leds. the red green and blue colors are on for roughly 2ms a piece, much faster than the human eye can perceive so it appears a solid color.
The table has two atmega's in it one to control the tlc5940 chips, and one to interface with the user and the computer. the two chips communicate via i2c.
the master board has a ftdi chip for serial comms with a computer and connection to a control panel.
the computer program is written completely with processing.
Here is a video
Sorry for the poor quality
// Coffee Table slave
#include "Wire.h"
const int column = 16; // number of columns
const int row = 7; // number of rows
const byte RedPin = 5; // digital pin to control red color
const byte GreenPin =6; // digital pin to control green color
const byte BluePin = 7; // digital pin to control blue color
byte Current_Color = 'R';
int power = 16; // allow changing the power
boolean checkreading =false;
struct led{
byte red;
byte green;
byte blue;
};
// Array to hold the led colors
led Box[][column] = {{{255,255,255},{0,16,16}, {255,255,255},{0,16,16},{255,255,255},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}},
{{255,255,255},{0,16,16}, {255,255,255},{0,16,16},{0,16,16}, {0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}},
{{255,255,255},{0,16,16}, {255,255,255},{0,16,16},{255,255,255},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}},
{{255,255,255},{255,255,255},{255,255,255},{0,16,16},{255,255,255},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}},
{{255,255,255},{0,16,16}, {255,255,255},{0,16,16},{255,255,255},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}},
{{255,255,255},{0,16,16}, {255,255,255},{0,16,16},{255,255,255},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}},
{{255,255,255},{0,16,16}, {255,255,255},{0,16,16},{255,255,255},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16},{0,16,16}}};
#include "tlc_config.h"
#include "Tlc5940.h"
void setup()
{
// Setup pins
pinMode(RedPin,OUTPUT);
pinMode(GreenPin,OUTPUT);
pinMode(BluePin,OUTPUT);
digitalWrite(RedPin,LOW);
digitalWrite(GreenPin,LOW);
digitalWrite(BluePin,LOW);
pinMode(2,OUTPUT);
// setup wire
Wire.begin(4);
Wire.onReceive(receiveEvent); // register event
// setup tlc5940
Tlc.init(0);
startXLATCallback();
Tlc.update();
// flash onboard led as well as cycling through the colors(debugging)
digitalWrite(2,HIGH);
setAll(255,0,0);
delay(1000);
digitalWrite(2,LOW);
setAll(0,255,0);
delay(1000);
digitalWrite(2,HIGH);
setAll(0,0,255);
delay(1000);
digitalWrite(2,LOW);
}
void loop()
{
if(checkreading)
savedata();
}
// save data to the led array
byte vals[column*row+2];
void savedata()
{
if(vals[0] == 'R' && vals[column*row+1] == 'R')
{
for(int i =0; i<column*row ; i++)
{
Box[i/column][15-i%column].red = vals[i+1];
}
}
else if(vals[0] == 'G' && vals[column*row+1] == 'G')
{
for(int i =0; i<column*row ; i++)
{
Box[i/column][15-i%column].green = vals[i+1];
}
}
else if(vals[0] == 'B' && vals[column*row+1] == 'B')
{
for(int i =0; i<column*row ; i++)
{
Box[i/column][15-i%column].blue = vals[i+1];
}
}
checkreading = false;
}
// load the vals buffer
void receiveEvent(int howMany)
{
int index =0;
checkreading=true;
while(Wire.available())
vals[index++]=Wire.receive();
}
// do something every 2 periods, so ~2048us
// TLC5940 multiplexing code
#define XLAT_PERIODS 2
volatile uint8_t timesCalled;
volatile void myXLATCallback()
{
if (timesCalled != 0) timesCalled--;
else
{
timesCalled = XLAT_PERIODS;
Send_data();
Tlc.update();
}
set_XLAT_interrupt(); // so this will continue to be called
}
void startXLATCallback() {
timesCalled = XLAT_PERIODS - 1;
tlc_onUpdateFinished = myXLATCallback;
myXLATCallback();
}
// update the tlc5940 chip
void Send_data()
{
if(Current_Color == 'R')
{
for(int i=0; i < column*row ; i++)
{
Tlc.set(i, Box[i/column][i%column].red*power);
}
Turn_off();
Tlc.update();
while(tlc_needXLAT);
Turn_on();
Current_Color = 'G';
}
else if(Current_Color =='G')
{
for(int i=0; i <column*row ; i++)
{
Tlc.set(i, Box[i/column][i%column].green*power);
}
Turn_off();
Tlc.update();
while(tlc_needXLAT);
Turn_on();
Current_Color = 'B';
}
else
{
for(int i=0; i < column*row ; i++)
{
Tlc.set(i, Box[i/column][i%column].blue*power);
}
Turn_off();
Tlc.update();
while(tlc_needXLAT);
Turn_on();
Current_Color = 'R';
}
}
// turn on or off the respective anode transistor
void Turn_off()
{
pinMode(RedPin,INPUT);
pinMode(GreenPin,INPUT);
pinMode(BluePin,INPUT);
digitalWrite(RedPin,LOW);
digitalWrite(GreenPin,LOW);
digitalWrite(BluePin,LOW);
delayMicroseconds(10);
}
void Turn_on()
{
//delayMicroseconds(75);
switch(Current_Color){
case 'R':
pinMode(RedPin,OUTPUT);
delayMicroseconds(10);
digitalWrite(RedPin, HIGH);
digitalWrite(GreenPin, LOW);
digitalWrite(BluePin, LOW);
break;
case 'G':
pinMode(GreenPin,OUTPUT);
delayMicroseconds(10);
digitalWrite(RedPin, LOW);
digitalWrite(GreenPin, HIGH);
digitalWrite(BluePin, LOW);
break;
case 'B':
pinMode(BluePin,OUTPUT);
delayMicroseconds(10);
digitalWrite(RedPin, LOW);
digitalWrite(GreenPin, LOW);
digitalWrite(BluePin, HIGH);
break;
}
}
// used for the initial debug
void setAll(byte sred, byte sgreen , byte sblue)
{
for(int i=0 ; i< column ; i++)
{
for(int j=0 ; j< row ; j++)
{
Box[j][i].red = sred;
Box[j][i].green = sgreen;
Box[j][i].blue = sblue;
}
}
}
If you want any more information i can provide it.