These two chips provide an easy way to control either an array of 64 Led’s or up to eight digits made of 7-segment displays with a minimum of electronic components. Besides the chip itself you will need only a single resistor and one or two capacitors. Data is send to the chip using a SPI-compatible protocol using 3 of the digital pins on the arduino. If you want control more than eight 7-segment displays (or more than 64 Led’s) the chips can be cascaded. The library supports up to 8 cascaded devices, which add up to 512 Led’s that can be lit individually. The good news is that you still need only 3 pins on your arduino board.
Here is a picture of my rather crappy (but working) testbed…
If you wonder wether the MAX7221 or the MAX7219 is more suitable for your project … just go for the cheaper one. But, if there is a chance you’ll switch from the arduino to a different controler hardware, use the (more expensive) MAX7221. This one implements a fully SPI compatible interface. The LedControl library can cope with both types of devices, and the visual appearance to the user is the same.
Everything else you need to know about the MAX7221 and MAX7219 is to be found in the components datasheet. I will refer to the datasheet in various places when describing the library functions. So I would suggest you read it before going on…
The LedControl library
This is not the first time someone puts out code for the arduino and the MAX7221, but the focus has usually been on controling Led’s layed out in some kind of rectangular matrix. I mainly use the chips to drive 7-segment displays, so I obviously want a function to display numbers (decimal and hexa-decimal) and also the limited set of alphanumeric characters that make (visual) sense for these types of displays.
I also wanted the code to be useful for a bigger audience, so there had to be a set of functions to switch individual or groups of Led’s on and off.
If you have used other libraries for the MAX72XX that used the Sprite-library, I have to tell you that the LedControl-library does not support Sprites, mainly because the library uses too much memeory on the Arduino. Adding the LedControl-library to your code will cost you 1690 bytes on an ATMega168. But this number is for the basic (do-nothing) application, where we only include the library-code without calling any of the functions.
//This app does nothing but waste (library-)memory #include "LedControl.h" void setup() {} void loop() {}
In my environment (arduino0007 on linux) memory consumption for the compiled application is raised from 4070 bytes (with the #include
-statement commented out) to 5760 from the code above. This is a little bit less than using the combination of the Matrix/Sprite
-library that adds 2266 bytes to my code. (I actually have been wondering for some time now where that memory is burned inside the Sprite
-library. Sprite.h
alone is reponsible for 1.2 kB of the 2.2 kB gone …?)
If you have been using the Matrix/Sprite
-lib you will not be amused to hear this one : The LedControl
-lib uses a different scheme of adressing the individual Led’s on the hardware Ok, I know that this is annoying, but it should not be difficult to port an existing application with the hints given later on. The reason I use a different hardware-address scheme for the Led’s, is that the layout used in the Matrix/Sprite
-lib would require some extra bit-twisting code for each change on an Led’s state. Since you will have to rewrite all of your code anyway when switching librarys, I decided to put that extra burdon upon you, just to save some more bytes and performance, sorry.
Other differences between existing library-code and the LedControl
-lib are discussed along with the API-documentation.
Creating a LedControl
All the libraries API-functions are called through an variable of type LedControl
. Lets go right into some basic code :
/* we have to including the library */ #include "LedControl.h" /* * Create a new LedControl. * We use pins 12,11 and 10 for the SPI interface * With our hardware we have connected pin 12 to the DATA IN-pin (1) of the first MAX7221 * pin 11 is connected to the CLK-pin(13) of the first MAX7221 * pin 10 is connected to the LOAD-pin(12) of the first MAX7221 * We will only have a single MAX7221 attached to the arduino */ LedControl lc1=LedControl(12,11,10,1);
The first step is is obvious we have to include the LedControl
-library. Then we create an instance of type LedControl
to talk to the MAX7221 devices. An LedControl
is to be initialized with 4 arguments. The first 3 arguments are the pin-numbers you haved used in the connection between the arduino-board and your (first) MAX72XX. You are free to choose any of the digital IO-pins on the arduino, but some of the pins are used also for serial communication with other devices or have a led attached to them (happens to be on pin 13 of my board). In the example I choose pins 12,11 and 10. But this simply depends on your own hardware setup. The library does not check for the pin-numbers to be valid in any way. Passing in something stupid will break your app.
You don’t have to set the pins to be used for the devices as outputs or initialize them in any way. The library handles all this for you. Simply hand them over to constructor and then leave them alone for the rest of the code.
Besides the 3 pin-numbers you provide the number of cascaded MAX72XX devices you will be using on this SPI-Bus. The LedControl
-lib allows to address up to 8 devices from a single LedControl
-variable. There is a little performance penalty implied with each device you add to the chain. If that is not important to you (try it out in your code) you could simply go for the maximum (8) devices. The library always uses the same amount of memory, no matter how many devices you set in the argument. Only values between 1..8 are allowed here, otherwise the default of 8 devices is used. Here is the prototype for a new LedControl
-instance:
/* * Create a new controler * 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 controled */ LedControl(int dataPin, int clkPin, int csPin, int numDevices);
If you need to control more than 8 MAX72XX, you’ll have to create another LedControl
-variable that uses 3 other Pins on your arduino-board.
/* we have to include the library */ #include "LedControl.h" // Create a new LedControl for 8 devices... LedControl lc1=LedControl(12,11,10,8); // ... and another one, now we control 1024 Leds's from an arduino, not bad! // The second one must use different pins! LedControl lc2=LedControl(9,8,7,8);
Obviously two instances of LedControl
cannot share the pins on the arduino-board.
There are no functions to replace or swap any of the pins later on. You can’t even read the used pin-numbers from your code. All this depends very much on the hardware you build, so implementing functions for this would be a waste of memory. But a function by which you can request the maximum number of devices attached to an LedControl
can be very handy when you want to iterate over the full list of MAX72XX devices attached to an LedControl
. 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()
function yet…
For more detail: A arduino library for the MAX7221 and MAX7219