112 RGB LED Coffee Table

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.

It looks awesome! This is exactly the kind of stuff I’d like to build (my arduino is in the mail right now ::))

How long did it take you to build it?

~1year since testing began. probably could be done in 2-3 months without school.

Wow. Very impressive, Joe.

Do you have any schematics? I'm curious as to how you've multiplexed the LEDs with the TLCs.

I'm assuming you have your manual controls and the processing sketch tied to the master board, which updates the slave? The master sends a rough equivalent of the Box[] array via I2C?

http://i50.tinypic.com/33nxapf.jpg the line above the capacitor on the left is VCC at 5v the line below is gnd

yea i send almost the box array, except to speed it up i only send red green or blue at a time

the slaves only job is to listen to i2c and update the tlc5940 array. this was done to ensure minimal cpu time available

Hey Joe. First, that is awesome. Seriously well done.

Still a noob to this stuff, but I was wondering if you could talk a bit more about multiplexing the anode. I looked at your schematic but it's not fully clicking for me.

Well they are common cathode led's so they have 3 positive leads and one negative. You can control which color is lit by activating a separate transistor in my schematic. when the program begins the first red grayscale pwm information gets loaded onto the TLC5940. then the red transistor pin is driven high by the atmega, while the two other transistors are driven low. after an amount of time has passed ~ 2 ms all of the transistors are shut off and the next information is uploaded to the tlc5940, this time its the green pwm info. then after the upload has finished the green transistor is driven high. this process cycles over and over...

hope this is helpful, take a look at the send_data() function in my code

I'm truely impressed. This is by far my favourite Arduino Project I've seen.

here's a slightly better video with some voiceover http://www.youtube.com/watch?v=Tj1j1-dIX6k

that table is so cool, i want one now

That is in serious need of tetris! Great work

im hooked… i want to make one… i guess step one is getting all the leds… im making mine 18" by 42", with 3" by 3" squares… so i need 84 leds… where did you get yours?

Ebay

they probably not the best or brightest, but by far the cheapest. to get brighter you could use three separate Red green and blue led's to get a better color spread and brightness.

lol im going to go with cheap for my prototype... lol

wow, the build itself is already good, but the software takes it all :)

where do you buy a tlc5940, and what is it?

Absolutely great work. I've actually been working on a smaller version of this same idea. How many TLCs are you running? Each chip has 16 channels. And it looks like each LED consumes one channel. So 112/16 is 7 chips? My build is using 25 LEDs. The big difference is that my LEDs are common anode LEDs. So each color has its own channel on the TLC and are connected together across columns. My anodes are connected together down the rows. So I basically set my TLCs, pulse a row for 2ms or so, clear the row, set the TLC for the next row, pulse the next row, etc. The problem I'm running in to is my colors are not consistent at all. If I set my display to white, I get some white, some bluish, some greenish, some redish, some don't turn on much at all, blah blah blah. Any ideas why this might be happening? I guess switching to common cathode LEDs might be an easier fix...

I didn't realize I needed one of these until I read this post. :)

Jeremy --> http://focus.ti.com/lit/ds/symlink/tlc5940.pdf |-> http://uk.rs-online.com/web/0422283.html & only £2.16!

Paul.

The TLC5940’s have dot correction which you can set on the individual channels to correct for the varying LED colors. Don’t ask me how to do it though, im just starting with these. Also the TLC5940’s are in very short supply and most major distributors are on back order. Mouser had some TLC5941NT’s (dip package) which are essentially the same chip, however their max Ic is 80mA instead of 120mA and they don’t have the EEprom to store the dot correction so you would have to set that in the setup each time.

how did you link processing to the arduino? i guess i could just google that huh? i'll try that too. ;)