LED Graduation Cap

My best friend is graduating and I have decided to make him a scrolling 8x14 LED matrix for his graduation cap. I originally came up with the idea from this guy Technical How To - Graduation Cap Mod
However, he doesn't give to many details and I reached a point beyond my current abilities and I see the help from everyone from the Arduino forum.

I have searched online and I can't seem to find anything about using Arduino to directly control the LED matrix. I already have the 8x8 portion of the matrix working, but I cant seem to figure out how to get the rest of the matrix programmed. Do I set the program to the rest of the pin outs or do I have to multiplex the entire display?

I also purchased some NPN 2n2222a transistors and a PIC18f4520 but I have no idea how to hook it up and or how to program it. Ideally I would like to have the least amount of components as the unit needs to fit underneath the graduation cap. Wiring the Arduino mega directly would be the best solution.

I would appreciate it if someone here could help me out and direct me to the right information to get my 8X14 LED matrix fully working. I would love to see my best friend with the only LED matrix at his college.

Thanks! :slight_smile:

I have attached pictures of what I have going so far:

How about a schematic of what you've done so far?

If you make it a 7 x 11 (characters: 5 x 7 's) you have the potential for 2 characters on screen (with 1 column space) as it scrolls (I presume).
You'd present the rows' pixels and enable the Column (via its driver / transistor.)

I mainly followed Andrew's write up on wiring a 8X8 LED Matrix to an R3. I dont have any schematics written out for wiring the PIC18f4520 and the NPN Transistors.

I wish there was a write up somewhere, but I dont know where to start.

An "R3" == Arduino Uno R3?

"Andrew" has another 1000+ days till graduation - and it shows:
"You should also have 16 2N 2222A transistors. 16 of your digital outputs will be used to control the transistors (connected to the gate) and the other 16 are directly connected to the cathodes. The collector of the transistors should be wired to +5V and the emitter to the anodes. A high signal to the transistor and a low signal to the cathode will allow current to flow through the LED.

"I did not include any resistor into my circuit because I wanted maximum brightness over longevity of LED. Yes, the LED will probably burn out faster, but I wanted the brightness. Furthermore, I'm going to be scanning through the rows anyway, so the LEDs are really only on at most 1/16th of the time and not continuous operation. Well, that's the theory anyway."

Well, he has the transistors wired as sacrificial pass transistors for the column anodes. So you enable the column and then dump the pixels for each row (LOW = "On"), and go for broke, flying by the seat of your flaming pants!

I don't understand what you mean by

Do I set the program to the rest of the pin outs or do I have to multiplex the entire display?

Why wouldn't you multiplex the entire display?

I suppose I dont have full grasp as to how I should multiplex the LEDs. Do you could give me a schematic of how I am supposed to wire the LEDs to the transistors and then to the microprocessor? I hope this isn't much to ask as this is my first time doing this. I really appreciate your help.

Another thing that I dont have a full grasp of would be how to program the PIC18f4520 using the Arduino R3 mega?

So, the picture in your original post, you have something going there.
It's using an Arduino Mega?
You're not going to use that?

What I was trying to get at before, suggesting that you re-scale your project to a 7 x 11 matrix, would require 18 output pins, which the Arduino Uno's microcontroller (ATmega328) is fully capable.

autostrada048:
Another thing that I dont have a full grasp of would be how to program the PIC18f4520 using the Arduino R3 mega?

I don't know anything about that. PIC isn't Arduino, it's PIC. They likely have their own programming hardware and so on. How is it that you came to understand that the Mega is used to programme PICs?

I thought that graduation was last week, but if it's next week you may miss the boat.

I am no longer using the r3 plus because I do not have enough pins to control my 8x14 matrix. That is why I purchased the arduino MEGA r3 plus and decided to go with that. I originally thought that it would be easier to use the mega r3 plus directly, but I cannot figure out where to put the pins. I thought that I would just be able to line up the pins in sequence but after looking at Andrews pinout it seems to not be the case.

I would much rather use my mega r3 plus, if only I knew how to wire it up to my matrix. I just don't know where to put the last six cathode columns and or how to modify the 8x8 program to control the 8x14 matrix.

autostrada048:
I would much rather use my mega r3 plus, if only I knew how to wire it up to my matrix. I just don't know where to put the last six cathode columns and or how to modify the 8x8 program to control the 8x14 matrix.

I asked a few Replies ago how you have what you've got connected already. What pins are you using? Andrew's? He's using a PIC and you're using a Mega, so everyone ought to automagically know what you're doing?
Why not Post the programme that you're using now?

I used these pinouts to connect to my OSEPP™ Mega 2560 R3 Plus to my LED matrix.

I'm sorry for the mix up I'm just a little confused as to what information i need to give and this is the program that I am using currently

/*
 * Show messages on an 8x8 led matrix,
 * scrolling from right to left.
 *
 * Uses FrequencyTimer2 library to
 * constantly run an interrupt routine
 * at a specified frequency. This
 * refreshes the display without the
 * main loop having to do anything.
 *
 */

#include <FrequencyTimer2.h>

#define SPACE { \
    {0, 0, 0, 0, 0, 0, 0, 0},  \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0} \
}

#define H { \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 1, 1, 1, 1, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}  \
}

#define E  { \
    {0, 1, 1, 1, 1, 1, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 1, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 1, 1, 0}  \
}

#define L { \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 0, 0}, \
    {0, 1, 1, 1, 1, 1, 1, 0}  \
}

#define O { \
    {0, 0, 0, 1, 1, 0, 0, 0}, \
    {0, 0, 1, 0, 0, 1, 0, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 1, 0, 0, 0, 0, 1, 0}, \
    {0, 0, 1, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 1, 1, 0, 0, 0}  \
}

byte col = 0;
byte leds[8][8];

// pin[xx] on led matrix connected to nn on Arduino (-1 is dummy to make array start at pos 1)
int pins[17]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6};

// col[xx] of leds = pin yy on led matrix
int cols[8] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16]};

// row[xx] of leds = pin yy on led matrix
int rows[8] = {pins[9], pins[14], pins[8], pins[12], pins[1], pins[7], pins[2], pins[5]};

const int numPatterns = 6;
byte patterns[numPatterns][8][8] = {
  H,E,L,L,O,SPACE
};

int pattern = 0;

void setup() {
  // sets the pins as output
  for (int i = 1; i <= 16; i++) {
    pinMode(pins[i], OUTPUT);
  }

  // set up cols and rows
  for (int i = 1; i <= 8; i++) {
    digitalWrite(cols[i - 1], LOW);
  }

  for (int i = 1; i <= 8; i++) {
    digitalWrite(rows[i - 1], LOW);
  }

  clearLeds();

  // Turn off toggling of pin 11
  FrequencyTimer2::disable();
  // Set refresh rate (interrupt timeout period)
  FrequencyTimer2::setPeriod(2000);
  // Set interrupt routine to be called
  FrequencyTimer2::setOnOverflow(display);

  setPattern(pattern);
}

void loop() {
    pattern = ++pattern % numPatterns;
    slidePattern(pattern, 60);
}

void clearLeds() {
  // Clear display array
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = 0;
    }
  }
}

void setPattern(int pattern) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = patterns[pattern][i][j];
    }
  }
}

void slidePattern(int pattern, int del) {
  for (int l = 0; l < 8; l++) {
    for (int i = 0; i < 7; i++) {
      for (int j = 0; j < 8; j++) {
        leds[j][i] = leds[j][i+1];
      }
    }
    for (int j = 0; j < 8; j++) {
      leds[j][7] = patterns[pattern][j][0 + l];
    }
    delay(del);
  }
}

// Interrupt routine
void display() {
  digitalWrite(cols[col], LOW);  // Turn whole previous column off
  col++;
  if (col == 8) {
    col = 0;
  }
  for (int row = 0; row < 8; row++) {
    if (leds[col][7 - row] == 1) {
      digitalWrite(rows[row], LOW);  // Turn on this led
    }
    else {
      digitalWrite(rows[row], HIGH); // Turn off this led
    }
  }
  digitalWrite(cols[col], HIGH); // Turn whole column on at once (for equal lighting times)
}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

Using that on your creation there makes it do HELLO ?

That GIF shows the pin numbers and all for a matrix module, but you're using discrete LEDs.
Also note which Arduino (Mega) pins you have connected to which Columns and to which Rows.

Yes, the program allows me to display the word HELLO on the LED matrix. I also have made some custom letters that I added on my own, so I am not limiting what the matrix can display.

Here are the pinouts that I used in order to allow the LED matrix that I created to Connect to my OSEPP™ Mega 2560 R3 Plus:

Columns:
1 - Pin 9
2 - Pin 3
3 - Pin 2
4 - Pin 12
5 - Pin 15
6 - Pin 11
7 - Pin 7
8 - Pin 6

Rows:
1 - Pin 13
2 - Pin 8
3 - Pin 18
4 - Pin 10
5 - Pin 5
6 - Pin 17
7 - Pin 4
8 - Pin 14

OK
Thanks for adding that info, I was trying to anticipate problems.

You can pick whichever outputs, it's your choice, it's a matter of integrating that into the pins[] array
int pins[17]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6,};

So, if you were going to use Digital 18-23 for the additional 8 columns:
int pins[23]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6, 18, 19, 20, 21, 22, 23};

and the related col[] array:
int cols[8] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16]};
should then be
int cols[14] = {pins[13], pins[3], pins[4], pins[10], pins[06], pins[11], pins[15], pins[16], pins[17], pins[18], pins[19], pins[20], pins[21], pins[22]};

Your char defines have to be reformatted / redefined to show the add'l columns.

There are many other modifications to be made: declaring the add'l pins as OUTPUTs; wherever there's a for loop involving the COLs counting to "8" should be changed to "14"; and so on.

That worked and the LEDs are working, but i'm still having trouble converting the program to work with the 8x14 matrix.

how do I get the text to start at column 14? the text is currently mirroring the last 6 rows with the first 8 LEDs.

autostrada048:
That worked...

Which or what "that" do you mean?
Let's get specific: Post Your Code ! **[**Inside code tags -- click that # gadget and paste your code between the two prompts [ code ] [ /code ] ]

As I posted last time out,

[quote author=Runaway Pancake]Your char defines have to be reformatted / redefined to show the add'l columns.

There are many other modifications to be made: declaring the add'l pins as OUTPUTs; wherever there's a for loop involving the COLs counting to "8" should be changed to "14"; and so on.[/quote]

{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 1, 1, 1, 1, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0}
must now become
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0} \

Is that thing supposed to scroll or what? I think the 8x8 just put up one letter at a time. What's the grand plan, why the 14 columns?

I was able to get everything to work before the graduation! Thank YOU!

here is the code that I ended up using.

/*
 * Show messages on an 8x8 led matrix,
 * scrolling from right to left.
 *
 * Uses FrequencyTimer2 library to
 * constantly run an interrupt routine
 * at a specified frequency. This
 * refreshes the display without the
 * main loop having to do anything.
 *
 */

#include <FrequencyTimer2.h>

#define SPACE { \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} \
}

#define HIRE1 { \
    {1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0}, \
    {1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \
    {1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \
    {1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \
    {1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \
    {1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \
    {1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \
    {1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0}, \
}


#define HIRE2  { \
    {1,1,1,1,0,0,0,1,1,1,1,1,0,0}, \
    {1,0,0,0,1,0,0,1,0,0,0,0,0,0}, \
    {1,0,0,0,1,0,0,1,0,0,0,0,0,0}, \
    {1,0,0,0,1,0,0,1,1,1,1,1,0,0}, \
    {1,1,1,1,0,0,0,1,0,0,0,0,0,0}, \
    {1,0,1,0,0,0,0,1,0,0,0,0,0,0}, \
    {1,0,0,1,0,0,0,1,0,0,0,0,0,0}, \
    {1,0,0,0,1,0,0,1,1,1,1,1,0,0}  \
}

#define ME1 { \
    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1}, \
    {0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1}, \
    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1}  \
}

#define ME2 { \
    {1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, \
    {1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
    {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}, \
    {1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}  \
}

byte col = 0;
byte leds[8][14];

// pin[xx] on led matrix connected to nn on Arduino (-1 is dummy to make array start at pos 1)
int pins[23]= {-1, 5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6, 22, 24, 26, 28, 30, 32};

// col[xx] of leds = pin yy on led matrix
int cols[14] = {pins[16], pins[15], pins[11], pins[06], pins[10], pins[04], pins[03], pins[13]};

// row[xx] of leds = pin yy on led matrix
int rows[14] = {pins[22], pins[21], pins[20], pins[19], pins[18], pins[17], pins[9], pins[14], pins[8], pins[12], pins[1], pins[7], pins[2], pins[5]};

const int numPatterns = 4;
byte patterns[numPatterns][8][14] = {
  HIRE1,HIRE2,ME1,ME2
};




int pattern = 0;

void setup() {
  // sets the pins as output
  for (int i = 1; i <= 22; i++) {
    pinMode(pins[i], OUTPUT);
  }

  // set up cols and rows
  for (int i = 1; i <= 8; i++) {
    digitalWrite(cols[i - 1], LOW);
  }

  for (int i = 1; i <= 14; i++) {
    digitalWrite(rows[i - 1], LOW);
  }

  clearLeds();

  // Turn off toggling of pin 11
  FrequencyTimer2::disable();
  // Set refresh rate (interrupt timeout period)
  FrequencyTimer2::setPeriod(2000);    
  // Set interrupt routine to be called
  FrequencyTimer2::setOnOverflow(display);

  setPattern(pattern);
}

void loop() {
    pattern = ++pattern % numPatterns;
    slidePattern(pattern, 75);
}

void clearLeds() {
  // Clear display array
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 14; j++) {
      leds[i][j] = 0;
    }
  }
}

void setPattern(int pattern) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 14; j++) {
      leds[i][j] = patterns[pattern][i][j];
    }
  }
}

void slidePattern(int pattern, int del) {
  for (int l = 0; l < 14; l++) {
    for (int i = 0; i < 14; i++) {
      for (int j = 0; j < 8; j++) {
        leds[j][i] = leds[j][i+1];
      }
    }
    for (int j = 0; j < 14; j++) {
      leds[j][13] = patterns[pattern][j][0 + l];
    }
    delay(del);
  }
}

// Interrupt routine
void display() {
  digitalWrite(cols[col], LOW);  // Turn whole previous column off
  col++;
  if (col == 8) {
    col = 0;
  }
  for (int row = 0; row < 14; row++) {
    if (leds[col][13 - row] == 1) {
      digitalWrite(rows[row], LOW);  // Turn on this led
    }
    else {
      digitalWrite(rows[row], HIGH); // Turn off this led
    }
  }
  digitalWrite(cols[col], HIGH); // Turn whole column on at once (for equal lighting times)
}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

I was wondering how you were doing, you dropped carrier.
Well, to me, Columns are up and down, Rows are across, but the cols/rows arrays are the other way round.
But it looks like you got what you needed going, and your friend there looks impressed.

Everyone was impressed. He was the only person at the graduation with the scrolling LED hat. As for the code it seemed as if I had mixed up my soldering for the LED matrix and had the rows and columns mixed up. After I had figured that out everything was smooth sailing. I just needed to change the values accordingly and my array was in full working order.

I just wanted to say thank you again for your help.