Overview
Two common questions we receive:
- How can I use more than one 8x8 matrix backpack in an Arduino sketch?
- Can I have two (or more) matrices always showing the same image?
This tutorial demonstrates both.
We’ve had spooky Halloween displays on the brain lately, but the concepts here are equally applicable to more innocent schemes!
Page last edited March 08, 2024
Text editor powered by tinymce.
Wiring
TWI allows multiple devices to communicate on the same bus. Just two wires are required…you don’t need to dedicate Arduino pins to every separate device. This takes place on analog pins 4 (serial data) and 5 (serial clock). Newer “R3” Arduino boards also include distinct SDA and SCL pins serving the same functions, though analog pins 4 and 5 still work too.
In order to distinguish among multiple devices on the bus, each must be assigned a unique numeric address. Most devices (sensors, etc.) are factory-configured for one specific address, but others (like these LED backpacks) are at least partially configurable. There’s a default address (0x70 in hexadecimal notation) which can then be tweaked by joining some solder pads on the back of the board:
But there’s only four addresses, and we have five matrices! So we’ll use a small compromise here: both eyes will always point the same direction and blink together…no winking or crossed eyes. To do this, we just use the same address for both — they’ll receive and display the exact same data in unison. (And that’s all there is to that…sorry if you were expecting a more technical procedure!)
The three mouth matrices are then each assigned a unique address, separate from the “eyes” address. Here’s the view from the back:
Notice we’re not using the DC power jack on the Arduino. Each of these displays can draw up to 200 milliamps (when fully lit), and the 5V regulator on the Arduino is only rated up to 500 mA. It could handle one or two of these displays (e.g. if only using the eyes), but the full face requires more current than this.
The buttons are optional — one of the example sketches (“wavface”) works together with a Wave Shield, and these are used to trigger sounds. A simpler example (“roboface”) does not require the Wave Shield or the buttons.
The three mouth matrices were tacked together with a bit of hot-melt glue. For the wires, an unused mounting hole on the Proto Shield was used as a strain relief attachment point, so anything pulling on the wires will put pressure here and not on the solder connections.
Page last edited March 08, 2024
Text editor powered by tinymce.
Software
If this is your first introduction to the Adafruit LED backpacks, you should work through the LED Backpack tutorial first. Get a single matrix up and running, confirm that code and wiring are all correct before advancing to this “level 2” project.
You’ll need to download and install the Adafruit_GFX, Adafruit_BusIO and Adafruit_LEDBackpack libraries. We have a tutorial explaining how libraries are installed.
The backpack library already includes the example code for animating the face (“roboface” and “wavface”), these don’t need to be separately downloaded.
If using the Wave Shield example (“wavface”), you’ll also need to download and install the WaveHC library. It’s imperative then that you work through the original Wave Shield tutorial before moving on to this more advanced project. There are many separate parts, and a misstep with any one of them can stop the whole system from working. Testing the Wave Shield first lets you know that the shield is properly assembled, the SD card properly formatted and so forth. (If you’re not using the Wave Shield then you can bypass this step.)
Programming for Multiple Matrices
Whether you’re working with one or with several LED backpacks, you’ll need to #include three header files at the top of your sketch: one for the standard Arduino TWI library, and one each for the Adafruit device and graphics libraries:#include <Wire.h> #include "Adafruit_LEDBackpack.h" #include "Adafruit_GFX.h"
Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
matrix.begin(0x70); matrix.drawRect(0, 0, 8, 8, LED_ON);
Adafruit_8x8matrix matrixOne = Adafruit_8x8matrix(); Adafruit_8x8matrix matrixTwo = Adafruit_8x8matrix(); Adafruit_8x8matrix matrixThree = Adafruit_8x8matrix(); ...
Adafruit_8x8matrix matrix[4];
for(uint8_t i=0; i<4; i++) {
matrix[i] = Adafruit_8x8matrix();
matrix[i].begin(0x70 + i);
}
To issue commands to a specific matrix, we follow the array name (“matrix”) with an index — the element number in the array (a four-element array has indices 0 through 3). The syntax and parameters are otherwise the same as the single-matrix example. Here we issue different commands to each of four matrices in an array:
matrix[0].drawPixel(0, 0, LED_ON); matrix[1].drawLine(0, 0, 7, 7, LED_ON); matrix[2].drawRect(0, 0, 8, 8, LED_ON); matrix[3].fillRect(2, 2, 4, 4, LED_ON);
for(uint8_t i=0; i<4; i++) {
matrix[i].writeDisplay();
}
Animating the Face
The “roboface” example simply flips among a set of six mouth images randomly. “wavface” is synchronized to one of three voice clips played by the Wave Shield (these are in the “wavs” folder — copy them to an SD card). There is no “magic” here, no decoding of the speech or whatnot…the timing and mouth positions were simply determined manually through some educated trial and error, same way traditional animators do it.
Six mouth images seems like it should be tremendously limiting, but together with the dialogue this coarse animation is enough to fool the eye. Here’s a great tutorial explaining the principle.
Bitmaps
The face is drawn using a series of stored bitmaps rather than having a lot of code drawing lines, circles, etc. The only exception are the moving pupils, which are simply 2x2 pixel black squares.The Arduino binary number notation simplifies the task of creating these shapes; you can practically see the image right in the code. For example, here's one frame of a Jack-o’-lantern mouth:
static uint8_t PROGMEM
mouthImg[][24] = {
{ B00000000, B00000000, B00000000,
B11100000, B00000000, B00000111,
B01111111, B00000000, B11111110,
B00111111, B11111111, B11111100,
B00001100, B01111110, B00110000,
B00000000, B01111110, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
// ...Subsequent bitmaps go here...
};
- The binary number notation (numbers starting with “B”) requires 8 digits…no longer, no shorter.
- By extension, a bitmap therefore must be some multiple of 8 pixels wide (e.g. 24 in the example above). You can pad an image with extra unused zeros at the right to fill out the multiple-of-8 rule.
- Bitmap data must be declared with the PROGMEM directive. This stores data in the Arduino’s flash program memory rather than using scarce RAM.
Page last edited March 08, 2024
Text editor powered by tinymce.
Ideas
Level up: add a joystick to move the eyes…or if you’re really committed, use a webcam or a Kinect sensor on a PC (connecting to the Arduino through USB) to make the eyes automatically follow victims around the room.
Lesson learned: at 200 milliamps each, these displays get warm enough to soften the glue. Nothing fell off, but it’s something to keep in mind. If the situation permits, use the matrix backpacks’ mounting holes (obviously this won’t work with the glass head).
Level up: have the mouth move in sync with the wearer’s own…perhaps a pressure or flex sensor under the chin, or using a microphone based on volume.
Page last edited March 08, 2024
Text editor powered by tinymce.