Modular Music Box – MAX7221
The ‘Winder’ in the MMB has a ‘clock face’ of 12 orange LEDs in a circle used to give visual feedback on which way and how much to wind the key… as well as display the ‘winding down’ of the mechanism.
While I could have managed this by using an LED per digital output on the Arduino Duemilanove clone – I thought I’d use it as an opportunity to work with and learn more about LED drivers.
74HC595 Shift Register
I’ve been playing with the 74HC595 Shift Register – which can control 8 LEDs per chip so I’d need two chips – but because the 74HC595 doesn’t current sink I’d also need 12 x 1KOhm 1/4 resistors and 12 BC548 NPN transistors…(or 2 x ULN2003A Darlington Transistors Seven NPN Arrays) which seems a bit too much of an effort. I haven’t managed to get any of the 74HC595 libraries working either (though I haven’t tried adding the code mentioned in the Modular Music Box – Quadrature Rotary Encoder post).
TLC5940
The Texas Instruments TLC5940 is“a 16 channel PWM unit with 12 bit duty cycle control (0 – 4095), 6 bit current limit control (0 – 63), and a daisy chain-able serial interface”. There’s also an Arduino library that makes coding with the TLC5940 very straightforward. – but when I tried to use it in the circuit I had no luck – possibly because it’s for use with common anode LED matrix types? UPDATE – Mike Cook suspects it may be a driver conflict with I2C.
MAX7219 and MAX7221
So looking for alternatives I came across the MAX7219 and MAX7221 LED drivers – “for driving either 64 individual Led’s, or up to 8 digits of 7-segment displays. The drivers implement a SPI compatible slave interface that can be controlled from the Arduino using only 3 of the digital output pins.”
The info is clear and thorough – albeit oriented towards 8×8 LED matrices and 7-Segment displays – but by treating my 12 lead as if they were the first row and a half of an 8×8 LED matrix I was able to control it easily enough.
Controlling a Led matrix or 7-segment displays with the MAX7219 or the MAX7221 outlines “different solutions for driving this popular piece of hardware from the Arduino.”
Since I can foresee using more sophisticated LED, matrices and 7-segment display configurations in the future I chose to use the LedControl-library which “can drive multiple devices and has a specific command-set for 7-segment displays”.
My experience was that there’s a fair amount of configuration involved to get this library to behave consistently… and I frequently found my test blinking sequences ended up with all the LEDs on…
Searching the Arduino Forums and other blog posts helped me piece together a sketch that worked… so I’m posting it in below for reference. I’m not sure if this is just my impatience in not reading the instructions properly – or a lack of clarity in the instructions – probably the former.
I do miss the PWM per channel of the TLC5940 – brightness is global on the MAX722 – but at least it works with the rest of the electronics!
The MAX7221 isn’t cheap either ~£10 from Mouser. An alternative – and cheaper solution – may well be the AS1107 LED Driver IC by austriamicrosystems “compact display drivers for 7-segment numeric displays of up to 8 digits… programmed via SPI…” which apparently works with the existing library.
[sourcecode language=”objc”]
#include "LedControl.h"
#undef int
#undef abs
#undef double
#undef float
#undef round
/* we have to including the library */
#include "LedControl.h"
/*
* 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);
/*
* 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);
int DIN = 12;
int CLK = 11;
int LOADCS = 10;
// define the LedControl instance – add more if >8 required
LedControl lc1=LedControl(DIN,CLK,LOADCS,1); // DIN, CLK, Load/CS, 1 = only one chip MAX chip attached.
int flashDelay = 100; // delay in MS (1000=1 second)
int ledBrightness = 15; // range is 0-15. 0=lowest, 15 = full power
void setup() // run once, when the sketch starts
{
// mark the three pins for the MAX signals as outputs
pinMode(DIN, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(LOADCS, OUTPUT);
// take pins out of power save mode. No updates otherwise.
for(int index=0;index<lc1.getDeviceCount();index++) {
lc1.shutdown(index,false);
}
/*
* Set the brightness of the display.
* Params:
* int addr the address of the display to control
* int intensity the brightness of the display.
* Only values between 0(darkest) and 15(brightest) are valid.
*/
//void setIntensity(int addr, int intensity);
lc1.setIntensity(0,ledBrightness );
/*
* Set the number of digits (or rows) to be displayed.
* See datasheet for sideeffects 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.
*/
lc1.setScanLimit(0, 1);
/*
* Switch all Leds on the display off.
* Params:
* int addr The address of the display to control
*/
//void clearDisplay(int addr);
lc1.clearDisplay(0);
}
void loop() // run over and over again
{
//int row = 0;
int chipId = 0;
// for this test I only wired up one row attached to PIN 2 (row 0)
// this is why row is defined as loop scoped and initialised to 0
// you could easily wrap row in another for (int row…) construct
// LED’s share +5v/cathode with Anodes on each LED connected
//to pins SegA – SegG
// for (int row=0; row<=7; row++) {
// for (int col=0; col<=7; col++) {
//
// lc1.setLed(chipId, row, col,true);
// delay(flashDelay);
// lc1.setLed(chipId, row, col, false);
// delay(flashDelay);
// }
// }
lc1.setLed(chipId, 0, 0, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 0, false);
lc1.setLed(chipId, 0, 1, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 1, false);
lc1.setLed(chipId, 0, 2, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 2, false);
lc1.setLed(chipId, 0, 3, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 3, false);
lc1.setLed(chipId, 0, 4, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 4, false);
lc1.setLed(chipId, 0, 5, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 5, false);
lc1.setLed(chipId, 0, 6, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 6, false);
lc1.setLed(chipId, 0, 7, true);
delay(flashDelay);
lc1.setLed(chipId, 0, 7, false);
lc1.setLed(chipId, 1, 0, true);
delay(flashDelay);
lc1.setLed(chipId, 1, 0, false);
lc1.setLed(chipId, 1, 1, true);
delay(flashDelay);
lc1.setLed(chipId, 1, 1, false);
lc1.setLed(chipId, 1, 2, true);
delay(flashDelay);
lc1.setLed(chipId, 1, 2, false);
lc1.setLed(chipId, 1, 3, true);
delay(flashDelay);
lc1.setLed(chipId, 1, 3, false);
//lc1.setLed(chipId, 0, 0, true);
//delay(500);
//lc1.setLed(chipId, 0, 0, false);
[/sourcecode]