Introduction: How to Drive a Lot of LEDs From a Few Microcontroller Pins.

About: Middle aged geek username also works at yahoo.com, mac.com, comcast.net, wharton-10.arpa
Using the fact that many microcontroller pins have three states (+V, GND, or
"high impedence", you can drive N*(N-1) LEDs from N pins. So the little 8
pin microcontroller like a PIC12Fxxx or an ATtiny11 can drive 20 LEDs on
its five available output pins, and still have one pin left for some kind of input.

See also https://www.instructables.com/id/Charlieplexing-LEDs--The-theory/

Step 1: 20 LEDs on 5 Pins

The current crop of low pin-count microcontrollers (6 pins to 20 pins on
the whole package) are attractively priced and 'cute', but the question
arrises as to how you can make the best use of those pins for common
applications such as driving LEDs.

A direct-connect approach to driving LEDs consumes one pin for each
LED. A traditional multiplexing scheme where rows of LED anodes are
driven by one set of N pins and each row's common cathode is driven by
another set of M pins manages to light N*M LEDs with N+M pins.
However, on a processor with only 5 or fewer outputs (as is the case
with most 8-pin microcontrollers), this barely gets you any more
outputs than direct drive.

Step 2: Charlieplexing

Assuming the output pins are actually tri-state-able (active high,
active low, and high impedence (input)) it is also possible to share
the row and column drivers and control N*(N-1) LEDs with only N pins.
One pin is connected to common cathodes of a row of LEDs and driven
low, and the N-1 pins remaining are connected to the anodes and either
driven high to light that column, or left as inputs to leave the LED
off. Maxim calls this technique "Charlieplexing", and describes it in
(1); Microchip also mentions this in their document (2) (and
implements in on the PICKit 1 board as well.)

(1) "Charlieplexing - Reduced Pin-Count LED Display Multiplexing"
http://www.maxim-ic.com/appnotes.cfm/appnote_number/1880

(2) "Tips 'n Tricks 8-pin FLASH PIC Microcontrollers"
http://ww1.microchip.com/downloads/en/DeviceDoc/40040b.pdf

(3) Charlieplexing LEDs- The theory An Instructable by rgbphil

Step 3: Putting It to Work.

This drives 20 LEDs from an ATtiny11. An earlier version of this board was
actually built and appears as the main page photo. I'm afraid the picture
of the schematic is pretty hopeless; you need Eagle to tell you which signals
are connected where.

Step 4: Smaller and More Versatile...

Since most of the board is taken up by the LED array, we can make room
for either a Attiny chip OR a microchip PIC12F chip. Shrink the LEDs down
to 3mm and go to a double sided board, and we get something about 27x44mm

Alas, this board hasn't been tested yet...

Step 5: Itty Bitty

Microchip of course has their 6 pin PIC10F chips, capable of driving a
mere 6 LEDs from the 3 output pins. This is about 16mm in diameter.
Going to 603 LEDs lets you get a bit smaller, but I'm not sure what's the point.

Step 6: Software

The software gets a bit messy for serveral reasons:

1) for the PCBs shown, the LEDs are laid out in a way that is convenient
to the PCB layout, rather than in "correct" bit order. IMO, this is the
way to do things, but it does mean that Row 1 doesn't necessarilly mean
bit 1, or coluimn 3 doesn't mean bit 3. This requires a level of mapping
between the usual row/column addressing and the bits that need setting.

2) Since the same bits are used for anodes and cathodes, the common
(row) connection for some bits can be in the middle of driven (column)
bits. That means you have to shift column bits around depending on whether
they are before or after the row bit for that set of columns.

3) You have to derive output words for both the ioport and the port direction
register.

The attached ASM code for ATtiny11 is a "proof of concept." It's embarassingly
un-optimized and poorly commented, but it's all I've got written so far.