How to build an LED matrix display?

How to build an LED matrix display?

Published on: 31-08-2012 18:09 - Lees in het Nederlands

Please note: this article was semi-automatically translated from Dutch, translation errors may occur, links will lead to Dutch websites, you are welcome to comment in English.

[VIDEO] Is your attention always drawn by large LED screens? Impressive RGB video walls, or a modest single color scrolling marquee? I wanted to see how difficult it is to build one myself.

Mega Arduino RGB LED matrix

Let me clarify one thing: with just a single Arduino you can't build a giant RGB LED matrix that displays 16 million colours. If that's what you want you better just (buy one. It's possible to build an 8 by 8 matrix, but the 16 MHz Atmel processor on the Arduino isn't really capable of anything more.

Because I'd like to build a slighlty lager LED matrix display I skip the colors and build a 192 LED single color matrix instead. But how can you control such a large amount of LED's with just a single Arduino? The magic word is multiplexing.

Multiplexing makes use of the fact that the human eye can not perceive all this rapid change, TV images appear smooth, while in reality you look at 25 pictures per second. I use the same trick when multiplexing the matrix, there is always a row of LEDs driven at once, but it goes so fast that it seems to burn all the rows at once.

192 LED's Arduino matrix

192 LED's soldering by hand

My LED matrix contains 192 LED's, divided into 8 rows and 24 columns. I control the columns with 74HC595 shiftregisters. Shift Registers can be seen as a kind of serial to parallel converters. The single input clock you the bits serially, after which they appear on the outputs simultaneously. So how you make an Arduino output eight outputs. A very good tutorial on shiftregisters can be found at

The eight rows are not controlled by a shift register and for the following reason: each output can handle just enough power to drive an LED to the shift registers. A row consists of 24 LEDs, if you directly controls this is your Arduino or you shift register literally up in smoke! The solution consists of a component with a small stream can send a large current, a transistor. Because I need 8 transistors here it is easier to use a ULN2803 driverarray. This is one chip with 8 transistors on it, which saves you a lot of soldering!

Schematic of the Arduino LED matrix

Calculate the LED-current

You can't just connect the LED's straight to the shift registers, things will break! You have to limit the current flowing through the LED with a current limiting resistor. The value of this resistor is calculated using Ohm's law:

U = I x R

I'm using red LED's with a forwading current of 20 mA and a voltage drop of 1.8 Volts. Since we're using 5 Volts to power the matrix the resistor has to process 3.2 Volts.

R = (Us - Ul) / I

When we fill in our variables we get:

R = (5 - 1,8) / 0,02 = 160 Ohm

The required resistor is 160 ohms. By multiplexing the 8 rows the LEDs are only on 1/8th of the time, this would have allowed to compensate the resistance value if you find that the LEDs to burn low. However, keep in mind that if something goes wrong and your matrix lingers in a row, this row of LEDs can get broken.

Building an 192 LED Arduino matrix

Finally it's important to use a proper power source. You can't power all these LED's through hour USB port. Using an LM7805 and some other compontents you can build a simple voltage regulator that supplies 1 Amp.

C++ for Arduino

To send and meanwhile also do other things with your processor the display can best be controlled via a timer interrupt. The timer interrupt ensures that the display remains refreshing stable so that no hiccups in the image occur. The Timer1 library helps you using these timerinterrupts.

The display is driven row by row by means of multiplexing. Because this should be visible to the human eye much faster I could not cope with Arduino's standard digitalWrite() function. This feature has about 54 clock cycles required to forward a port, which is too slow. Therefore, I send the complete ports directly with C++, a port write happened in about three clock cycles, so 18 times faster!

Finishing the last 8x8 matrix before the complete 192 LED matrix is completed

The code below is the write screen routine is invoked. The timer interrupt For each row, the 24 bits from the buffer into the shift registers are clocked, and then the outputs of the shift registers is activated as well as the associated driving transistor. The micro seconds delay () ensures that the LEDs can also glow, visible brightness value influenced how bright the display seems to be the spectator. This may of course not be too large because then the refresh rate of the screen is too low.

void writeScreen() {
  for (row = 0; row <= 7; row++) {
    for (col = 0; col <= 23; col++) {
      PORTB &= B00; // clock and data low
      PORTB |= buffer[row][col]; // set databit from buffer
      PORTB |= B10; // clockpulse high to clock in databit
    PORTB |= B100; // latch high to show outputs
    PORTB &= B011; // latch low
    PORTD = 1 << row; // enable rowdriver
    delayMicroseconds(brightness); // show outputs
    PORTD = 0; // disable rowdriver

Outside the writescreen routine you obviously have all sorts of features that require the appropriate bits in the buffer to display. Example, letters or a clock on the display I use the following code to display. 4 digits of five columns wide

void UberKlok() {
  klok[0] = hour()/10;
  klok[1] = hour()%10;
  klok[2] = minute()/10;
  klok[3] = minute()%10;

  for (x = 0; x <= 7; x++) {
    for (karakter = 0; karakter <= 1; karakter++) {
      for (y = 0; y <= 4; y++) {
        buffer[x][karakter * 6 + y] = bitRead(pgm_read_byte_near(&cijfers_uber[klok[karakter]][y]), x);
      buffer[x][karakter * 6 + 5] = 0;

    buffer[x][12] = 0; // space between chars

    for (karakter = 2; karakter <= 3; karakter++) {
      for (y = 0; y <= 4; y++) {
        buffer[x][karakter * 6 + y + 1] = bitRead(pgm_read_byte_near(&cijfers_uber[klok[karakter]][y]), x);
      buffer[x][karakter * 6 + 6] = 0;

The numerical characters are saved in the Arduino memory using the pgmspace library. The "realtime" clock comes from the Time library. Using the module operator (%) you can split the minutes into two digits.

The following YouTube video demonstrates the capabilities of the Arduino ledmatrix.

Watch on Youtube

High on my wish list is the ability to fill the buffer directly from your computer via USB to date is not yet succeeded. Any idea how I can get that done? Let me know in the comments below!

4 comments on this article »

More articles like this one