# Tutorial – LM3915 Logarithmic Dot/Bar Display Driver IC

Introduction

This is the second of three articles that will examine the LM391x series of LED driver ICs. The first covered the LM3914, this will cover the LM3915 and the LM3916 will follow. The goal of these is to have you using the parts in a small amount of time and experiment with your driver ICs, from which point you can research further into their theory and application.

Although these parts have been around for many years, the LM3915 isn’t used that much however for the sake of completeness we’re writing the tutorial. The LM3915 offers a simple way to display a logarithmic voltage level using one or more groups of ten LEDs with a minimum of fuss. If you’re wanting to make a VU meter, you should use the LM3916 which we will cover in the final instalment of this trilogy.

Instead of having each LED represent a voltage level as with the LM3914, each LED connected to the LM3915 represents a 3 dB (decibel) change in the power level of the signal. For more on decibels, check out Wikipedia.

To display these power level changes we’ll run through a couple of examples that you can use in your own projects and hopefully give you some ideas for the future. Originally by National Semiconductor, the LM391X series is now handled by Texas Instruments.

Getting Started

You will need the LM3915 data sheet, so please download that and keep it as a reference. First – back to basics. The LM3915 controls ten LEDs. It controls the current through the LEDs with the use of only one resistor, and the LEDs can appear in a bar graph or single ‘dot’ when in use. The LM3915 contains a ten-stage voltage divider, each stage when reached will illuminate the matching LED (and those below it in level meter mode).

Let’s consider the most basic of examples (from page two of the data sheet) – a simple logarithmic display of voltage between 0 and 10V:

After building the circuit you can connect a signal to measure via pin 5, and the GND to pin 2. We’ve built the circuit exactly as above on some stripboard for demonstration purposes, with the only difference being the use of an 8.2kΩ resistor for R2:

To show this in action we use a signal of varying AC voltage – a sine wave at around 2 kHz. In the following video, you can see the comparison of the signal’s voltage against the LEDs being illuminated, and you will see the logarithmic voltage increase represented by the LEDs:

We used the bar display mode for the voltage increase, and the dot display mode for the voltage decrease. Did you notice that during the voltage decrease, the LEDs below the maximum level being displayed were dim?

As the signal’s voltage was varying very quickly, the change in the LED’s location is a blur due to the speed of change. In the video below, we’ve slowed the frequency right down but kept the same maximum voltage.

Well that was a lot of fun, and gives you an idea of what is possible with the LM3915.

Displaying weaker signals

In non-theoretical situations your input signal won’t conveniently be between 0 and 10 V. For example the line level on audio equipment can vary between 1 and 3V peak to peak. For example, here’s a random DSO image from measuring the headphone output on my computer whilst playing some typical music:

Although it’s an AC signal we’ll treat it as DC for simplicity. So to display this random low DC voltage signal we’ll reduce the range of the display to 0~3V DC. This is done using  the same method as with the LM3914 – with maths and different resistors.

Consider the following formulae:

As you can see the LED current (Iled) is simple, however we’ll need to solve for R1 and R2 with the first formula to get our required Vref of 3V. For our example circuit I use 2.2kΩ for R2 which gives a value of 1.8kΩ for R1. However putting those values in the ILED formula gives a pretty low current for the LEDs, about 8.3 mA.

Live and learn – so spend time experimenting with values so you can match the required Vref and ILED.

Nevertheless in this video below we have the Vref of 3V and some music in from the computer as a sample source of low-voltage DC. This is not a VU meter! Wait for the LM3916 article to do that.

Again due to the rapid rate of change of the voltage, there is the blue between the maximum level at the time and 0V.

Chaining multiple LM3915s

This is covered well in the data sheet, so read it for more on using two LM3915s. Plus there are some great example circuits in the data sheet, for example the 100W audio power meter on page 26 and the vibration meter (using a piezo) on page 18.

Conclusion

As always we hope you found this useful. Don’t forget to stay tuned for the final instalment about the LM3916.

This post is brought to you by pmdway.com – everything for makers and electronics enthusiasts, with free delivery worldwide.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on twitter @tronixstuff.

# Tutorial – Arduino and the MAX7219 LED Display Driver IC

Sooner or later Arduino enthusiasts and beginners alike will come across the MAX7219 IC. And for good reason, it’s a simple and somewhat inexpensive method of controlling 64 LEDs in either matrix or numeric display form. Furthermore they can be chained together to control two or more units for even more LEDs. Overall – they’re a lot of fun and can also be quite useful, so let’s get started.

Here’s an example of a MAX7219 and another IC which is a functional equivalent, the AS1107 from Austria Microsystems. You might not see the AS1107 around much, but it can be cheaper – so don’t be afraid to use that instead:

At first glance you may think that it takes a lot of real estate, but it saves some as well. As mentioned earlier, the MAX7219 can completely control 64 individual LEDs – including maintaining equal brightness, and allowing you to adjust the brightness of the LEDs either with hardware or software (or both). It can refresh the LEDs at around 800 Hz, so no more flickering, uneven LED displays.

You can even switch the display off for power saving mode, and still send it data while it is off. And another good thing – when powered up, it keeps the LEDs off, so no wacky displays for the first seconds of operation. For more technical information, here is the data sheet: MAX7219.pdf. Now to put it to work for us – we’ll demonstrate using one or more 8 x 8 LED matrix displays, as well as 8 digits of 7-segment LED numbers.

Before continuing, download and install the LedControl Arduino library as it is essential for using the MAX7219.

Controlling LED matrix displays with the MAX7219

First of all, let’s examine the hardware side of things. Here is the pinout diagram for the MAX7219:

The MAX7219 drives eight LEDs at a time, and by rapidly switching banks of eight your eyes don’t see the changes. Wiring up a matrix is very simple – if you have a common matrix with the following schematic:

connect the MAX7219 pins labelled DP, A~F to the row pins respectively, and the MAX7219 pins labelled DIG0~7 to the column pins respectively. A total example circuit with the above matrix  is as follows:

The circuit is quite straight forward, except we have a resistor between 5V and MAX7219 pin 18. The MAX7219 is a constant-current LED driver, and the value of the resistor is used to set the current flow to the LEDs. Have a look at table eleven on page eleven of the data sheet:

You’ll need to know the voltage and forward current for your LED matrix or numeric display, then match the value on the table. E.g. if you have a 2V 20 mA LED, your resistor value will be 28kΩ (the values are in kΩ). Finally, the MAX7219 serial in, load and clock pins will go to Arduino digital pins which are specified in the sketch. We’ll get to that in the moment, but before that let’s return to the matrix modules.

In the last few months there has been a proliferation of inexpensive kits that contain a MAX7219 or equivalent, and an LED matrix. These are great for experimenting with and can save you a lot of work – some examples of which are shown below:

Now for the sketch. You need the following two lines at the beginning of the sketch:

```#include "LedControl.h"
LedControl lc=LedControl(12,11,10,1);```

The first pulls in the library, and the second line sets up an instance to control. The four parameters are as follows:

1. the digital pin connected to pin 1 of the MAX7219 (“data in”)
2. the digital pin connected to pin 13 of the MAX7219 (“CLK or clock”)
3. the digital pin connected to pin 12 of the MAX7219 (“LOAD”)
4. The number of MAX7219s connected.

If you have more than one MAX7219, connect the DOUT (“data out”) pin of the first MAX7219 to pin 1 of the second, and so on. However the CLK and LOAD pins are all connected in parallel and then back to the Arduino.

Next, two more vital functions that you’d normally put in void setup():

```lc.shutdown(0,false);
lc.setIntensity(0,8);```

The first line above turns the LEDs connected to the MAX7219 on. If you set TRUE, you can send data to the MAX7219 but the LEDs will stay off. The second line adjusts the brightness of the LEDs in sixteen stages. For both of those functions (and all others from the LedControl) the first parameter is the number of the MAX7219 connected. If you have one, the parameter is zero… for two MAX7219s, it’s 1 and so on.

Finally, to turn an individual LED in the matrix on or off, use:

`lc.setLed(0,col,row,true);`

which turns on an LED positioned at col, row connected to MAX7219 #1. Change TRUE to FALSE to turn it off. These functions are demonstrated in the following sketch:

```#include "LedControl.h" //  need the library
LedControl lc=LedControl(12,11,10,1); //

// pin 12 is connected to the MAX7219 pin 1
// pin 11 is connected to the CLK pin 13
// pin 10 is connected to LOAD pin 12
// 1 as we are only using 1 MAX7219

void setup()
{
// the zero refers to the MAX7219 number, it is zero for 1 chip
lc.shutdown(0,false);// turn off power saving, enables display
lc.setIntensity(0,8);// sets brightness (0~15 possible values)
lc.clearDisplay(0);// clear screen
}
void loop()
{
for (int row=0; row<8; row++)
{
for (int col=0; col<8; col++)
{
lc.setLed(0,col,row,true); // turns on LED at col, row
delay(25);
}
}

for (int row=0; row<8; row++)
{
for (int col=0; col<8; col++)
{
lc.setLed(0,col,row,false); // turns off LED at col, row
delay(25);
}
}
}```

And a quick video of the results:

How about controlling two MAX7219s? Or more? The hardware modifications are easy – connect the serial data out pin from your first MAX7219 to the data in pin on the second (and so on), and the LOAD and CLOCK pins from the first MAX7219 connect to the second (and so on). You will of course still need the 5V, GND, resistor, capacitors etc. for the second and subsequent MAX7219.

You will also need to make a few changes in your sketch. The first is to tell it how many MAX7219s you’re using in the following line:

`LedControl lc=LedControl(12,11,10,X);`

by replacing X with the quantity. Then whenever you’re using  a MAX7219 function, replace the (previously used) zero with the number of the MAX7219 you wish to address. They are numbered from zero upwards, with the MAX7219 directly connected to the Arduino as unit zero, then one etc. To demonstrate this, we replicate the previous example but with two MAX7219s:

```#include "LedControl.h" //  need the library
LedControl lc=LedControl(12,11,10,2); //

// pin 12 is connected to the MAX7219 pin 1
// pin 11 is connected to the CLK pin 13
// pin 10 is connected to LOAD pin 12
// 1 as we are only using 1 MAX7219

void setup()
{
lc.shutdown(0,false);// turn off power saving, enables display
lc.setIntensity(0,8);// sets brightness (0~15 possible values)
lc.clearDisplay(0);// clear screen

lc.shutdown(1,false);// turn off power saving, enables display
lc.setIntensity(1,8);// sets brightness (0~15 possible values)
lc.clearDisplay(1);// clear screen
}

void loop()
{
for (int row=0; row<8; row++)
{
for (int col=0; col<8; col++)
{
lc.setLed(0,col,row,true); // turns on LED at col, row
lc.setLed(1,col,row,false); // turns on LED at col, row
delay(25);
}
}

for (int row=0; row<8; row++)
{
for (int col=0; col<8; col++)
{
lc.setLed(0,col,row,false); // turns off LED at col, row
lc.setLed(1,col,row,true); // turns on LED at col, row
delay(25);
}
}
}```

And again, a quick demonstration:

Another fun use of the MAX7219 and LED matrices is to display scrolling text. For the case of simplicity we’ll use the LedControl library and the two LED matrix modules from the previous examples.

First our example sketch – it is quite long however most of this is due to defining the characters for each letter of the alphabet and so on. We’ll explain it at the other end!

```// based on an orginal sketch by Arduino forum member "danigom"
// http://forum.arduino.cc/index.php?action=profile;u=188950

#include <avr/pgmspace.h>
#include <LedControl.h>

const int numDevices = 2;      // number of MAX7219s used
const long scrollDelay = 75;   // adjust scrolling speed

unsigned long bufferLong [14] = {0};

LedControl lc=LedControl(12,11,10,numDevices);

prog_uchar scrollText[] PROGMEM ={
"  THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG 1234567890 the quick brown fox jumped over the lazy dog   "};

void setup(){
for (int x=0; x<numDevices; x++){
lc.shutdown(x,false);       //The MAX72XX is in power-saving mode on startup
lc.setIntensity(x,8);       // Set the brightness to default value
lc.clearDisplay(x);         // and clear the display
}
}

void loop(){
scrollMessage(scrollText);
scrollFont();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

prog_uchar font5x7 [] PROGMEM = {      //Numeric Font Matrix (Arranged as 7x font data + 1x kerning data)
B00000000,	//Space (Char 0x20)
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
6,

B10000000,	//!
B10000000,
B10000000,
B10000000,
B00000000,
B00000000,
B10000000,
2,

B10100000,	//"
B10100000,
B10100000,
B00000000,
B00000000,
B00000000,
B00000000,
4,

B01010000,	//#
B01010000,
B11111000,
B01010000,
B11111000,
B01010000,
B01010000,
6,

B00100000,	//\$
B01111000,
B10100000,
B01110000,
B00101000,
B11110000,
B00100000,
6,

B11000000,	//%
B11001000,
B00010000,
B00100000,
B01000000,
B10011000,
B00011000,
6,

B01100000,	//&
B10010000,
B10100000,
B01000000,
B10101000,
B10010000,
B01101000,
6,

B11000000,	//'
B01000000,
B10000000,
B00000000,
B00000000,
B00000000,
B00000000,
3,

B00100000,	//(
B01000000,
B10000000,
B10000000,
B10000000,
B01000000,
B00100000,
4,

B10000000,	//)
B01000000,
B00100000,
B00100000,
B00100000,
B01000000,
B10000000,
4,

B00000000,	//*
B00100000,
B10101000,
B01110000,
B10101000,
B00100000,
B00000000,
6,

B00000000,	//+
B00100000,
B00100000,
B11111000,
B00100000,
B00100000,
B00000000,
6,

B00000000,	//,
B00000000,
B00000000,
B00000000,
B11000000,
B01000000,
B10000000,
3,

B00000000,	//-
B00000000,
B11111000,
B00000000,
B00000000,
B00000000,
B00000000,
6,

B00000000,	//.
B00000000,
B00000000,
B00000000,
B00000000,
B11000000,
B11000000,
3,

B00000000,	///
B00001000,
B00010000,
B00100000,
B01000000,
B10000000,
B00000000,
6,

B01110000,	//0
B10001000,
B10011000,
B10101000,
B11001000,
B10001000,
B01110000,
6,

B01000000,	//1
B11000000,
B01000000,
B01000000,
B01000000,
B01000000,
B11100000,
4,

B01110000,	//2
B10001000,
B00001000,
B00010000,
B00100000,
B01000000,
B11111000,
6,

B11111000,	//3
B00010000,
B00100000,
B00010000,
B00001000,
B10001000,
B01110000,
6,

B00010000,	//4
B00110000,
B01010000,
B10010000,
B11111000,
B00010000,
B00010000,
6,

B11111000,	//5
B10000000,
B11110000,
B00001000,
B00001000,
B10001000,
B01110000,
6,

B00110000,	//6
B01000000,
B10000000,
B11110000,
B10001000,
B10001000,
B01110000,
6,

B11111000,	//7
B10001000,
B00001000,
B00010000,
B00100000,
B00100000,
B00100000,
6,

B01110000,	//8
B10001000,
B10001000,
B01110000,
B10001000,
B10001000,
B01110000,
6,

B01110000,	//9
B10001000,
B10001000,
B01111000,
B00001000,
B00010000,
B01100000,
6,

B00000000,	//:
B11000000,
B11000000,
B00000000,
B11000000,
B11000000,
B00000000,
3,

B00000000,	//;
B11000000,
B11000000,
B00000000,
B11000000,
B01000000,
B10000000,
3,

B00010000,	//<
B00100000,
B01000000,
B10000000,
B01000000,
B00100000,
B00010000,
5,

B00000000,	//=
B00000000,
B11111000,
B00000000,
B11111000,
B00000000,
B00000000,
6,

B10000000,	//>
B01000000,
B00100000,
B00010000,
B00100000,
B01000000,
B10000000,
5,

B01110000,	//?
B10001000,
B00001000,
B00010000,
B00100000,
B00000000,
B00100000,
6,

B01110000,	//@
B10001000,
B00001000,
B01101000,
B10101000,
B10101000,
B01110000,
6,

B01110000,	//A
B10001000,
B10001000,
B10001000,
B11111000,
B10001000,
B10001000,
6,

B11110000,	//B
B10001000,
B10001000,
B11110000,
B10001000,
B10001000,
B11110000,
6,

B01110000,	//C
B10001000,
B10000000,
B10000000,
B10000000,
B10001000,
B01110000,
6,

B11100000,	//D
B10010000,
B10001000,
B10001000,
B10001000,
B10010000,
B11100000,
6,

B11111000,	//E
B10000000,
B10000000,
B11110000,
B10000000,
B10000000,
B11111000,
6,

B11111000,	//F
B10000000,
B10000000,
B11110000,
B10000000,
B10000000,
B10000000,
6,

B01110000,	//G
B10001000,
B10000000,
B10111000,
B10001000,
B10001000,
B01111000,
6,

B10001000,	//H
B10001000,
B10001000,
B11111000,
B10001000,
B10001000,
B10001000,
6,

B11100000,	//I
B01000000,
B01000000,
B01000000,
B01000000,
B01000000,
B11100000,
4,

B00111000,	//J
B00010000,
B00010000,
B00010000,
B00010000,
B10010000,
B01100000,
6,

B10001000,	//K
B10010000,
B10100000,
B11000000,
B10100000,
B10010000,
B10001000,
6,

B10000000,	//L
B10000000,
B10000000,
B10000000,
B10000000,
B10000000,
B11111000,
6,

B10001000,	//M
B11011000,
B10101000,
B10101000,
B10001000,
B10001000,
B10001000,
6,

B10001000,	//N
B10001000,
B11001000,
B10101000,
B10011000,
B10001000,
B10001000,
6,

B01110000,	//O
B10001000,
B10001000,
B10001000,
B10001000,
B10001000,
B01110000,
6,

B11110000,	//P
B10001000,
B10001000,
B11110000,
B10000000,
B10000000,
B10000000,
6,

B01110000,	//Q
B10001000,
B10001000,
B10001000,
B10101000,
B10010000,
B01101000,
6,

B11110000,	//R
B10001000,
B10001000,
B11110000,
B10100000,
B10010000,
B10001000,
6,

B01111000,	//S
B10000000,
B10000000,
B01110000,
B00001000,
B00001000,
B11110000,
6,

B11111000,	//T
B00100000,
B00100000,
B00100000,
B00100000,
B00100000,
B00100000,
6,

B10001000,	//U
B10001000,
B10001000,
B10001000,
B10001000,
B10001000,
B01110000,
6,

B10001000,	//V
B10001000,
B10001000,
B10001000,
B10001000,
B01010000,
B00100000,
6,

B10001000,	//W
B10001000,
B10001000,
B10101000,
B10101000,
B10101000,
B01010000,
6,

B10001000,	//X
B10001000,
B01010000,
B00100000,
B01010000,
B10001000,
B10001000,
6,

B10001000,	//Y
B10001000,
B10001000,
B01010000,
B00100000,
B00100000,
B00100000,
6,

B11111000,	//Z
B00001000,
B00010000,
B00100000,
B01000000,
B10000000,
B11111000,
6,

B11100000,	//[
B10000000,
B10000000,
B10000000,
B10000000,
B10000000,
B11100000,
4,

B00000000,	//(Backward Slash)
B10000000,
B01000000,
B00100000,
B00010000,
B00001000,
B00000000,
6,

B11100000,	//]
B00100000,
B00100000,
B00100000,
B00100000,
B00100000,
B11100000,
4,

B00100000,	//^
B01010000,
B10001000,
B00000000,
B00000000,
B00000000,
B00000000,
6,

B00000000,	//_
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B11111000,
6,

B10000000,	//`
B01000000,
B00100000,
B00000000,
B00000000,
B00000000,
B00000000,
4,

B00000000,	//a
B00000000,
B01110000,
B00001000,
B01111000,
B10001000,
B01111000,
6,

B10000000,	//b
B10000000,
B10110000,
B11001000,
B10001000,
B10001000,
B11110000,
6,

B00000000,	//c
B00000000,
B01110000,
B10001000,
B10000000,
B10001000,
B01110000,
6,

B00001000,	//d
B00001000,
B01101000,
B10011000,
B10001000,
B10001000,
B01111000,
6,

B00000000,	//e
B00000000,
B01110000,
B10001000,
B11111000,
B10000000,
B01110000,
6,

B00110000,	//f
B01001000,
B01000000,
B11100000,
B01000000,
B01000000,
B01000000,
6,

B00000000,	//g
B01111000,
B10001000,
B10001000,
B01111000,
B00001000,
B01110000,
6,

B10000000,	//h
B10000000,
B10110000,
B11001000,
B10001000,
B10001000,
B10001000,
6,

B01000000,	//i
B00000000,
B11000000,
B01000000,
B01000000,
B01000000,
B11100000,
4,

B00010000,	//j
B00000000,
B00110000,
B00010000,
B00010000,
B10010000,
B01100000,
5,

B10000000,	//k
B10000000,
B10010000,
B10100000,
B11000000,
B10100000,
B10010000,
5,

B11000000,	//l
B01000000,
B01000000,
B01000000,
B01000000,
B01000000,
B11100000,
4,

B00000000,	//m
B00000000,
B11010000,
B10101000,
B10101000,
B10001000,
B10001000,
6,

B00000000,	//n
B00000000,
B10110000,
B11001000,
B10001000,
B10001000,
B10001000,
6,

B00000000,	//o
B00000000,
B01110000,
B10001000,
B10001000,
B10001000,
B01110000,
6,

B00000000,	//p
B00000000,
B11110000,
B10001000,
B11110000,
B10000000,
B10000000,
6,

B00000000,	//q
B00000000,
B01101000,
B10011000,
B01111000,
B00001000,
B00001000,
6,

B00000000,	//r
B00000000,
B10110000,
B11001000,
B10000000,
B10000000,
B10000000,
6,

B00000000,	//s
B00000000,
B01110000,
B10000000,
B01110000,
B00001000,
B11110000,
6,

B01000000,	//t
B01000000,
B11100000,
B01000000,
B01000000,
B01001000,
B00110000,
6,

B00000000,	//u
B00000000,
B10001000,
B10001000,
B10001000,
B10011000,
B01101000,
6,

B00000000,	//v
B00000000,
B10001000,
B10001000,
B10001000,
B01010000,
B00100000,
6,

B00000000,	//w
B00000000,
B10001000,
B10101000,
B10101000,
B10101000,
B01010000,
6,

B00000000,	//x
B00000000,
B10001000,
B01010000,
B00100000,
B01010000,
B10001000,
6,

B00000000,	//y
B00000000,
B10001000,
B10001000,
B01111000,
B00001000,
B01110000,
6,

B00000000,	//z
B00000000,
B11111000,
B00010000,
B00100000,
B01000000,
B11111000,
6,

B00100000,	//{
B01000000,
B01000000,
B10000000,
B01000000,
B01000000,
B00100000,
4,

B10000000,	//|
B10000000,
B10000000,
B10000000,
B10000000,
B10000000,
B10000000,
2,

B10000000,	//}
B01000000,
B01000000,
B00100000,
B01000000,
B01000000,
B10000000,
4,

B00000000,	//~
B00000000,
B00000000,
B01101000,
B10010000,
B00000000,
B00000000,
6,

B01100000,	// (Char 0x7F)
B10010000,
B10010000,
B01100000,
B00000000,
B00000000,
B00000000,
5
};

void scrollFont() {
for (int counter=0x20;counter<0x80;counter++){
delay(500);
}
}

// Scroll Message
void scrollMessage(prog_uchar * messageString) {
int counter = 0;
int myChar=0;
do {
if (myChar != 0){
}
counter++;
}
while (myChar != 0);
}
// Load character into scroll buffer
if (ascii >= 0x20 && ascii <=0x7f){
for (int a=0;a<7;a++){                      // Loop 7 times for a 5x7 font
unsigned long c = pgm_read_byte_near(font5x7 + ((ascii - 0x20) * 8) + a);     // Index into character table to get row data
unsigned long x = bufferLong [a*2];     // Load current scroll buffer
x = x | c;                              // OR the new character onto end of current
bufferLong [a*2] = x;                   // Store in buffer
}
byte count = pgm_read_byte_near(font5x7 +((ascii - 0x20) * 8) + 7);     // Index into character table for kerning data
for (byte x=0; x<count;x++){
rotateBufferLong();
printBufferLong();
delay(scrollDelay);
}
}
}
// Rotate the buffer
void rotateBufferLong(){
for (int a=0;a<7;a++){                      // Loop 7 times for a 5x7 font
unsigned long x = bufferLong [a*2];     // Get low buffer entry
byte b = bitRead(x,31);                 // Copy high order bit that gets lost in rotation
x = x<<1;                               // Rotate left one bit
bufferLong [a*2] = x;                   // Store new low buffer
x = bufferLong [a*2+1];                 // Get high buffer entry
x = x<<1;                               // Rotate left one bit
bitWrite(x,0,b);                        // Store saved bit
bufferLong [a*2+1] = x;                 // Store new high buffer
}
}
// Display Buffer on LED matrix
void printBufferLong(){
for (int a=0;a<7;a++){                    // Loop 7 times for a 5x7 font
unsigned long x = bufferLong [a*2+1];   // Get high buffer entry
byte y = x;                             // Mask off first character
lc.setRow(3,a,y);                       // Send row to relevent MAX7219 chip
x = bufferLong [a*2];                   // Get low buffer entry
y = (x>>24);                            // Mask off second character
lc.setRow(2,a,y);                       // Send row to relevent MAX7219 chip
y = (x>>16);                            // Mask off third character
lc.setRow(1,a,y);                       // Send row to relevent MAX7219 chip
y = (x>>8);                             // Mask off forth character
lc.setRow(0,a,y);                       // Send row to relevent MAX7219 chip
}
}```

The pertinent parts are at the top of the sketch – the following line sets the number of MAX7219s in the hardware:

`const int numDevices = 2;`

The following can be adjusted to change the speed of text scrolling:

`const long scrollDelay = 75;`

… then place the text to scroll in the following (for example):

```prog_uchar scrollText[] PROGMEM ={
"  THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG 1234567890 the quick brown fox jumped over the lazy dog   "};```

Finally – to scroll the text on demand, use the following:

`scrollMessage(scrollText);`

You can then incorporate the code into your own sketches. And a video of the example sketch in action:

Although we used the LedControl library, there are many others out there for scrolling text. One interesting example is Parola  – which is incredibly customisable.

Controlling LED numeric displays with the MAX7219

Using the MAX7219 and the LedControl library you can also drive numeric LED displays – up to eight digits from the one MAX7219. This gives you the ability to make various numeric displays that are clear to read and easy to control. When shopping around for numeric LED displays, make sure you have the common-cathode type.

Connecting numeric displays is quite simple, consider the following schematic which should appear familiar by now:

The schematic shows the connections for modules or groups of up to eight digits. Each digit’s A~F and dp (decimal point) anodes connect together to the MAX7219, and each digit’s cathode connects in order as well. The MAX7219 will display each digit in turn by using one cathode at a time. Of course if you want more than eight digits, connect another MAX7219 just as we did with the LED matrices previously.

The required code in the sketch is identical to the LED matrix code, however to display individual digits we use:

`lc.setDigit(A, B, C, D);`

where A is the MAX7219 we’re using, B is the digit to use (from a possible 0 to 7), C is the digit to display (0~9… if you use 10~15 it will display A~F respectively) and D is false/true (digit on or off). You can also send basic characters such as a dash “-” with the following:

`lc.setChar(A, B,'-',false);`

Now let’s put together an example of eight digits:

```#include "LedControl.h" //  need the library
LedControl lc=LedControl(12,11,10,1); // lc is our object
// pin 12 is connected to the MAX7219 pin 1
// pin 11 is connected to the CLK pin 13
// pin 10 is connected to LOAD pin 12
// 1 as we are only using 1 MAX7219
void setup()
{
// the zero refers to the MAX7219 number, it is zero for 1 chip
lc.shutdown(0,false);// turn off power saving, enables display
lc.setIntensity(0,8);// sets brightness (0~15 possible values)
lc.clearDisplay(0);// clear screen
}
void loop()
{
for (int a=0; a<8; a++)
{
lc.setDigit(0,a,a,true);
delay(100);
}
for (int a=0; a<8; a++)
{
lc.setDigit(0,a,8,1);
delay(100);
}
for (int a=0; a<8; a++)
{
lc.setDigit(0,a,0,false);
delay(100);
}
for (int a=0; a<8; a++)
{
lc.setChar(0,a,' ',false);
delay(100);
}
for (int a=0; a<8; a++)
{
lc.setChar(0,a,'-',false);
delay(100);
}
for (int a=0; a<8; a++)
{
lc.setChar(0,a,' ',false);
delay(100);
}
}```

and the sketch in action:

Conclusion

We have only scratched the surface of what is possible with the MAX7219 and compatible parts. They’re loads of fun and quite useful as well.

This post brought to you by pmdway.com – everything for makers and electronics enthusiasts, with free delivery worldwide.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on twitter @tronixstuff.

# Tutorial – LM3914 Dot/Bar Display Driver IC

This is the first of three tutorials that will examine the LM391x series of LED driver ICs. In this first tutorial we cover the LM3914, then the LM3915 and LM3916 will follow. The goal of these tutorials is to have you using the parts in a small amount of time and experiment with your driver ICs, from which point you can research further into their theory and application.

Although these parts have been around for many years, the LM3914 in particular is still quite popular. It offers a simple way to display a linear voltage level using one or more groups of ten LEDs with a minimum of fuss.

You can order LM3914s in various pack sizes from PMD Way with free delivery, worldwide

With a variety of external parts or circuitry these LEDs can then represent all sorts of data, or just blink for your amusement. We’ll run through a few example circuits that you can use in your own projects and hopefully give you some ideas for the future. Originally by National Semiconductor, the LM391X series is now handled by Texas Instruments.

Getting Started

You will need the LM3914 data sheet, so please download that and keep it as a reference. So – back to basics. The LM3914 controls ten LEDs. It controls the current through the LEDs with the use of only one resistor, and the LEDs can appear in a bar graph or single ‘dot’ when in use. The LM3914 contains a ten-stage voltage divider, each stage when reached will illuminate the matching LED (and those below it in level meter mode).

Let’s consider the most basic of examples (from page two of the data sheet) – a voltmeter with a range of 0~5V.

The Vled rail is also connected to the supply voltage in our example. Pin 9 controls the bar/dot display mode – with it connected to pin 3 the LEDs will operate in bar graph mode, leave it open for dot mode.

The 2.2uF capacitor is required only when “leads to the LED supply are 6″ or longer”. We’ve hooked up the circuit above, and created a 0~5V DC source via a 10kΩ potentiometer with a multimeter to show the voltage – in the following video you can see the results of this circuit in action, in both dot and bar graph mode:

Customising the upper range and LED current

Well that was exciting, however what if you want a different reference voltage? That is you want your display to have a range of 0~3 V DC? And how do you control the current flow through each LED? With maths and resistors. Consider the following formulae:

As you can see the LED current (Iled) is simple, our example is 12.5/1210 which returned 10.3 mA – and in real life 12.7 mA (resistor tolerance is going to affect the value of the calculations).

Now to calculate a new Ref Out voltage – for example  we’ll shoot for a 3 V meter, and keep the same current for the LEDs. This requires solving for R2 in the equation above, which results with R2 = -R1 + 0.8R1V. Substituting the values – R2 = -1210 + 0.8 x 1210 x 3 gives a value of 1694Ω for R2. Not everyone will have the E48 resistor range, so try and get something as close as possible. We found a 1.8 kΩ for R2 and show the results in the following video:

You can of course have larger display range values, but a supply voltage of no more than 25 V will need to be equal to or greater than that value. E.g. if you want a 0~10 V display, the supply voltage must be >= 10V DC.

Creating custom ranges

Now we’ll look at how to create  a lower range limit, so you can have displays that (for example) can range from a non-zero positive value. For example, you want to display levels between 3 and 5V DC. From the previous section, you know how to set the upper limit, and setting the lower limit is simple – just apply the lower voltage to pin 4 (Rlo).

You can derive this using a resistor divider or other form of supply with a common GND. When creating such circuits, remember that the tolerance of the resistors used in the voltage dividers will have an affect on the accuracy. Some may wish to fit trimpots, which after alignment can be set permanently with a blob of glue.

Chaining multiple LM3914s

Two or more LM3914s can be chained together to increase the number of LEDs used to display the levels over an expanded range. The circuitry is similar to using two independent units, except the REFout (pin 7) from the first LM3914 is fed to the REFlo (pin 4) of the second LM3914 – whose REFout is set as required for the upper range limit. Consider the following example schematic which gave a real-world range of 0~3.8V DC:

The 20~22kΩ resistor is required if you’re using dot mode (see “Dot mode carry” in page ten of the data sheet). Moving on, the circuit above results with the following:

Where to from here?

Now you can visually represent all sorts of low voltages for many purposes. There’s more example circuits and notes in the LM3914 data sheet, so have a read through and delve deeper into the operation of the LM3914.

Furthermore Dave Jones from eevblog.com has made a great video whcih describes a practical application of the LM3914:

Conclusion

As always we hope you found this useful. Don’t forget to stay tuned for the second and third instalments using the LM3915 and LM3916.

This post is brought to you by pmdway.com – everything for makers and electronics enthusiasts, with free delivery worldwide.

To keep up to date with new posts at tronixstuff.com, please subscribe to the mailing list in the box on the right, or follow us on twitter @tronixstuff.