You can imagine these modules as a matrix of four times eight LEDs, as can be seen in the included circuit. I use two of these, so I have a matrix of eight times eight LEDs.
The rows and columns of this matrix are connected to the microcontroller, so it can power them row by row. This has two advantages: at first a maximum of eight LEDs is powered at a time, so power consumption is lowered. And at second you need only 16 pins of the controller to address a total of 64 LEDs.
Driving the LEDs in this way makes them flicker a bit, but the controller is fast enough to keep the flickering way above the level you would be able to recognize.
I could have connected my display modules directly to the main controller of my next project, but I don't have enough free pins on that. As a further benefit, multiplexing the LEDs on a second controller makes the main program easier to write, since I don't have to mind the timing. So the solution is to use a cheap ATmega8 as LED driver and use the I2C-bus to tell it what to display.
A basic code example would look like this:
#define I2C_LEDMATRIX 0x10 // address of the device timerInit(); // initialize timers timerPause(100); // give everything a little time to settle i2cInit(); // initialize i2c function library timerPause(100); // wait a bit more while (1) { // endless loop uint8_t buffer[9]; // prepare buffer // loop until 255 for (uint8_t i = 0; i <= 255; i++) { // set all bytes of the buffer to value i memset(buffer, i, sizeof(buffer)); // send the buffer via I2C-bus i2cMasterSend(I2C_LEDMATRIX, sizeof(buffer), buffer); timerPause(500); // wait, so you have the time to watch } }
Note: the buffer doesn't contain any numbers that should be displayed on 7segment-displays. At least not in this example. It only holds bit-patterns.
However, if you are going to use 7segment displays, definition of the numbers still depends on how you soldered them to the controller. I don't know if the pin-outs are commonly standardized.
To give an example of how you would implement this, here is a fragment of code that defines hexadecimal numbers for usage on my displays:
// Names of the segments: // aaaaa // f b // f b // ggggg // e c // e c // ddddd h uint8_t characters[16]; // c e g a h f b d characters[ 0] = (1 << 0) | (1 << 1) | (0 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (1 << 7); // 0 characters[ 1] = (1 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (0 << 7); // 1 characters[ 2] = (0 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (1 << 7); // 2 characters[ 3] = (1 << 0) | (0 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (1 << 7); // 3 characters[ 4] = (1 << 0) | (0 << 1) | (1 << 2) | (0 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (0 << 7); // 4 characters[ 5] = (1 << 0) | (0 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (1 << 7); // 5 characters[ 6] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (1 << 7); // 6 characters[ 7] = (1 << 0) | (0 << 1) | (0 << 2) | (1 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (0 << 7); // 7 characters[ 8] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (1 << 7); // 8 characters[ 9] = (1 << 0) | (0 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (1 << 7); // 9 characters[10] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (0 << 7); // a characters[11] = (1 << 0) | (1 << 1) | (1 << 2) | (0 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (1 << 7); // b characters[12] = (0 << 0) | (1 << 1) | (0 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (1 << 7); // c characters[13] = (1 << 0) | (1 << 1) | (1 << 2) | (0 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (1 << 7); // d characters[14] = (0 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (1 << 7); // e characters[15] = (0 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (0 << 7); // f
If you take a brand-new controller you shouldn't have to hassle with the fuses of the controller. The internal oscillator at 1MHz is enough to keep the display flicker-free. The settings I used are included in the makefile, so you can use it to reset controllers you already changed in other projects.
Oh, and if you want the slave to use an I2C-address different from 0x10: no problem. Just change it in the code.
(c) 2008 by Ronald Schaten - http://www.schatenseite.de