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"
The “matrix8x8” example sketch (included with the Adafruit_LEDBackpack library) is written for a single LED matrix. That code declares a single Adafruit_8x8matrix object like so:
Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
That single object is then later referred to by its name (“matrix”) for graphics and other operations:
  matrix.begin(0x70);
  matrix.drawRect(0, 0, 8, 8, LED_ON);
With multiple matrices, we could declare each matrix object with a distinct name:
Adafruit_8x8matrix matrixOne   = Adafruit_8x8matrix();
Adafruit_8x8matrix matrixTwo   = Adafruit_8x8matrix();
Adafruit_8x8matrix matrixThree = Adafruit_8x8matrix();
...
But we’ll usually find it easier to declare an object array. This is what the “roboface” example sketch does. There are four unique matrix addresses (remember, the two eyes share the same address), so we declare a four-element array:
Adafruit_8x8matrix matrix[4];
Each object can then be instantiated and initialized in the setup() function (using a loop if we like):
  for(uint8_t i=0; i<4; i++) {
    matrix[i] = Adafruit_8x8matrix();
    matrix[i].begin(0x70 + i);
  }
(“roboface” uses a table for the device addresses, but the principle is the same.)

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);
Don’t forget to refresh each display! Can use a loop if we like:
  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...
  };
Each “1” represents an “on” pixel, and “0” is off. Do you see it?
A few things to keep in mind with bitmaps:
  • 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.
The image on each matrix is sideways!

“Small” (1.2") and “mini” (0.8") matrices have different default orientations. With small displays, one line in the code (commented out by default) must be enabled (remove the leading slashes “//”), around line 180:

    matrix[i].setRotation(3);

This guide was first published on Oct 13, 2012. It was last updated on Mar 08, 2024.

This page (Software) was last updated on Mar 08, 2024.

Text editor powered by tinymce.