Driving 7-segment displays with a MM5480 and Arduino
For the last year, up until a couple of months ago, my
heater was pretty unreliable, probably because of a flaky
relay in its control unit, or maybe some bad capacitors,
something that nowadays seems to kill almost all electronics
prematurely.
Well getting bored of hitting the poor machine until it started
working again, about every day, I finally replaced its Econgas
control unit and, of course, I tore the old unit apart.
It's a nice piece of kit, It seems to be made by a Dutch firm
called Pijnenburg, a name that I only associated with a
particular brand of Dutch cakes before. ;-)
Maybe more later about the internals of that unit, or maybe
never, it depends on whether I find any other interesting stuff
inside. But wat got me started was its nice control panel,
containing three red 7-segment LED displays, three buttons and
a Micrel MM5480BN shift-register based LED driver. Something
that just screamed to be hooked up to my trusty Arduinos!
Here is the result already:
But how I ended up with this result might be interesting for
fellow tinkerers, so I'll summarize my steps below.
The Micrel MM5480 is actually quite a nice part. After a start
bit, that is always high, you clock in another 35 bits of data,
with wich you define the state of your LED's.
Once your 36th clock pulse goes high, the data that you've
clock into the shift-register is latched to the LED drivers,
eliminating the need for a seperate pin to do so.
Well...that was the nice bit.
Now I only needed to find out how the display segments were
connected to the MM5480, so which databit maps to which LED
segment.
To do so, I created a small program that shifted a 1 through
all 35 databits, printed the current databit that was 1 to
the Arduino IDE's console and I noted the lit LED segment on
a piece of paper.
There are a few oddities in the segment mapping, those are only
related to this particular board.
Next, I wrote a small demonstration program, that contains
two tables. One to map segments to MM5480 databits and a sort
or character ROM with hexadecimal numbers and some other stuff
that is displayable on a 7-segment display.
The sample program that I've listed below does nothing more
than counting from 0 to 999 over and over again, but it's
a good start for some more useful programs.
/* * Drive Micrel MM5480BN based 3x7 segment LED display * module from an Econgas control unit * * Hessel Schut, hessel@isquared.nl, 2009-10-17 * */ // MM5480 shift register connections #define PIN_SERDAT 2 #define PIN_SERCLK 3 /* Segment numbering: * * 3333 * 2 4 * 2 4 * 6666 * 1 5 * 1 5 * 0000 77 * * Digits are numbered from left to right, should the * other way around, of course, silly me... */ /* reg is a buffer containing the bits to be clocked to * the MM5480, reg[0], the first bit sent is always high, * indicating a start of frame, on the rising edge of * SERCLK period 36, bits 1..36 will be latched to the display. */ boolean reg[36]; // (digit, segment) to bit mapping static const int segment[][3] = { {25, 13, 2}, {27, 14, 3}, {30, 15, 4}, {31, 20, 5}, {32, 21, 6}, {33, 22, 7}, {23, 24, 12}, // bleh?! {34, 26, 8} // 26 is nc }; // char to 7-segment mapping static const byte digit[] = { /* _76543210 */ B00111111, // 0 -- integers B00110000, // 1 B01011011, // 2 B01111001, // 3 B01110100, // 4 B01101101, // 5 B01101111, // 6 B00111000, // 7 B01111111, // 8 B01111101, // 9 B01111110, // A -- hex digits B01100111, // b B01000011, // c B01110011, // d B01001111, // E B01001110, // F B00101111, // G -- some alpha and the rest B01110110, // H B00110011, // J B00000111, // L B01100010, // n B01100011, // o B01011110, // P B01111100, // q B01000010, // r B01000111, // t B00100011, // u B01110101, // y B00110101, // ij B01001001, // x (dash dash dash) B01111011, // a B00001111, // C B01011111, // e B01100110, // h B01011100, // degree B01000001, // = B00000100, // ' B00010100, // " B00000000 // space }; // clear reg[] buffer void eraseBuffer() { for (int i = 1; i <= 36; i++) { reg[i] = 0; }; reg[0] = 1; } // write buffer to the display void writeBuffer() { for(int databit = 0; databit <= 35; databit++) { // bit 0 is always high if ((databit == 0) || (reg[databit] == 1)) { digitalWrite(PIN_SERDAT, HIGH); } else { digitalWrite(PIN_SERDAT, LOW); }; // strobe clock digitalWrite(PIN_SERCLK, HIGH); digitalWrite(PIN_SERCLK, LOW); }; } // set individual digit void setLEDDigit(int LEDdigit, int value) { for(int d = 0; d <= 7; d++) { if ((digit[value] >> d) & B00000001) { reg[segment[d][LEDdigit]] = 1; }; }; } // write a value (<=999) to the display void writeValue(int val) { int h, t, u; if (val > 999) val = 999; h = val / 100; // hunderds t = val % 100 / 10; // tens u = val % 10; // units // write value without leading zeroes if (h > 0) setLEDDigit(2, h); if (h > 0 || t > 0) setLEDDigit(1, t); setLEDDigit(0, u); writeBuffer(); }; // write a value (<=99) to the display void writeValueRightMost(int val) { int t, u; if (val > 99) val = 99; t = val / 10; // tens u = val % 10; // units // write value without leading zeroes if (t > 0) setLEDDigit(1, t); setLEDDigit(0, u); writeBuffer(); }; void setup() { pinMode(PIN_SERDAT, OUTPUT); pinMode(PIN_SERCLK, OUTPUT); digitalWrite(PIN_SERDAT, LOW); for(int databit = 0; databit <= 35; databit++) { digitalWrite(PIN_SERCLK, HIGH); digitalWrite(PIN_SERCLK, LOW); }; } void loop() { eraseBuffer(); for(int i = 0; i <= 999; i++) { eraseBuffer(); if (i & 1) reg[34] = 1; // blink dp writeValue(i); delay(100); }; }
Now for some more interesting programs, I have no idea yet.
I might think of something later, but for now it was a nice
time to spent my saturday evening... ;)
isquared.nl rss (atom)