Arduino Playground - LedControl PDF
Arduino Playground - LedControl PDF
Arduino Playground - LedControl PDF
(https://playground.arduino.cc/Main/ManualsAndCurriculum)
Arduino StackExchange
(http://arduino.stackexchange.com)
Board Setup and Configuration
(https://playground.arduino.cc/Main/ArduinoCoreHardware)
Development Tools
(https://playground.arduino.cc/Main/DevelopmentTools)
Arduino on other Chips
(https://playground.arduino.cc/Main/ArduinoOnOtherAtmelChips)
Interfacing With Hardware
(https://playground.arduino.cc/Main/InterfacingWithHardware)
- Output
(https://playground.arduino.cc/Main/InterfacingWithHardware#Output)
- Input
(https://playground.arduino.cc/Main/InterfacingWithHardware#InputTOC)
- User Interface
(https://playground.arduino.cc/Main/InterfacingWithHardware#ui)
- Storage
(https://playground.arduino.cc/Main/InterfacingWithHardware#Storage)
- Communication
(https://playground.arduino.cc/Main/InterfacingWithHardware#Communication)
- Power supplies
(https://playground.arduino.cc/Main/IntWithHW-
PwrSup)
- General
(https://playground.arduino.cc/Main/InterfacingWithHardware#General)
Interfacing with Software
(https://playground.arduino.cc/Main/InterfacingWithSoftware)
User Code Library
(https://playground.arduino.cc/Main/GeneralCodeLibrary)
- Snippets and Sketches
(https://playground.arduino.cc/Main/SketchList)
- Libraries
(https://playground.arduino.cc/Main/LibraryList)
- Tutorials
(https://playground.arduino.cc/Main/TutorialList)
Suggestions & Bugs
(https://github.com/arduino/arduino/issues)
Electronics Technique
(https://playground.arduino.cc/Main/ElectroInfoResources)
Sources for Electronic Parts
(https://playground.arduino.cc/Main/Resources)
Related Hardware and Initiatives
(https://playground.arduino.cc/Main/SimilarBoards)
Arduino People/Groups & Sites
(http://playground.arduino.cc/Main/People)
Exhibition
(http://playground.arduino.cc/Projects/ArduinoUsers)
Project Ideas
(http://playground.arduino.cc/Projects/Ideas)
Languages
(https://playground.arduino.cc/Main/Languages)
Participate
(https://playground.arduino.cc/Main/Participate)
- Formatting guidelines
(https://playground.arduino.cc/Main/Participate#contribrules)
- All recent changes
(https://playground.arduino.cc/Site/AllRecentChanges)
- PmWiki
(https://playground.arduino.cc/PmWiki/PmWiki)
- WikiSandBox training
(https://playground.arduino.cc/Main/WikiSandbox)
- Basic Editing
(https://playground.arduino.cc/PmWiki/BasicEditing)
- Documentation index
(http://www.pmwiki.org/wiki/PmWiki/DocumentationIndex)
LedControl
a Arduino library for the MAX7221 (https://playground.arduino.cc/Main/MAX72XXHardware) and
MAX7219 (https://playground.arduino.cc/Main/MAX72XXHardware)
These two chips provide an easy way to control either an array of 64 LEDs or up to 8 digits of 7-
segment displays. A detailed description of the hardware and a schematic can be found here
(https://playground.arduino.cc/Main/MAX72XXHardware).
Table of contents
- Creating a LedControl
- Powersaving mode
- Limiting the number of digits
- Setting display brightness
- Device initialization
- Clearing the display
- Controlling a Ledmatrix
- Control individual LEDs
- Control all the LEDs in a row
- Control all the LEDs in a column
- Controlling 7-Segement displays
- Printing numbers
- Printing characters
- Commented demos for the library
- Source code and download
- Revision history
Creating a LedControl
All the libraries API-functions are called through a variable of type LedControl which you have to
create inside your projects code.
/*
* Now we create a new LedControl.
* We use pins 12,11 and 10 on the Arduino for the SPI interface
* Pin 12 is connected to the DATA IN-pin of the first MAX7221
* Pin 11 is connected to the CLK-pin of the first MAX7221
* Pin 10 is connected to the LOAD(/CS)-pin of the first MAX7221
* There will only be a single MAX7221 attached to the arduino
*/
LedControl lc1=LedControl(12,11,10,1);
Then we create an instance of type LedControl through which we talk to the MAX72XX devices.
The initialization of an LedControl takes 4 arguments. The first 3 arguments are the pin-numbers
on the Arduino that are connected to the MAX72XX. You are free to choose any of the digital IO-pins
on the arduino, but since some of the pins are also used for serial communication or have a led
attached to them its best to avoid pin 0,1 and 13. I choose pins 12,11 and 10 in my example. The library
does not check the pin-numbers to be valid in any way. Passing in something stupid (pin 123??) will
break your app. You don't have to initialize the pins as outputs or set them to a certain state, the
library will do that for you.
/*
* Create a new controller
* Params :
* int dataPin The pin on the Arduino where data gets shifted out
* int clockPin The pin for the clock
* int csPin The pin for selecting the device when data is to be sent
* int numDevices The maximum number of devices that can be controlled
*/
LedControl(int dataPin, int clkPin, int csPin, int numDevices);
If you need to control more than 8 MAX72XX, you can always create another LedControl -variable
that uses 3 different pins on your Arduino board. The only thing you have to do is to initialize another
LedControl
// ... and another one. Now we control 1024 LEDs from an Arduino, not bad!
// Note : the second one must use different pins!
LedControl lc2=LedControl(9,8,7,8);
There is no way to read the pin-numbers from your code, but there is a function that requests the
maximum number of devices attached to an LedControl . This can be very handy when you want
to loop over the full list of MAX72XX devices attached. Here is a piece of code that switches all of the
MAX72XX-devices from power saving mode into normal operation. I'll think you'll get the idea even
though we haven't talked about the shutdown(addr) function yet...
#include "LedControl.h"
void setup() {
for(int index=0;index<lc1.getDeviceCount();index++) {
lc1.shutdown(index,false);
}
}
We iterate over the list of devices by an index that runs from 0 to getDeviceCount()-1 . That
would be 0 to 4 in this piece of code. The index is the address of each device. This address will be the
first argument of every function that sets a feature or a new (Led-)value on a device. Keep in mind
that getDeviceCount() returns the number of devices attached, but the address of an device
starts at 0 for the first one, 1 for the second one,.. getDeviceCount()-1 for the last one. Here is
the prototype of the function:
/*
* Gets the maximum number of devices attached to this LedControl.
* Returns :
* int the number of devices attached to this LedControl
*/
int LedControl::getDeviceCount();
The device will switch off all the LEDs on the display, but the data is retained. You can even continue to
send new data during shutdown mode. When the device is activated later on, the new data will appear
on your display. Here is an example for an invisible countdown on a 7-segment display:
void countDown() {
int i=9;
lc.setDigit(0,(byte)i,false);
//now we see the number '9'
delay(1000);
//switch the display off ...
lc.shutdown(0,true);
//and count down silently
while(i>1) {
//data is updated, but not shown
lc.setDigit(0,(byte)i,false);
i--;
delay(1000);
}
//when we switch the display on again we have already reached '1'
lc.shutdown(0,false);
lc.setDigit(0,(byte)i,false);
}
/*
* Set the shutdown (power saving) mode for the device
* Params :
* int addr The address of the display to control
* boolean b If true the device goes into power-down mode. If false
* device goes into normal operation
*/
void shutdown(int addr, bool b);
Please note that the MAX72XX is always in shutdown mode when the Arduino is powered up.
When a new LedControl is created it will activate all 8 digits on all devices. Each lit digit will be
switched on for 1/8 of a second by the multiplexer circuit that drives the digits. If you have any reason
to limit the number of scanned digits, this is what happens : The LEDs get switched on more
frequently, and therefore will be on for longer periods of time. Setting the scan limit to 4 would mean
that a lit Led is now switched on for 1/4 of a second, so the MAX72XX has to provide the current on
the segment-driver for a longer period of time.
You should read the relevant section of the MAX72XX datasheet carefully! Its actually possible to kill
your MAX72XX by choosing a bad combination of the resistor RSet
(https://playground.arduino.cc/Main/MAX72XXHardware#SelectRSet) that limits the current through
the LEDs and the number of digits scanned by the device. The only reason to tweak the scanlimit at all,
is that the display looks too dark. But this is most likely due to the fact that you haven't raised the
intensity on startup. Anyway, here's the prototype of setScanLimit() for those who need it:
/*
* Set the number of digits (or rows) to be displayed.
* See datasheet for side effects of the scanlimit on the brightness
* of the display.
* Params :
* int addr The address of the display to control
* int limit The number of digits to be displayed
* Only values between 0 (only 1 digit) and 7 (all digits) are valid.
*/
void setScanLimit(int addr, int limit);
Device initialization
When a new LedControl is created the library will initialize the hardware with ...
void setup() {
//wake up the MAX72XX from power-saving mode
lc.shutdown(0,false);
//set a medium brightness for the Leds
lc.setIntensity(0,8);
}
}
/*
* Switch all LEDs on the display off.
* Params:
* int addr The address of the display to control
*/
void clearDisplay(int addr);
All LEDs off after this one, that's it...
There are 3 different ways to switch a Led in a Matrix on or off. We start with a function that controls
each one of the LEDs individually...
/*
* Set the status of a single Led.
* Params :
* addr address of the display
* row the row of the Led (0..7)
* col the column of the Led (0..7)
* state If true the led is switched on,
* if false it is switched off
*/
void setLed(int addr, int row, int col, boolean state);
The addr and the state arguments should be clear, but what exactly is a row and what is a
column on the matrix? It really depends on the wiring between the MAX72XX and your matrix.
The LedControl -library assumes the setup used in this schematic:
There are 8 rows (indexed from 0..7) and 8 columns (also indexed from 0..7) in the matrix. If we want
to light up the LED which is located at the very right of the 3'rd row from the top, simply take the index
of the Led (2.7) and use is as the row and column arguments.
setLed() is fine if you light up only a few LEDs, but if more LEDs need to be updated, it would
require many lines of code. So there are two more functions in the library, that control a complete row
and column with a single call.
Control all the LEDs in a row
The setRow(addr,row,value) -function takes 3 arguments. The first one is the already familiar
address of our device. The second one is the row that is going to be updated and the third one the
value for this row.
But how do we know which LEDs light up for a specific value? The value, a byte, uses a simple encoding
where each bit set to 1 represents a lit led and an unset bit a Led switched off. Here is an example:
The index for the row to be updated is 2. Now we have to set the byte-value for the LEDs to be lit. The
easiest approach is to include the standard header-file <binary.h> to your sketch. Now you can write
down the value in binary encoding and have an exact mapping between bits set to 1 and the LEDs to be
switched on. To light up the the LEDs from the example we could simply write:
//now setting the LEDs from the third row on the first device is easy
lc.setRow(0,2,B10110000);
If for any reason you can not specify the value in binary encoding, here is a simple table that maps the
decimal values of each bit to the Led it affects. The two rows at bottom give an example for how to
calculate the decimal value for the example from above.
Inside your code you would use lc.setRow(0,2,176) to update this row on the first MAX72XX
attached to the Arduino. As a side-effect the setRow() -call is much faster than calling
setLed() in turn for each Led. So use this method wherever you can.
/*
* Set all 8 LEDs in a row to a new state
* Params:
* addr address of the display
* row row which is to be set (0..7)
* value each bit set to 1 will light up the corresponding Led.
*/
void setRow(int addr, int row, byte value);
Here is an example.
This time we want the 4 LEDs at the bottom of column 6 to be lit. We can use the the binary encoding
again. Here the leftmost bit in the value refers to the Led at the top of the column:
//now setting the leds from the sixth column on the first device is easy
lc.setColumn(0,5,B00001111);
and here is the table that maps bits to the LEDs for columns:
The signature of the method is almost the same a the row-version of it:
/*
* Set all 8 LEDs in a column to a new state
* Params:
* addr address of the display
* col column which is to be set (0..7)
* value each bit set to 1 will light up the corresponding Led.
*/
void setColumn(int addr, int col, byte value);
A complete example for the Led matrix functions can be found on the demo-page
(https://playground.arduino.cc/Main/LedControlDemos) for the library.
A note on performance...
There is an important difference between the way the setRow()- and the setColumn()-
methods update the Leds:
- setRow() only needs to send a single int -value to the MAX72XX in order to update all
8 LEDs in a row.
- setColumn() uses the setLed() -method internally to update the LEDs. The library has
to send 8 ints to the driver, so there is a performance penalty when using setColumn() .
You won't notice that visually when using only 1 or 2 cascaded LED boards, but if you have a
long queue of devices (6..8) which all have to be updated at the same time, that could lead to
some delay that is actually visible.
Printing numbers
The most common use of 7-segment displays is to show numbers. The first function we look at, takes
an argument of type byte and prints the corresponding digit on the specified column. The range of
valid values runs from 0..15. All values between 0..9 are printed as digits, values between 10..15 are
printed as their hexadecimal equivalent.
Any other value will simply be ignored, which means nothing will be printed. The column on the display
will not be blanked, it will simply retain its last valid value. The decimal point on the column can be
switched on or off with an extra argument.
Here is a small example that prints an int value (-999..999) on a display with 4 digits.
void printNumber(int v) {
int ones;
int tens;
int hundreds;
boolean negative;
/*
* Display a (hexadecimal) digit on a 7-Segment Display
* Params:
* addr address of the display
* digit the position of the digit on the display (0..7)
* value the value to be displayed. (0x00..0x0F)
* dp sets the decimal point.
*/
void setDigit(int addr, int digit, byte value, boolean dp);
The digit -argument must be from the range 0..7 because the MAX72XX can drive up to eight 7-
segment displays. The index starts at 0 as usual.
Printing characters
There is a limited set of characters that make (visual) sense on a 7-segment display. A common use
would be the character '-' for negative values and the 6 characters from 'A'..'F' for hex-values.
The setChar(addr,digit,value.dp) -function accepts a value of type char for the whole range
of 7-bit ASCII encoding. Since the recognizable patterns are limited, most of the defined characters will
be the <SPACE> -char. But there are quite a few characters that make sense on a 7-segment display.
- 0123456789
- A a (prints upper case)
- B b (prints lower case)
- C c (prints lower case)
- D d (prints lower case)
- E e (prints upper case)
- F f (prints upper case)
- H h (prints upper case)
- L l (prints upper case)
- P p (prints upper case)
- - (the minus sign)
- ., (lights up the decimal-point)
- _ (the underscore)
- <SPACE> (the blank or space char)
For your convenience, the hexadecimal characters have also been redefined at the character values
0x00...0x0F. If you want to mix digits and characters on the display, you can simply take the same byte
argument that you would have used for the setDigit() -function and it will print the hexadecimal
value.
The prototype of the function is almost the same as the one for displaying digits.
/*
* Display a character on a 7-Segment display.
* There are only a few characters that make sense here :
* '0','1','2','3','4','5','6','7','8','9','0',
* 'A','b','c','d','E','F','H','L','P',
* '.','-','_',' '
* Params:
* addr address of the display
* digit the position of the character on the display (0..7)
* value the character to be displayed.
* dp sets the decimal point.
*/
void setChar(int addr, int digit, char value, boolean dp);
The latest binary release is always available from the LedControl Release Page
(https://github.com/wayoda/LedControl/releases)
Instructions to install a library for the Arduino IDE are found here
(http://arduino.cc/en/Guide/Libraries#.UwxndHX5PtY)
#include "LedControl.h"
void setup() {}
void loop() {}
... hit the verify button and the library will be compiled and is available for all of your sketches that
start with a #include "LedControl.h" line.
The Zip-File also contains 3 example sketches which are documented on the LedControlDemos
(https://playground.arduino.cc/Main/LedControlDemos) page.
Known bugs
Currently none
Revision History
- May 26, 2014 Fixed an error in the setChar() function.
- Februrary 10, 2014 Updated the install instructions for the library.
- September 10, 2012 Changed the software license from LGPL to an MIT-style license.
- September 19, 2011 Uploaded new version of LedControl.zip. Release 1.0 of the Arduino IDE
renamed the internal header file WProgramm.h to Arduino.h . The include statement in
LedControl.h was updated so the library compiles under pre- and post-1.0 versions of the
IDE
- October 14, 2008 Uploaded a new version of the LedControl.zip. The original version did not
compile under arduino-0012.
- December 5, 2007 Documentation and source code is now hosted on the Arduino Playground
- June 23, 2007 First public release
Feedback
You are also welcome to send questions, objections or corrections to <e.fahle@wayoda.org>, or create
an issue on the GitHub page (https://github.com/wayoda/LedControl/issues) for the library
Share