Klausj
Published © GPL3+

Charlieplexing: drive 30 LEDs with only 6 pins

Whenever you are in danger of running out of pins to drive all your LEDs this is a way to solve the problem.

AdvancedFull instructions provided3 hours1,032
Charlieplexing: drive 30 LEDs with only 6 pins

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
LED (generic)
LED (generic)
×30
Strips Grid Board, 160 mm x 100 mm Hard paper with Cu.-plating
×1
Through Hole Resistor, 10 ohm
Through Hole Resistor, 10 ohm
×6
Male-Header 36 Position 1 Row- Long (0.1")
Male-Header 36 Position 1 Row- Long (0.1")
×1

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Drill / Driver, Cordless
Drill / Driver, Cordless
jigsaw
Mini Side Cutter, 120mm Length with 25mm Jaw Capacity
Mini Side Cutter, 120mm Length with 25mm Jaw Capacity

Story

Read more

Schematics

Charlieplexing 30 LEDs driven by 6 pins

Code

Charlieplexing 30 LEDs driven by 6 pins

C/C++
/*
   Charlieplexing, 30 LEDs connected to these 6 pins:
   PORTD: pins 2 ... 7, (avoid using RX and TX)
   PORTB: pins 8 ... 13 or
   PORTC: pins A0 ... A5
   Make sure to select the proper PORT (B, C, or D):
*/

//##################
#define portSelect B
//##################

#define PORT __CONCAT(PORT,portSelect)
#define DDR __CONCAT(DDR,portSelect)
// some macros to process the #defined value
#define TOSTRING(x) __STRINGIFY(x)
#define myPort TOSTRING(portSelect)

byte low; // mask for PORTB and PORTC
void setup() {
  Serial.begin(9600);
  Serial.println(__FILE__ "\nPORT" myPort);
  if (myPort == "D") low = 4; else low = 1;
  TIMSK0 = 1 + 2; // OVF + COMPA
}

const byte N1 = 6;
const byte N = N1 * (N1 - 1);
boolean VRAM[N1][N1];

void loop() {
  // Demo-Mode (sine function):
  static float t;
  LEDs_ON(15 * (sin(t) + 1));
  t = t + 0.05;
  /*
     for real data use something like this:
     int value = analogRead(A6);
     int number = map(value, 0, 1023, 0, N - 1);
     LEDs_ON(number);
  */
  delay(6);
}

// set of { anode-pin, cathode-pin }
const byte WAYS[][2] = {
  {5, 3}, {3, 5}, {4, 3}, {3, 4}, {3, 1}, {1, 3},
  {3, 0}, {0, 3}, {3, 2}, {2, 3}, {4, 5}, {5, 4},
  {5, 1}, {1, 5}, {5, 0}, {0, 5}, {5, 2}, {2, 5},
  {4, 1}, {1, 4}, {4, 0}, {0, 4}, {4, 2}, {2, 4},
  {0, 1}, {1, 0}, {2, 1}, {1, 2}, {2, 0}, {0, 2}
};

// store actual value in "Video RAM":
void LEDs_ON(byte x) {
  for (int i = 0; i < N; i++) {
    byte anode   = WAYS[i][0];
    byte cathode = WAYS[i][1];
    VRAM[anode][cathode] = i == x;
  }
}

// Timer 0 called with TIMER0_Overflow
ISR(TIMER0_COMPA_vect) {
  static byte i;
  // activate only the PORT bits that are really used:
  byte dirs = low << i;
  PORT = dirs; // this is the positive (the other ones will be the negatives)
  // pick value from Video RAM
  for (byte j = 0; j < N1; j++) if (VRAM[i][j]) dirs = dirs | (low << j);
  DDR  = dirs;
  if (++i >= N1) i = 0; // next LED
}

Credits

Klausj
86 projects • 8 followers
Contact

Comments

Please log in or sign up to comment.