Output Devices




Group Assignment

The purpose of the group assignment this week is to measure the consumption of an output device and document how it was determined. Because of the current situation, I will be conducting the experiment individually with the equipment that I do have, for now.

*TO BE UPDATED*

Individual Assignment

The purpose is to add an output to a board that we have previously designed. As I do not have a board yet I will be working with output devices on the arduino.

I wanted to test out the MAX7219 to drive an 8x8 LED display Matrix. First thing was to understand how it works and read the data sheet. The Matrix contains an 8x8 LED sets of rows and columns that can display still or moving images or words which works by pulsating different LEDs for a short time and then shifting the rows and columns to make the object move. The dot matrix display contains numbered rows and columns with 16 pins.

The image to the left is from the datasheet showing the connections and the image on the right is showing the in and out pins. To double check the orientation of the dot matrix you can use a multimeter, on its diode check setting, and place the positive probe to pin 16 and negative probe to pin 1. Once they are touching you see that diodes in column 8 and row 5 will light up which will help you understand the orientation.

The MAX7219 has four wires that connect it to a microcontroller: clock, data, chip select and ground. Reading the datasheet was helpful to begin to understand the logic behind it. An interesting comment I found is that it contained a 8x8 static RAM that can store digits. Through looking at the data sheet, I understood that we need to use the 5V pin on the arduino rather than the 3.3V. If you only have a 3.3V device available, it is best to use the MAX6950/1, however, this device is only available in a surface mount package and cannot cascade when more than one deviced is connected.

The basice schematice of a MAX7219

The board contains the MAX7219, two capacitors, and a resistor. The capacitors are used to control the noise signals from the Vin and Gnd and the resistor is used to set an upper limit on the current fed to the diodes. It is also mentioned in some discussions that it would be more appropriate to use an external power-supply if there are more than one matrix. From the arduino we see the four connections (mentioned earlier) and then the same 4 connections that would be used to connect another matrix. SegDP-A-G correspond to the columns and Dig0-8 correspond to the rows when connected to the Matrix.

How Much Current Does It Draw?

As the drivers continue switching between the rows of the matrix about 800 times a second, it gives the impression that all the LEDs are constantly on. As explained on the arduino website, the maximum current that a single matrix will ever demand is 8 times the current you have set with the resistor, around 10mA from the MAX7219 and 20mA from the resistor. If all the LEDs are turned on at the same time, the supply will be 170mA. The USB-hub on the computer should supply up to 500mA.

PeakCurrent=(8 x LedCurrent) + MAX7219-Supply
PeakCurrent=(8 x 20mA) + 10mA = 170mA


Example #1

Understanding The Code

I began with an example sketch that scrolls text to the left using the MaxMatrix library. (linked below).

// maxmatrix-disp-scroll-text-7219
// based on
// https://code.google.com/p/arudino-maxmatrix-library/wiki/Example_Display_Scrolling_Tex
#include <MaxMatrix.h>
#include <avr/pgmspace.h>

#define maxDisplays 2
// Number of MAX7219's in use.

byte Buf7219[7]; // "width,height,data[5]" single character buffer.
const int data  = 11;     // DIN or MOSI
const int load  = 10;     // CS
const int clock = 13;     // SCK
  
MaxMatrix m(data, load, clock, maxDisplays);
// Data array is stored in program memory (see memcpy_P for access).
// Parameters are width, height, character data...
// There is a speed improvement for characters with height 8 bits see lib.

PROGMEM const unsigned char CH[] = {
3,
 8, B0000000, B0000000, B0000000, B0000000, B0000000, // space
1, 8, B1011111, B0000000, B0000000, B0000000, B0000000, // !
3, 8, B0000011, B0000000, B0000011, B0000000, B0000000, // "
5, 8, B0010100, B0111110, B0010100, B0111110, B0010100, // #
4, 8, B0100100, B1101010, B0101011, B0010010, B0000000, // $
5, 8, B1100011, B0010011, B0001000, B1100100, B1100011, // %
5, 8, B0110110, B1001001, B1010110, B0100000, B1010000, // &
1, 8, B0000011, B0000000, B0000000, B0000000, B0000000, // '
3, 8, B0011100, B0100010, B1000001, B0000000, B0000000, // (
3, 8, B1000001, B0100010, B0011100, B0000000, B0000000, // )
5, 8, B0101000, B0011000, B0001110, B0011000, B0101000, // *
5, 8, B0001000, B0001000, B0111110, B0001000, B0001000, // +
2, 8, B10110000, B1110000, B0000000, B0000000, B0000000, // ,
4, 8, B0001000, B0001000, B0001000, B0001000, B0000000, // -
2, 8, B1100000, B1100000, B0000000, B0000000, B0000000, // .
4, 8, B1100000, B0011000, B0000110, B0000001, B0000000, // /
4, 8, B0111110, B1000001, B1000001, B0111110, B0000000, // 0
3, 8, B1000010, B1111111, B1000000, B0000000, B0000000, // 1
4, 8, B1100010, B1010001, B1001001, B1000110, B0000000, // 2
4, 8, B0100010, B1000001, B1001001, B0110110, B0000000, // 3
4, 8, B0011000, B0010100, B0010010, B1111111, B0000000, // 4
4, 8, B0100111, B1000101, B1000101, B0111001, B0000000, // 5
4, 8, B0111110, B1001001, B1001001, B0110000, B0000000, // 6
4, 8, B1100001, B0010001, B0001001, B0000111, B0000000, // 7
4, 8, B0110110, B1001001, B1001001, B0110110, B0000000, // 8
4, 8, B0000110, B1001001, B1001001, B0111110, B0000000, // 9
2, 8, B01010000, B0000000, B0000000, B0000000, B0000000, // :
2, 8, B10000000, B01010000, B0000000, B0000000, B0000000, // ;
3, 8, B0010000, B0101000, B1000100, B0000000, B0000000, // <
3, 8, B0010100, B0010100, B0010100, B0000000, B0000000, // =
3, 8, B1000100, B0101000, B0010000, B0000000, B0000000, // >
4, 8, B0000010, B1011001, B0001001, B0000110, B0000000, // ?
5, 8, B0111110, B1001001, B1010101, B1011101, B0001110, // @
4, 8, B1111110, B0010001, B0010001, B1111110, B0000000, // A
4, 8, B1111111, B1001001, B1001001, B0110110, B0000000, // B
4, 8, B0111110, B1000001, B1000001, B0100010, B0000000, // C
4, 8, B1111111, B1000001, B1000001, B0111110, B0000000, // D
4, 8, B1111111, B1001001, B1001001, B1000001, B0000000, // E
4, 8, B1111111, B0001001, B0001001, B0000001, B0000000, // F
4, 8, B0111110, B1000001, B1001001, B1111010, B0000000, // G
4, 8, B1111111, B0001000, B0001000, B1111111, B0000000, // H
3, 8, B1000001, B1111111, B1000001, B0000000, B0000000, // I
4, 8, B0110000, B1000000, B1000001, B0111111, B0000000, // J
4, 8, B1111111, B0001000, B0010100, B1100011, B0000000, // K
4, 8, B1111111, B1000000, B1000000, B1000000, B0000000, // L
5, 8, B1111111, B0000010, B0001100, B0000010, B1111111, // M
5, 8, B1111111, B0000100, B0001000, B0010000, B1111111, // N
4, 8, B0111110, B1000001, B1000001, B0111110, B0000000, // O
4, 8, B1111111, B0001001, B0001001, B0000110, B0000000, // P
4, 8, B0111110, B1000001, B1000001, B10111110, B0000000, // Q
4, 8, B1111111, B0001001, B0001001, B1110110, B0000000, // R
4, 8, B1000110, B1001001, B1001001, B0110010, B0000000, // S
5, 8, B0000001, B0000001, B1111111, B0000001, B0000001, // T
4, 8, B0111111, B1000000, B1000000, B0111111, B0000000, // U
5, 8, B0001111, B0110000, B1000000, B0110000, B0001111, // V
5, 8, B0111111, B1000000, B0111000, B1000000, B0111111, // W
5, 8, B1100011, B0010100, B0001000, B0010100, B1100011, // X
5, 8, B0000111, B0001000, B1110000, B0001000, B0000111, // Y
4, 8, B1100001, B1010001, B1001001, B1000111, B0000000, // Z
2, 8, B1111111, B1000001, B0000000, B0000000, B0000000, // [
4, 8, B0000001, B0000110, B0011000, B1100000, B0000000, // backslash
2, 8, B1000001, B1111111, B0000000, B0000000, B0000000, // ]
3, 8, B0000010, B0000001, B0000010, B0000000, B0000000, // hat
4, 8, B1000000, B1000000, B1000000, B1000000, B0000000, // _
2, 8, B0000001, B0000010, B0000000, B0000000, B0000000, // `
4, 8, B0100000, B1010100, B1010100, B1111000, B0000000, // a
4, 8, B1111111, B1000100, B1000100, B0111000, B0000000, // b
4, 8, B0111000, B1000100, B1000100, B0000000, B0000000, // c // JFM MOD.
4, 8, B0111000, B1000100, B1000100, B1111111, B0000000, // d
4, 8, B0111000, B1010100, B1010100, B0011000, B0000000, // e
3, 8, B0000100, B1111110, B0000101, B0000000, B0000000, // f
4, 8, B10011000, B10100100, B10100100, B01111000, B0000000, // g
4, 8, B1111111, B0000100, B0000100, B1111000, B0000000, // h
3, 8, B1000100, B1111101, B1000000, B0000000, B0000000, // i
4, 8, B1000000, B10000000, B10000100, B1111101, B0000000, // j
4, 8, B1111111, B0010000, B0101000, B1000100, B0000000, // k
3, 8, B1000001, B1111111, B1000000, B0000000, B0000000, // l
5, 8, B1111100, B0000100, B1111100, B0000100, B1111000, // m
4, 8, B1111100, B0000100, B0000100, B1111000, B0000000, // n
4, 8, B0111000, B1000100, B1000100, B0111000, B0000000, // o
4, 8, B11111100, B0100100, B0100100, B0011000, B0000000, // p
4, 8, B0011000, B0100100, B0100100, B11111100, B0000000, // q
4, 8, B1111100, B0001000, B0000100, B0000100, B0000000, // r
4, 8, B1001000, B1010100, B1010100, B0100100, B0000000, // s
3, 8, B0000100, B0111111, B1000100, B0000000, B0000000, // t
4, 8, B0111100, B1000000, B1000000, B1111100, B0000000, // u
5, 8, B0011100, B0100000, B1000000, B0100000, B0011100, // v
5, 8, B0111100, B1000000, B0111100, B1000000, B0111100, // w
5, 8, B1000100, B0101000, B0010000, B0101000, B1000100, // x
4, 8, B10011100, B10100000, B10100000, B1111100, B0000000, // y
3, 8, B1100100, B1010100, B1001100, B0000000, B0000000, // z
3, 8, B0001000, B0110110, B1000001, B0000000, B0000000, // {
1, 8, B1111111, B0000000, B0000000, B0000000, B0000000, // |
3, 8, B1000001, B0110110, B0001000, B0000000, B0000000, // }
4, 8, B0001000, B0000100, B0001000, B0000100, B0000000, // ~
};

void setup()
{
  m.init();
  m.setIntensity(3);
}

// Scrolling Text
char string[] = "The quick brown fox juumped over the lazy DOG.;:@'+=-/&";  
void loop()
{
      
  
delay(100);
  m.shiftLeft(false, true);
  printStringWithShift(string,100);   
}

void printCharWithShift(char c, int shift_speed)
{
  if (c < 32) return;
  c -= 32;
  memcpy_P(Buf7219, CH + 7*c, 7);
  m.writeSprite(maxDisplays*8, 0, Buf7219);
  m.setColumn(maxDisplays*8 + Buf7219[0], 0);


  
for (int i=0; i<=Buf7219[0]; i++) 
  
{
    delay(shift_speed);
    m.shiftLeft(false, false);
  }
}

void printStringWithShift(char* s, int shift_speed)
{
  while (*s != 0)
  {
    printCharWithShift(*s, shift_speed);
    s++;
  }
}





This sketch has the PROGMEM qualifier which places data inside the programming memory to embed the type face which will them be called through memcpy_p(). The PROGMEM stores the data in the flash memory instead of the SRAM that is avialable in the MAX7219 so as to make sure not to fill up the SRAM if you print a lot. In the case of our example sketch above, the full alphabet and some characters are saved in the flash memory to allow us to simply type the phrase as in char string[] = "";.

To understand the void printCharWithShift function I checked the ASCII table and I looked at the html number associating the alphabet. In the void function we see that if c < 32 it "returns" meaning does nothing and detects again, else when it is = or > than 32 it subtracts 32 from the value of the character from the ASCII table, resulting in the same character saved in the PROGMEM. Once it finds the character, it then makes a copy into a buffer and then writes it to the MAX7219 using writeSprite().



a message to my lovely brother

Now that I understand how to display text and text with a shift, I would like to test with images.


Example #2

I kept all the connections the same and began looking for a tutorial on how to manipulate the LEDs to display a moving graphic. I went with a face smiling then frowning.

Understanding The Code

Using the LedControl library functions, setRow(), setColumn(), or setLed(), you can manipulate one LED at a time. In this code we are setting each row for each graphic, happy or sad face. The setRow() function allows you to plug in 3 points, the addr, row, and value. setRow(addr, row, value). The addr is the address of your matrix, and since I am only using one matrix the value will be zero in all cases. The row will begin from 0 and continue to 7 to cover all the 8 rows. Finally, the value is the state of the led true or false (1 or 0).

To make it simpler I drew out the faces first and found the corresponding rows and their values for each face

Next I set the bytes for the happy and sad face, and added a neutral from the existing example. Each byte contains 8 values that will then represent each row. Once they are set, we can call a loop function, drawFaces(), that simply calls the ledControl and sets the row from 0-7 with the bit-1 corresponding to the first row and so on. After each face there is a delay of 1000 and then jumps to the next face and keeps going.

/*

        */

        #include "LedControl.h"
        #include "binary.h"

        /*
         DIN connects to pin 12
         CLK connects to pin 11
         CS connects to pin 10
        */
        LedControl lc=LedControl(12,11,10,1);

        // delay time between faces
        unsigned long delaytime=1000;

        // happy face
        byte hf[8]= {B00111100,B01000010,B10100101,B10000001,B10100101,B10011001,B01000010,B00111100};
        // neutral face
        byte nf[8]={B00111100, B01000010,B10100101,B10000001,B10111101,B10000001,B01000010,B00111100};
        // sad face
        byte sf[8]= {B00111100,B01000010,B10100101,B10000001,B10011001,B10100101,B01000010,B00111100};

        void setup() {
          lc.shutdown(0,false);
          // Set brightness to a medium value
          lc.setIntensity(0,8);
          // Clear the display
          lc.clearDisplay(0);
        }

        void drawFaces(){
          // Display sad face
          lc.setRow(0,0,sf[0]);
          lc.setRow(0,1,sf[1]);
          lc.setRow(0,2,sf[2]);
          lc.setRow(0,3,sf[3]);
          lc.setRow(0,4,sf[4]);
          lc.setRow(0,5,sf[5]);
          lc.setRow(0,6,sf[6]);
          lc.setRow(0,7,sf[7]);
          delay(delaytime);

          // Display neutral face
          lc.setRow(0,0,nf[0]);
          lc.setRow(0,1,nf[1]);
          lc.setRow(0,2,nf[2]);
          lc.setRow(0,3,nf[3]);
          lc.setRow(0,4,nf[4]);
          lc.setRow(0,5,nf[5]);
          lc.setRow(0,6,nf[6]);
          lc.setRow(0,7,nf[7]);
          delay(delaytime);

          // Display happy face
          lc.setRow(0,0,hf[0]);
          lc.setRow(0,1,hf[1]);
          lc.setRow(0,2,hf[2]);
          lc.setRow(0,3,hf[3]);
          lc.setRow(0,4,hf[4]);
          lc.setRow(0,5,hf[5]);
          lc.setRow(0,6,hf[6]);
          lc.setRow(0,7,hf[7]);
          delay(delaytime);
        }

        void loop(){
          drawFaces();
        }
        

I placed a tissue on the matrix to be able to see the lights better, although parchment paper works best.

Example #3

I couldn't help but try the Pong Game by Alessandro Pasotti. With the same setup, you will just need to ad a 1k ohm potentiometer. Unfortunately, I only had a 10k ohm resistance value which meant that when I attempted to play each turn of the pot oved the bar with a much higher sensitivity.

it was doing much better before I touched it

Final Thoughts

Files & Useful Links