Direct Drive LED Matrix
Note: DON’T FORGET CURRENT-LIMITING RESISTORS.
See here for an example of using resistors: http://www.instructables.com/id/Multiplexing-with-Arduino-and-the-74HC595/step8/Current-Limiting-Resistors/
Click here for YouTube video
Sample code for scrolling messages (needs FrequencyTimer2 library):
/* * 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) }
Sample code for “Life” (needs FrequencyTimer2 library):
/* * Conway's "Life" * * Adapted from the Life example * on the Processing.org site * * Needs FrequencyTimer2 library */ #include <FrequencyTimer2.h> 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]}; #define DELAY 0 #define SIZE 8 extern byte leds[SIZE][SIZE]; byte world[SIZE][SIZE][2]; long density = 50; void setup() { setupLeds(); randomSeed(analogRead(5)); for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (random(100) < density) { world[i][j][0] = 1; } else { world[i][j][0] = 0; } world[i][j][1] = 0; } } } void loop() { // Display current generation for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { leds[i][j] = world[i][j][0]; } } delay(DELAY); // Birth and death cycle for (int x = 0; x < SIZE; x++) { for (int y = 0; y < SIZE; y++) { // Default is for cell to stay the same world[x][y][1] = world[x][y][0]; int count = neighbours(x, y); if (count == 3 && world[x][y][0] == 0) { // A new cell is born world[x][y][1] = 1; } if ((count < 2 || count > 3) && world[x][y][0] == 1) { // Cell dies world[x][y][1] = 0; } } } // Copy next generation into place for (int x = 0; x < SIZE; x++) { for (int y = 0; y < SIZE; y++) { world[x][y][0] = world[x][y][1]; } } } int neighbours(int x, int y) { return world[(x + 1) % SIZE][y][0] + world[x][(y + 1) % SIZE][0] + world[(x + SIZE - 1) % SIZE][y][0] + world[x][(y + SIZE - 1) % SIZE][0] + world[(x + 1) % SIZE][(y + 1) % SIZE][0] + world[(x + SIZE - 1) % SIZE][(y + 1) % SIZE][0] + world[(x + SIZE - 1) % SIZE][(y + SIZE - 1) % SIZE][0] + world[(x + 1) % SIZE][(y + SIZE - 1) % SIZE][0]; } void setupLeds() { // 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 and 3 FrequencyTimer2::disable(); // Set refresh rate (interrupt timeout period) FrequencyTimer2::setPeriod(2000); // Set interrupt routine to be called FrequencyTimer2::setOnOverflow(display); } void clearLeds() { // Clear display array for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { leds[i][j] = 0; } } } // 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) }
Possible Alternative on Arduino 0015 using the Timer1 library
This example, made at a workshop at DKDS in April 2009, and debugged in May, uses Arduino 0015 and the Timer1 Library on the same Hardware setup to address the different LEDs in the matrix in an elegant way.
/* * _8x8 LED matrix * * (c) 2009 BlushingBoy.net */ #include "TimerOne.h" byte rows[8] = {9, 14, 8, 12, 1, 7, 2, 5}; byte cols[8] = {13, 3, 4, 10, 6, 11, 15, 16}; byte pins[16] = {5, 4, 3, 2, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6}; byte screen[8] = {0, 0, 0, 0, 0, 0, 0, 0}; volatile byte screenRow = 0; volatile byte screenCol = 0; void setup() { Timer1.initialize(100); for (int i = 2; i <= 17; i++) pinMode(i, OUTPUT); Timer1.attachInterrupt(doubleBuffer); } // interrupt routine void doubleBuffer() { // reset the previous iteration digitalWrite(translatePin(rows[screenRow]), HIGH); // set previous off digitalWrite(translatePin(cols[screenCol]), LOW); // set previous off // go to the next iteration... // go to the next screenCol, wrap if necessary screenCol++; if (screenCol >= 8) { screenCol = 0; // when screenCol wraps, go to the next screenRow, wrap if necessary screenRow++; if (screenRow >= 8) { screenRow = 0; } } // set this iteration if((screen[screenRow]>>screenCol)&B1 == B1) { digitalWrite(translatePin(rows[screenRow]), LOW); // set this on digitalWrite(translatePin(cols[screenCol]), HIGH); // set this on } else { digitalWrite(translatePin(rows[screenRow]), HIGH); // set this off digitalWrite(translatePin(cols[screenCol]), LOW); // set this off } } byte translatePin(byte original) { return pins[original - 1]; } void allOFF() { for (int i = 0; i < 8; i++) screen[i]=0; } void on(byte row, byte column) { screen[column-1] |= (B1<<(row-1)); } void off(byte row, byte column) { screen[column-1] &= ~(B1<<(row-1)); } // looping some LEDs routine void loop() { allOFF(); delay(1000); on(3,3); on(3,4); on(3,5); on(3,6); delay(400); allOFF(); delay(1000); on(4,4); delay(400); }