Go Down

Topic: Building a Word-Clock with 13x8 Grid of LEDs - How to controll the LEDs?! (Read 3960 times) previous topic - next topic

Tia2014

Hi guys,

i´m planning to build a Word-Clock with a 13x8 grid underneath, but i´m a bit stuck with the decision how to light up the whole thing :(
The words are lit by a single LED under each letter (maybe a led per 2 letters is also enough…). The clock should be controlled by via an Arduino UNO (respectively a standalone ATmega328) and the time comes from a small I2C-realtime-clock-module.
Brightness control is only needed for all LEDs at once, not individually.

At first i thought about simply building groups with the LEDs for each word (21 words have to be swiched on or off according to the current time) and using MOSFETs to switch the groups on or off. (longest word is 7 letters long and every LED consumes 20ma at 3,1V). Also I/O-Expanders (or ShiftRegisters) would be added to have enough output pins.
Problem here would be that i can´t control the brightness (only the overall brightness has to be adjusted), but I stumbled upon "ShiftPWM" which would be a Software-PWM libary with which the brightness could be adjusted (for example when using 74HC595 shift registers to get enough output-pins).

My second thought was to multiplex the 13x8 matrix by using 8 logic level MOSFETs to switch Vcc onto the 8 rows and a TLC5940NT to connect the columns to ground (this would also eliminate the need of resistors at the LEDs, because the TLC5940NT is a constant-current sink LED driver). Then every LED could be controlled individually.

- What would you suggest?

I already checked a few logic-level MOSFETs:






NameTypeCaseUDSUGS(th)Ic25RDS(on)td(on/off)
IRLR 110power-MOSFET n-channel logic levelTO-252100 V1 V4,3 A0,54 Ohm9,3 ns
IRLU 024Npower-MOSFET n-channel logic levelTO-251AA55 V1 V17 A0,065 Ohm7,1 ns
IRLIZ 44Npower-MOSFET n-channel logic levelTO-220-Fullpak55 V1 V30 A0,022 Ohm11 ns
IRLU 8721power-MOSFET n-channel logic levelTO-251AA30 V1,35 V65 A0,0084 Ohm8,8 ns

- Would all of them work for this task? Are there better ones you would suggest?`

I also got other stuff already laying around (or are already ordered):
10x MAX7219 (should arrive next week)
5x MCP23017
5x TLC5940NT
25x 74HC595 (should also arrive next week)
and also LEDs, Resistors (for the LEDs and also the right ones to set the current of the TLC5940NT), various capacitors, ...


Would be great if you could give me a few hints or suggestions on how to proceed with this project  ;)


Thank you in advance and best regards,
Matthias

fungus

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

PaulRB

Hi Matthias,

As fungus says, 2 x max7219 will take care of all your leds in the simplest way, if you truly need to individually control 13 × 8 leds. But you also say you only need to control lighting 21 words up with groups of leds. This would be much simpler. You could do that with no extra chips, just your mega328 and a few ordinary transistors. You can control overall brightness in this way with some careful sketch writing.

Paul


For the rtc i would recommend ds3231, its more accurate than the more common ds1307.

Depending what other inputs/outputs you need, you may only need an ATtiny84 or even an ATtiny85 instead of a full Uno to run your clock.

Paul

Tia2014

Thanks for the quick reply :)

I already got a DS1307 RTC here, but maybe I order a couple DS3231 and replace the DS1307 some time later (They are also quite cheap...) - thanks for the tipp.

I just checked the MAX7219 a bit more in detail. So a good way would be splitting the 13x8 grid into a 7x8 and a 6x8 grid - all anodes connect to pins SegDP -> SegG and the cathodes to Dig0 -> Dig7.
Also needed: 1x 10µF capacitor, 1x 100nF capacitor (to supress noise through the power-supply line) and 1x 24kOhm resistor (to limit the flowing current to 20ma at 3.0 V (The LEDs are running at 3.1V according to the datasheet, but i think 3.0V and the 24kOhm instead of the mentioned 24,5kOhm should be also fine?! Or better the next higher value?).
- Am i missing something?
- Which library would you suggest to control the MAX7219 via the Arduino?
(I just downloaded the https://code.google.com/p/arudino-maxmatrix-library/ and will try this one as soon as my MAX7219s arrive...)

I also got 3x ATtiny85 and 3x ATtiny84 here - the ATtiny85 with its 5 output pins could be a bit "tiny" if I already have 3 pins to the MAX7219, but I still have to check the I2C RTC clock and how that works... The ATtiny84 should have enough pins if - maybe - I run out of pins with the ATtiny85... The first test-version will be controlled by the Arduino anyways and then i try to port it to something smaller ;)

Paul__B


Which library would you suggest to control the MAX7219 via the Arduino?

I suggest - none.

Just write the code to control it.

Here is a little example of library-free code:
Code: [Select]
/* Loop scanner demonstration
Code for max 7219 from maxim, reduced & optimised for using multiple 7219 cascaded.
______________________________________

General notes:

- if using only one max7219, then use maxSingle function to control
the module --- maxSingle(register (1-8), column (0-255))

- if using more then one max7219, and all should work the same, use maxAll
function --- maxAll(register (1-8), collum (0-255))

- if using more than one max7219 and want to change something on one module only,
then use maxOne function
--- maxOne(module you want to control [1=first], register [1-8], column [0-255])

During initiation, be sure to send every part to every max7219 and then upload it.
For example, if you have five max7219's, you have to send the scanLimit 5 times
before you load it, otherwise not every max7219 will get the data. the (fixed)
variable maxInUse keeps track of this, just tell it how many max7219 you are using.
*/

int dataIn = 2;            // "DIN" on module
int load = 3;              // "CS" on module
int clock = 4;             // "CLK" on module
const int ledPin =  13;    // LED pin number

int maxInUse = 1;          // set how many MAX7219's used
int ledState = LOW;        // initialise the LED

int e = 0;                 // just a varialble

// define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;


void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask) {           // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    } else {
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

// maxSingle is the "easy" function to use for a single max7219
void maxSingle( byte reg, byte col) {   
  digitalWrite(load, LOW);  // begin     
  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data   
  digitalWrite(load,HIGH);
}

// initialize all MAX7219's
void maxAll( byte reg, byte col) {
  int c = 0;
  digitalWrite(load, LOW);
  for ( c =1; c<= maxInUse; c++) {
  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load,HIGH);
}

// for adressing different MAX7219's while cascaded
void maxOne(byte maxNr, byte reg, byte col) {   
  int c = 0;
  digitalWrite(load, LOW);  // begin     
  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);             // no operation
    putByte(0);             // no operation
  }

  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data

  for ( c = maxNr-1; c >= 1; c--) {
    putByte(0);             // no operation
    putByte(0);             // no operation
  }
  digitalWrite(load,HIGH);
}

void putCol( byte colno, byte coldat) {
// Interprets colno as (zero ref) index in combined array
    byte t;
    t = colno >> 3;
    byte u;
    u = colno & 0x07;
    maxOne(t+1, u+1, coldat);
}


void dispon() {
maxAll(max7219_reg_shutdown, 0x01);               // Display on


void dispoff() {
maxAll(max7219_reg_shutdown, 0x00);              // Display off


byte irow = 0;          // Row index
byte icol = 0;          // Column index
byte pattern;           // bit mask
byte lcol;              // left border
byte rcol;              // right border
byte trow;              // top row marker
byte brow;              // bottom row marker

int s_vert;             // Vertical switch
int s_horz;             // Horizontal switch

void worker () {

  if (pattern == 0) pattern = trow;            // pattern must be set
  if (s_vert != 0) {
    if (s_vert == -1) {                     // moving upward
      pattern = pattern >> 1;
      if (pattern == trow) {                   // hit the top
        s_vert = 0; s_horz = 1;
      }
    } else {
      pattern = pattern << 1;               // moving downward
      if (pattern == brow) {                // hit the bottom
        s_vert = 0; s_horz = -1;
      }
    }
    putCol(icol,pattern);              // Show the column.
    return;
  }

  if (s_horz != 0) {
    putCol(icol,0);                    // blank previous column.
    if (s_horz == -1) {                     // moving left
      icol--;
      if (icol == lcol) {                      // hit the side
        s_horz = 0; s_vert = -1;
      }
    } else {
      icol++;                               // moving right
      if (icol == rcol) {                      // hit the side
        s_horz = 0; s_vert = 1;
      }
    }
    putCol(icol,pattern);              // Show the column.
  }
}
 
// the follow variable is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 60;           // interval at which to step (milliseconds)
long previousMillis = 0;      // will store last time LED was updated


void setup () {

  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
  pinMode(ledPin, OUTPUT);     

  //Serial begin(9600);
  digitalWrite(13, HIGH); 

//initiation of the max 7219
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  maxAll(max7219_reg_scanLimit, 0x07);   // all columns in use   
  maxAll(max7219_reg_decodeMode, 0x00);  // using a LED matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  for (e=1; e<=8; e++) {                 // empty registers, turn all LEDs off
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x08 & 0x0f);  // middle argument is intensity value
                                               // range: 0x00 to 0x0f
                                                 
  pattern = 0;
  s_vert = 0;
  s_horz = 1;

// define edges of loop
  lcol = 1;              // left border
  rcol = 6;              // right border
  trow = 0x02;           // top row marker
  brow = 0x40;           // bottom row marker     
     


void loop () {

  unsigned long currentMillis = millis();

// Active waiting for next event
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) { ledState = HIGH;  } else { ledState = LOW; }
    // Timed process:
   
    worker();

    // set the LED according to ledState:
    digitalWrite(ledPin, ledState);
    }

}

PaulRB

Another option for you to think over. This one is dead easy, and you can not only control brightness but colour too!

WS2812B LED strips. You can buy strips with 60 or 144 leds per metre. They can be cut between each led and are sticky-taped backed. Cut an appropriate length (1~6leds) for each word and stick them down to the board behind each word. Then wire them together in  a daisy chain (3 wires, 5V, ground and data). No extra driver chips required!

bperrybap

There are a few existing designs out there, Have you looked at them?:
http://www.instructables.com/id/Sleek-word-clock/
http://www.instructables.com/id/Sleek-word-clock/
http://forum.arduino.cc/index.php?topic=118338.0 (different design using 16x8)

I'm in the process of building out one of these as well.
I am VERY picky with the way the lighting as I want all the letters to
have nice even lighting with no dark spots or dim edges.
In my view the most difficult part of this project is the mechanical design.
To me, this is actually much more difficult than how to control the LEDs.
Much of what you use may actually depend on how much space you have.
In my case I'm using an IKEA shadow box and you don't have much room for
components. Compounding that is that depending on the LEDs you use
you have to provided enough space between the LED and the front of the
display surface to allow the LED beam to widen to fully light up the letter.
If the LEDs are not well aligned or there is not enough distance and the letters
will not be lit up evenly, even if you use onion skin as a diffuser.

Space for components get even tighter if you use any sort of light guides
to help control the light between letters. If say you are going down a path
of being able to individually control the LEDs to be able use the leds as
a moving LED matrix sign as well.

I looked at MANY different ways of handling it.
You can use diffused LEDs to provide a diffused light which means
that alignment issues are reduced and you get nice beautiful even lighting;
however, diffused LEDs consume considerably more power than
water clear LEDs that can focus the beam on the surface.
With water clear LEDs, there are "normal" leds which have a bout 20 degrees of viewing
angle and then there are "wide angle" leds which give a much broader beam given
the distance to the viewing surface.
Any of these can work, depending on your mechanical design.
I will say that the light emitted by the diffused LEDs isn't really bright enough
when multiplexing - regardless if whether using say a 7219 or a HT16K33.

In terms of actually driving the LEDS, there are several approaches but again
it can come down to physical space.

There is the "drive the words" non multiplexing approach which you drive all the LEDs for a given word.
This is approach is what was used in two of the links provided above.


If you use something like a 7219, you will need two of them and then you end up
having to wire up the rows twice since each 7219 controls the rows separately.
There are several libraries out there and in most cases code size is  not an issue
unless using a smaller part, so I'd recommend using a library vs rolling your own.

A Teensy++ can be used to drive the LEDs  in a "drive the words" approach
rather using shift registers since it has so many pins. This can save space which
might be needed.
If you don't have much else to do in your s/w you could do the multiplexing in s/w
to provide full independent LED control. In this approach you would use 21 pins
and need transistors on the 8 rows, and potentially 13 transistors on the columns depending
on how much current you want to send to the LEDs.

What I ended settling on was this module from Adafruit:
http://www.adafruit.com/products/1427
This is VERY small and can drive all the LEDs with a minimal amount of wiring.
I opted for water clear wide angle "straw hat"  LEDs - the diffused LEDs just didn't have the brightness
I wanted when they were multiplexed with this chip.
The beauty of this that not only can it drive all the LEDs,  it uses i2c which is already needed
for the RTC chip so it essentially uses no additional pins and it has mounting holes.
This module can be used for either the 13x8 or 16x8 clock.
I ordered a pair of them from GadgetCat because Adafruit charges too much
for shipping: http://www.gadgetcat.com/product/adafruit-16x8-led-matrix-driver-backpack-ht16k33-breakout/



Originally I was going to use a Teensy++ with a few transistors, but since
I'm also looking at doing speech in s/w on the micro-controller for announcements
with either huffman or LPC encoded data, the processor gets very busy and I didn't
want any flickering during the announcements. For this reason I eliminated s/w multiplexing.
"drive the words" with diffused LEDs would have worked but I wanted (needed) something
smaller than the Teensy++ and that is why I went a Teensy 2.0 and the AdaFruit board.
I'm also putting in an WWBV atomic clock receiver along the top above the LEDs and so my
space is very limited.
I have two areas of 6"x0.75"x0.75" total working area for components so space is
at a premium.

--- bill


CrossRoads

MAX7219 with high brightness LEDs will be very bright, even when multiplexed.
I offer this little daisychainable board that makes it easy to connect the 64 LEDs up individually
http://www.crossroadsfencing.com/BobuinoRev17/ about 1/2 down, there's a short video of it working.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Tia2014


I suggest - none.

Maybe I will try this approach... Still waiting for the MAX7219 to arrive -.-


WS2812B LED

I have a few of them here, but due to the fact that i don´t need any colors, that would be just a wastage - but they are really easy to control!


I'm in the process of building out one of these as well.

Thanks for the insight in your building process - I also checked a few projects on instructables, but just to get some inspiration, I don´t want to rebuild someones work... I am also using one of the IKEA Ribba photo-boxes as a housing :P

I decided to go with two MAX7219 and started building the first matrix yesterday. I used white SMD LEDs - they are very inexpensive, small (hard to work with at first, but after a few LEDs you get used to the small size), are really bright (almost to bright - have to be dimmed I think) and have a good viewing angle.
I aligned the LEDs on a printed pattern so that the sit right underneath the letters.

Here are a few pictures of the process:

Put some solder on all anodes and cathodes.


Pre-built rows.


I put transparent shrinking-tube on the spots where the row and column lines meet to avoid shorts.





...I hope I will be able to start with the second matrix today.

Best regards,
Matthias


Go Up