Recent from talks
Nothing was collected or created yet.
Charlieplexing
View on Wikipedia

Charlieplexing (also known as tristate multiplexing, reduced pin-count LED multiplexing, complementary LED drive and crossplexing) is a technique for accessing a large number of LEDs, switches, micro-capacitors or other I/O entities, using relatively few tri-state logic wires from a microcontroller. These I/O entities can be wired as discrete components,[1][2] x/y arrays,[3][4] or woven in a diagonally intersecting pattern to form diagonal arrays.[5]
Etymology
[edit]Although the technique was introduced in 2001 by Maxim Integrated, the name "Charlieplexing", however, first occurred in a 2003 application note.[6] It was named after Charles "Charlie" M. Allen, an applications engineer of MAX232 fame,[7][8][9] who had proposed this method internally.[when?]
How and why to use Charlieplexing
[edit]The simplest way to address a single pixel (or input button) is to run a wire out to it and another wire back to ground, but this requires a lot of wiring. A slight improvement is to have everything return on a common ground, but this still requires one wire (and one pin on the microcontroller) for each pixel or button. For an X by Y array, X*Y pins are required.
With tri-state logic pins (high, low, disconnected), matrix wiring needs only X+Y pins and wires. Each X and each Y take turns being on vs being disconnected; the disadvantage is that each light is only powered at most 1/(X*Y) of the time. If there is enough fan-out, the Y pins can be left always on, and all checked in parallel. The refresh can then happen every 1/X of the time, but the X wires each need to pass enough current to light up Y lights at once.
Charlieplexing is a further improvement on matrix wiring, which enables the I/O entities (LEDs, switches etc.) to be connected between any two microcontroller I/O pins. Instead of X horizontal wires meeting Y vertical wires, every wire meets every other wire. Assuming diodes are used for the connections (to distinguish between wire A going to wire B vs wire B going to wire A), Charlieplexing needs only about half as many pins as a conventional matrix arrangement, at the cost of more complicated mapping. Alternatively, the same number of pins will support a display nearly four times (doubling in both directions) as large.
| Vcc | GND | Hi-Z | Matrix | Switch | LED |
|---|---|---|---|---|---|
| 1 | 2 | 3,4 | No | Yes | Yes |
| 2 | 1 | 3,4 | No | duplicate | Yes |
| 1 | 3 | 2,4 | Yes | Yes | Yes |
| 3 | 1 | 2,4 | duplicate | duplicate | Yes |
| 1 | 4 | 2,3 | Yes | Yes | Yes |
| 4 | 1 | 2,3 | duplicate | duplicate | Yes |
| 2 | 3 | 1,4 | Yes | Yes | Yes |
| 3 | 2 | 1,4 | duplicate | duplicate | Yes |
| 2 | 4 | 1,3 | Yes | Yes | Yes |
| 4 | 2 | 1,3 | duplicate | duplicate | Yes |
| 3 | 4 | 1,2 | No | Yes | Yes |
| 4 | 3 | 1,2 | No | duplicate | Yes |
For example, with 4 I/O pins, standard x/y matrix multiplexing distinguishes only 4 positions. Pins representing the same direction (such as 1 and 2) can never pair with each other.
With Charlieplexing, each pin can pair with any other pin, so those same 4 I/O pins have 6 unique pairings: all those available to matrix multiplexing, but also (1 to 2) and (3 to 4).
Because the microcontroller can send current in either direction, and diodes can filter out one direction, each connection can address two diodes separately. In this example, 4 pins with six connections can identify 12 independent diodes. Doubling connections with diodes isn't unique to Charlieplexing, but is rarely done unless I/O pins are scarce enough to at least consider Charlieplexing.
Although Charlieplexing is more efficient in its use of I/O lines, the mapping from I/O lines to a physical location is usually more complicated.
Other issues that affect standard multiplexing but are exacerbated by Charlieplexing include:
- consideration of current requirements and the forward voltages of the LEDs.
- a requirement to cycle through the in-use LEDs rapidly so that the persistence of the human eye perceives the display to be lit as a whole. Multiplexing can generally be seen by a strobing effect and skewing if the eye's focal point is moved past the display rapidly.
Origin
[edit]The Charlieplexing technique was introduced[6] by Maxim Integrated in 2001[10] as a reduced pin-count LED multiplexing scheme in their MAX6951 LED display driver.[10][6]
Also in 2001, when the name "Charlieplexing" became common, Don Lancaster illustrated the method as part of his musings about the "N-connectedness" problem,[11] referring to Microchip Technology,[11] who had already discussed it as "complementary LED drive technique" in a 1998 application note[12] and would later include it in a tips & tricks booklet.[13]
While Microchip did not mention the origin of the idea, they might have picked it up in the PICLIST, a mailing list on Microchip PIC microcontrollers, where, also in 1998, Graham Daniel[14][15] proposed it to the community as a method to drive rows and columns of bidirectional LEDs. Daniel at the time had created simple circuits with PIC 12C508 chips driving 12 LEDs off 5 pins with a mini command set to set various lighting displays in motion.[14][15]
The method, however, was known and utilized by various parties much earlier in the 1980s, and has been described in detail as early as in 1979 in a patent by Christopher W. Malinowski, Heinz Rinderle and Martin Siegle of the Department of Research and Development, AEG-Telefunken, Heilbronn, Germany for what they called a "three-state signaling system".[16]
Reportedly, similar techniques were already in use as early as 1972 for track signaling applications in model railroading.[17][citation needed]
Display multiplexing is very different from multiplexing used in data transmission, although it has the same basic principles. In display multiplexing, the data lines of the displays are connected in parallel to a common databus on the microcontroller. Then, the displays are turned on and addressed individually. This allows the use of fewer I/O pins than it would normally take to drive the same number of displays directly. Here, each "display" could, for instance, be one calculator digit, not the complete array of digits.
With traditional multiplexing I/O pins can drive a maximum of LEDs, or listen to that many input switches. Charlieplexing can drive LEDs, or listen to buttons even if directionality is not enforced by a diode.
Tri-state multiplexing (Charlieplexing)
[edit]
The Charlieplexing configuration may be viewed as a directed graph, where the drive pins are vertices and the LEDs are directed edges; there is an outward-pointing edge connected from each vertex to each other vertex, hence with n drive pins there are (n)(n-1) total edges (a pronic number). This equates to n pins being able to drive n2 − n segments or LEDs.
| Pins | LEDs |
|---|---|
| 2 | 2 |
| 3 | 6 |
| 4 | 12 |
| 5 | 20 |
| 6 | 30 |
| 7 | 42 |
| 8 | 56 |
| 9 | 72 |
| 10 | 90 |
| 11 | 110 |
| 12 | 132 |
| 13 | 156 |
| 14 | 182 |
| 15 | 210 |
| 16 | 240 |
| 20 | 380 |
| 24 | 552 |
| 32 | 992 |
| 40 | 1,560 |
| 48 | 2,256 |
| 56 | 3,080 |
| 64 | 4,032 |
| n | n2 − n |
If the number of LEDs (L) is known, then the number of pins (n) can be found from the equation: , the result being rounded to the nearest whole number.[nb 1]
Example: If L = 57, then √L = 7.549, and 1 + √L = 8.549; the nearest whole number to this is 9, so 9 pins are needed to drive 57 LEDs (9 pins could drive up to 72 LEDs, but 8 pins could drive only 56 LEDs at most).
If L = 56, then √L = 7.483, and 1 + √L = 8.483; the nearest whole number to this is 8, so 8 pins are needed to drive 56 LEDs.
- Origin of the (n2 − n) equation in Charlieplexing

Unlike in a traditional x/y multiplexed array, where a sub-set of conductive elements crosses a different sub-set of conductive elements, in a "fully Charlieplexed" multiplexed array, each conductive element crosses every other conductive element.
Six (n) conductive elements in a standard x/y multiplexed array forms a maximum of nine ((n / 2)2) unique intersections (see figure on far left).
The other diagrams also show six (n) conductive elements, but here all six elements cross over themselves, forming a multiplexed array of 36 (n2) intersections. LEDs are shown placed at every intersection. However, each conductor also crosses itself at the diagonal. Horizontal conductor 1 crosses vertical conductor 1, horizontal conductor 2 crosses vertical conductor 2, etc. This means that six of these LEDs are short-circuited (e.g. D1 and D5 are short-circuited). The six (n) diagonal LEDs will, therefore, never light up, because no voltage can ever develop across them, so (n) has to be subtracted from the total. There is no point in installing these LEDs (they are simply included here for illustrative purposes).
This leaves 30 LEDs (n2 − n) that can be uniquely addressed and lit up independently.
Conductor "a" crossing conductor "b" is distinguishable from conductor "b" crossing conductor "a" because LED polarity is reversed. For example, when conductor 3 is positive and conductor 2 is negative, current flows through, and lights up LED D8, but when conductor 3 is negative and conductor 2 is positive, current flows through, and lights up LED D9.
These reverse polarity LED pairs are called complementary pairs. This diagram has 15 complementary pairs, allowing 30 LEDs to be lit independently.

The 6 unusable diagonal LEDs can be conveniently replaced by actual bidirectional shortcuts (so that there's no longer need to set up the interconnection lines grouped on the left and bottom of the diagrams, to drive the bottom input of vertical connectors from the matching left input of horizontal connectors).
By adjusting diagonally the form of horizontal and vertical connectors along the short-circuited main diagonal of the original matrix, this can be easily transformed into an array of 5 × 6 or 6 × 5 LEDs arranged on a regular grid.
A similar pattern could be used for a 10 × 11 matrix that could be used to drive up to 110 keys (including a few indicator LEDs) on a modern PC keyboard, where each key switch includes a small serial diode or LED, so that only 11 pins would be needed to individually control all of them (these individual diodes or LEDs inside each key switch would also avoid all common and undesirable "ghosting" effects, that are hard to eliminate completely when an arbitrary number of keys at any position are pressed at the same time).
Charlieplexing can also be used to significantly reduce the number of controlling pins for much larger matrixes, such as modern digital displays with high resolution. E.g. for a 4K RGB display at 3840 × 2160, this requires more than 8 millions individually addressable pixels, each featuring at least 3 colored LEDs or LCD cells, for a total of nearly 25 millions LEDs or LCD cells. Using a conventional x/y multiplexing would require at least (3840 + 2160 × 3) = 10320 controlling pins and many selection chips for controlling rows and columns all around the panel of LEDs or LCD cells. But with Charlieplexing, this can be reduced to only 63 controlling pins for the selection gate of display columns, plus 46 × 3 controlling pins for the selection and power-activation of RGB display rows, by a single transistor for each row or column (possibly with an extra common shielding ground to limit their mutual coupling); these controlling pins can easily fit around the output pins of one or two controller chips, even if we add the few additional pins needed on the controller for power, ground, clocks and I/O buses, surface-mounted with a high density and low cost on a single-layer PCB, and no need of complex routing and interconnection holes between layers; a dual layer is needed only for the basic Charlieplexing matrix mounted on borders of the panel itself.
Positions in the Charlieplexed matrix are not reduced to be just LEDs or diodes, they can be filled as well by two pins of a transistor (including its gate pin) so that its third pin is used as output to further control other devices, such as the horizontal and vertical selection lines of a large flat display panel (in that case, the two Charlieplexed matrices of transistors controlling and activating the rows or columns of the panel will be smartly arranged all along a border of that panel).
Complementary drive
[edit]Charlieplexing in its simplest form works by using a diode matrix of complementary pairs of LEDs. The simplest possible Charlieplexed matrix would look like this:


By applying a positive voltage to pin X1 and grounding pin X2, LED 1 will light. Since current cannot flow through LEDs in reverse direction at this low voltage, LED2 will remain unlit. If the voltages on pin X1 and pin X2 are reversed, LED 2 will light and LED1 will be unlit.
The Charlieplexing technique does not actually make a larger matrix possible when only using two pins, because two LEDs can be driven by two pins without any matrix connections, and without even using tri-state mode. In this two-LED example, Charlieplexing would save one ground wire, which would be needed in a common 2-pin driver situation.
However, the 2-pin circuit serves as a simple example to show the basic concepts before moving on to larger circuits where Charlieplexing actually shows an advantage.
Expanding: tri-state logic
[edit]If the circuit above were to be expanded to accommodate three pins and six LEDs, it would look like this:


This presents a problem, however: In order for this circuit to act like the previous one, one of the pins must be disconnected before applying charge to the remaining two. If, for example, LED 5 was intended to be lit, X1 must be charged and X3 must be grounded. However, if X2 is also charged, LED 3 would illuminate as well. If X2 was instead grounded, LED1 would illuminate, meaning that LED 5 cannot be lit by itself. This can be solved by utilizing the tri-state logic properties of microcontroller pins.
Microcontroller pins generally have several possible states:
- "output": the pin "drives". It can drive "high" (often 5 V) or "low" (usually 0 V).
- "input": the pin does not intentionally drive at all, but instead senses what some other device (or pin) is driving. It may draw current while doing so.
- "high-Z": the pin is in a high-impedance state. Essentially, it is disconnected from the circuit; it will neither drive nor draw any current.
This allows the circuit to see any number of pins connected at any time, simply by changing the state of the pins. In order to drive the six-LED matrix above, the two pins corresponding to the LED to be lit are connected to 5 V (I/O pin "high" = binary number 1) and 0 V (I/O pin "low" = binary 0), while the third pin is set in its high-impedance state.
In doing so, current leakage out of the third pin is prevented, ensuring that the LED which should be lit is the only one lit.
Because the a diode (such as a LED) reduces the voltage available in series, current will not flow across alternate paths (an alternate 2-LED path exists for every pair of pins in the 3-pin diagram, for example), so long as the voltage drop in the desired LED path is less than the total voltage drop across each string of alternative LEDs. However, in the variant with individual resistors this voltage-regulating effect does not affect the alternative paths so all LEDs used will not have to be lit with half the supply voltage applied because this variant does not benefit from the voltage-regulating effect of the desired path LED.
By using tri-state logic, the matrix can theoretically be expanded to any size, as long as pins are available. For n pins, n(n − 1) LEDs can be in the matrix. Any LED can be lit by applying 5 V and 0 V to its corresponding pins and setting all of the other pins connected to the matrix to high-impedance mode. Under the same constraints as discussed above up to n − 1 LEDs sharing a common positive or negative path can be lit in parallel.
Expanding
[edit]The 3-wire circuit can be rearranged to this near-equivalent matrix (resistors have been relocated).


This emphasizes the similarities between ordinary grid multiplex and Charlieplex, and demonstrates the pattern that leads to "the n-squared minus n" rule.
In typical usage on a circuit board the resistors would be physically located at the top of the columns and connected to the input pin. The rows would then be connected directly to the input pin bypassing the resistor.
The first setup in the image on the left is suitable only when identical LEDs are used since a single resistor is used for current-limiting through more than one LED (though not at the same time—rather, one resistor limits current through only one LED in a given column at one time). This is contrasted to the second configuration with individual resistors for each LED, as shown in the image on the right. In this second configuration, each LED has a unique resistor paired with it. This makes it possible to mix different kinds of LEDs by providing each with its appropriate resistor value.
In both of these configuration, as shown in both the left and the right image, the relocated resistors make it possible to light multiple LEDs at the same time row-by-row, instead of requiring that they be lit individually. The row current capacity could be boosted by an NPN emitter follower BJT transistor instead of driving the current directly with the typically much weaker I/O pin alone.
Problems with Charlieplexing
[edit]Refresh rate
[edit]Refresh rate is not a problem if Charlieplexed Active matrix addressing is used with a Charlieplexed LED array.[18]
In common with x/y multiplexing, however, there can be refresh rate issues if passive matrix addressing is used.
Because only a single set of LEDs, all having a common anode or cathode, can be lit simultaneously without turning on unintended LEDs, Charlieplexing requires frequent output changes, through a method known as multiplexing. When multiplexing is done, not all LEDs are lit quite simultaneously, but rather one set of LEDs is lit briefly, then another set, and eventually the cycle repeats. If it is done fast enough, they will appear to all be on, all the time, to the human eye because of persistence of vision. In order for a display to not have any noticeable flicker, the refresh rate for each LED must be greater than the Flicker fusion threshold; 50 Hz is often used as an approximation.
As an example, 8 tri-state pins are used to control 56 LEDs through Charlieplexing, which is enough for 8 7-segment displays (without decimal points). Typically, 7-segment displays are made to have a common cathode, sometimes a common anode, but without loss of generality a common cathode is assumed in the following: All LEDs in all 8 7-segment displays cannot be turned on simultaneously in any desired combination using Charlieplexing. It is impossible to get 56 bits of information directly from 8 trits (the term for a base-3 character, as the pins are 3-state) of information, as 8 trits fundamentally comprises 8 log23, or about 12.7 bits of information, which falls far short of the 56 bits required to turn all 56 LEDs on or off in any arbitrary combination. Instead, the human eye must be fooled by use of multiplexing.
Only one 7-segment display, one set of 7 LEDs can be active at any time. The way this would be done is for the 8 common cathodes of the 8 displays to each get assigned to its own unique pin among the 8 I/O ports. At any time, one and only one of the 8 controlling I/O pins will be actively low, and thus only the 7-segment display with its common cathode connected to that actively low pin can have any of its LEDs on. That is the active 7-segment display. The anodes of the 7 LED segments within the active 7-segment display can then be turned on in any combination by having the other 7 I/O ports either high or in high-impedance mode, in any combination. They are connected to the remaining 7 pins, but through resistors (the common cathode connection is connected to the pin itself, not through a resistor, because otherwise the current through each individual segment would depend on the number of total segments turned on, as they would all have to share a single resistor). But to show a desired number using all 8 digits, only one 7-segment display can be shown at a time, so all 8 must be cycled through separately, and in a 50th of a second for the entire period of 8. Thus the display must be refreshed at 400 Hz for the period-8 cycle through all 8 segments to make the LEDs flash no slower than 50 times per second. This requires constant interruption of whatever additional processing the controller performs, 400 times per second.
Peak current
[edit]Due to the decreased duty cycle, the current requirement of a Charlieplexed display increases much faster than it would with a traditionally multiplexed display. As the display gets larger, the average current flowing through the LED must be (roughly) constant in order for it to maintain constant brightness, thus requiring the peak current to increase proportionally. This causes a number of issues that limit the practical size of a Charlieplexed display.
- LEDs often have a maximum peak current rating as well as an average current rating.
- If the microcontroller code crashes, and a one-LED-at-a-time Charlieplex is being used, the single LED left lit is under much higher stress than it would be in a row-at-a-time Charlieplexed display or in a traditionally multiplexed display, increasing the risk of a failure before the fault is spotted.
Requirement for tristate
[edit]All the outputs used to drive a Charlieplexed display must be tristate. If the current is low enough to drive the displays directly by the I/O pins of the microcontroller, this is not a problem, but if external tristates must be used, then each tristate will generally require two output lines to control, eliminating most of the advantage of a Charlieplexed display. Since the current from microcontroller pins is typically limited to about 20 mA, this severely restricts the practical size of a Charlieplexed display. However, it can be done by enabling one segment at a time.[19]
Forward voltage
[edit]When using LEDs with different forward voltages, such as when using different color LEDs, some LEDs can light when not desired.
In the diagram above it can be seen that if LED 6 has a 4 V forward voltage, and LEDs 1 and 3 have forward voltages of 2 V or less, they will light when LED 6 is intended to, as their current path is shorter. This issue can easily be avoided by comparing forward voltages of the LEDs used in the matrix and checking for compatibility issues. Or, more simply, using LEDs that all have the same forward voltage.[11][6]
This is also a problem where the LEDs are using individual resistors instead of shared resistors, if there is a path through two LEDs that has less LED drop than the supply voltage these LEDs may also illuminate at unintended times.
Alternative use cases and variants
[edit]Input data multiplexing
[edit]Charlieplexing can also be used to multiplex digital input signals into a microcontroller. The same diode circuits are used, except a switch is placed in series with each diode. To read whether a switch is open or closed, the microcontroller configures one pin as an input with an internal pull-up resistor. The other pin is configured as an output and set to the low logic level. If the input pin reads low, then the switch is closed, and if the input pin reads high, then the switch is open.[20]
One potential application for this is to read a standard (4 × 3) 12-key numeric keypad using only 4 I/O lines. The traditional row-column scan method requires 4 + 3 = 7 I/O lines. Thus Charlieplexing saves 3 I/O lines; however it adds the expense of 12 diodes, (since the diodes are only free when LEDs are used). A variation of the circuit with only 4 diodes is possible,[20] however this reduces the rollover of the keyboard. The microcontroller can always detect when the data is corrupt, but there is no guarantee it can sense the original key presses, unless only one button is pressed at a time. (However, it is probably possible to arrange the circuit so that if at most any two adjacent buttons are pressed, then no data loss will occur.)[vague] The input is only lossless in the 4-diode circuit if only one button is pressed at a time, or if certain problematic multiple key presses are avoided. In the 12-diode circuit, this is not an issue, and there is always a one-to-one correspondence between button presses and input data. However, there are so many diodes that are required to use the method (especially for larger arrays) that there is generally no cost savings over the traditional row-column scan method, unless the cost of a diode is only a fraction of the cost of an I/O pin, where that fraction is one over the number of I/O lines.
Projected capacitance touchscreens and keypads
[edit]These do not use diodes but rely on the change in capacitance between crossing conductive tracks to detect the proximity of one or more fingers through non-conducting materials such as plastic overlays, wood, glass, etc. - even double glazing.
These tracks can be made from a wide range of materials, such as printed circuit boards, transparent Indium Tin oxide, insulation coated fine wire, etc.
The technology can range in size from very small, as in "fingerprint detectors",[21] to very large, as in "touch interactive video walls". Usually, a limit is imposed on the maximum width of an x/y wired touchscreen, because the horizontal track resistance gets too great for the product to function properly. However, a diagonally wired touchscreen (as described later in this section) does not have this problem.
There are no LEDs or diodes and, at any one time, only one I/O line is set as an output, the remaining I/O lines being set as high-impedance inputs or "grounded". This means that power requirements are very small.
GuGaplexing
[edit]In 2008, Dhananjay V. Gadre devised Gugaplexing, which is like Charlieplexing with multiple drive voltages.[22][23]
Chipiplexing
[edit]In 2008, Guillermo Jaquenod's so called Chipiplexing adds emitter followers to boost the strength of the row drive allowing rows wider than a single microcontroller port could drive to be lit simultaneously.[24][25]
Cross-plexing
[edit]In 2010, the Austrian chip manufacturer austriamicrosystems AG (named ams AG[nb 2] since 2012, and ams-OSRAM AG since 2020) introduced the multiplexing LED driver IC AS1119,[26][27] followed by the AS1130 in 2011.[28][29]
Also, the analog & mixed signal (AMS)[nb 2] division (named Lumissil Microsystems since 2020) of Integrated Silicon Solution Inc. (ISSI) introduced the IS31FL3731 in 2012[30][31] and the IS31FL3732 in 2015.[32][33][34] They all use a technique they call cross-plexing, a variant of Charlieplexing with automatic detection of open or shorted connections and anti-ghosting measures.[35]
Tucoplexing
[edit]In 2019, Micah Elizabeth Scott developed a method to use 3 pins to run 4 LEDs and 4 switches called Tucoplexing.[36]
Pulse-width modulation
[edit]Charlieplexing can even be used with pulse-width modulation to control the brightness of 12 LEDs with 4 pins.[37]
Code example
[edit]In the following Arduino code example, the circuit[38][39] uses ATtiny 8-pin microcontroller which has 5 I/O pins to create a 7-segment display. Since a 7-segment display only requires control of 7 individual LEDs, we use 4 of the ATtiny I/O pins as Charlieplexed outputs (n (n - 1)), i.e. the 4 pins could be used to control up to 12 individual LEDs (here we just use 7 of them). Leaving the fifth I/O pin to be used as digital or analog input or another output.
// ATtiny code.
// Reads analog (or digital) input from pin 4 and every time the input goes below a set threshold.
// It counts one and displays the increase in count either by activating up one of four LEDs (or transistors)
// or one of twelve Charlieplexed LEDs.
// SET THESE VALUES:
int threshold = 500;
int maxCount = 7;
////////////////////
boolean sensorTriggered = false;
int count = 0;
int sensorValue = 0;
long lastDebounceTime = 0; // The last time the output pin was toggled.
long debounceDelay = 50; // The debounce time; increase if the output flickers.
////////////////////////////////////////////////////////////////////////////////
void setup() {
// Use pull-down for disabled output pins rather than pull-up to reduce internal consumption.
for (int pin = 0; pin < 4; pin++) {
pinMode(pin, INPUT), digitalWrite(pin, LOW);
}
// Internal pull-up for enabled input pin 4.
pinMode(4, INPUT), digitalWrite(4, HIGH);
}
////////////////////////////////////////////////////////////////////////////////
void loop() {
testDigits();
}
void testDigits() {
charlieLoop();
}
////////////////////////////////////////////////////////////////////////////////
void readSensor() {
sensorValue = analogRead(2); // pin4!
delay(100);
if (sensorValue < threshold && sensorTriggered == false) {
sensorTriggered = true;
count++;
if (count > maxCount) count = 0;
charlieLoop();
}
if (sensorValue > threshold) sensorTriggered = false;
}
////////////////////////////////////////////////////////////////////////////////
void charlieLoop() {
count++;
for (int i = 0; i < 1000; i++) {
for (int c = 0; c < count; c++) {
charliePlexPin(c);
}
}
delay(1000);
if (count > maxCount) count = 0;
}
////////////////////////////////////////////////////////////////////////////////
void charliePlexPin(int myLed){
// Make sure we don't feed random voltages to the LEDs
// during the brief time we are changing pin voltages and modes.
// Use pull-down for disabled output pins rather than pull-up to reduce internal consumption.
for (int pin = 0; pin < 4; pin++) {
pinMode(pin, INPUT), digitalWrite(pin, LOW);
}
// With 4 pins we could lit up to 12 LEDs, we use only 7 here.
// Make sure to set pin voltages (by internal pull-up or pull-down)
// before changing pin modes to output.
#if 1 // Reduced code using a static lookup table.
typedef struct {
// Two different pin numbers (between 0 and 3; order is significant),
// otherwise no led will be lit.
low, high: int: 2;
} Pins;
static Pins pinsLookup[] = {
{2, 0}, {2, 3}, {1, 3}, {0, 1}, {1, 0}, {0, 2}, {1, 2},
// Other possible combinations for up to 12 LEDs:
// {0, 3}, {2, 1}, {3, 0}, {3, 1}, {3, 2},
// Other unusable combinations that don't lit any LED with a significant voltage and current,
// unless pull-up or pull-down resistances are very unbalanced:
// {0, 0}, {1, 1}, {2, 2}, {3, 3}
};
if (myLed >=0 && myLed <= sizeof(pinsLookup) / sizeof(Pins)) {
register Pins &pins = pinsLookup[myLed];
// Note that the first digitWrite to LOW is commented out,
// as it is already set above for all output pins.
/* digitalWrite(pins.low, LOW), */ pinMode(pins.low, OUTPUT);
digitalWrite(pins.high, HIGH), pinMode(pins.high, OUTPUT);
}
#else // Equivalent code using a long switch.
switch(myLed) {
case 0:
/* digitalWrite(2, LOW), */ pinMode(2, OUTPUT);
digitalWrite(0, HIGH), pinMode(0, OUTPUT);
break;
case 1:
/* digitalWrite(2, LOW), */ pinMode(2, OUTPUT);
digitalWrite(3, HIGH), pinMode(3, OUTPUT);
break;
case 2:
/* digitalWrite(1, LOW), */ pinMode(1, OUTPUT);
digitalWrite(3, HIGH), pinMode(3, OUTPUT);
break;
case 3:
/* digitalWrite(0, LOW), */ pinMode(0, OUTPUT);
digitalWrite(1, HIGH), pinMode(1, OUTPUT);
break;
case 4:
/* digitalWrite(1, LOW), */ pinMode(1, OUTPUT);
digitalWrite(0, HIGH), pinMode(0, OUTPUT);
break;
case 5:
/* digitalWrite(0, LOW), */ pinMode(0, OUTPUT);
digitalWrite(2, HIGH), pinMode(2, OUTPUT);
break;
case 6:
/* digitalWrite(1, LOW), */ pinMode(1, OUTPUT);
digitalWrite(2, HIGH), pinMode(2, OUTPUT);
break;
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
void spwm(int freq, int pin, int sp) {
// Call Charlieplexing to set correct pin outs:
// on:
digitalWrite(pin, HIGH);
delayMicroseconds(sp * freq);
// off:
digitalWrite(pin, LOW);
delayMicroseconds(sp * (255 - freq));
}
See also
[edit]Notes
[edit]- ^ Yes, round-closest rather than round-up. Normally pin counts would have to round up, since an unused pin is merely wasteful, but an unprovided pin is non-functional. But in this particular formula, the constant +1 is already needed to handle the case of a single I/O element. Because that +1 is added, the final result is already guaranteed to be larger than the square root of the number of I/O elements.
- ^ a b The ICs AS1119 and AS1130 were introduced by austriamicrosystems AG (formerly Austria Mikro Systeme), later named ams AG and ams-OSRAM AG. The ICs IS31FL3731 and IS31FL3732 were introduced by the AMS (analog & mixed signal) division (now called Lumissil Microsystems) of the fab-less chip manufacturer Integrated Silicon Solution Inc. (ISSI). Presumably, the fact that both manufacturers of cross-plexing LED driver ICs carry "AMS" in their name is coincidence only.
References
[edit]- ^ "Charlieplexing made easy". Retrieved 2024-01-08.
- ^ "Charlieplexed-Arduino-8x8-LED-Grid-Display". Retrieved 2024-01-08.
- ^ "Making Charlieplex arrays". Retrieved 2024-01-08.
- ^ "sparkfun-led-array-8x7-hookup-guide". Retrieved 2024-01-09.
- ^ "Touch sensor". Retrieved 2024-01-08.
- ^ a b c d "Charlieplexing - Reduced Pin-Count LED Display Multiplexing". Maxim Integrated Products, Inc. 2003-02-10. Application Note 1880. Archived from the original on 2016-08-13. Retrieved 2017-06-07.
[…] This unusual multiplex technique is used by the MAX6950, MAX6951, MAX6954, MAX6955, MAX6958, and MAX6959 LED display drivers. […] Charlie Allen originally championed this technique internally at Maxim, and so the shorthand name "Charlieplexing" came into use to distinguish reduced pin count multiplexing from the traditional method. The first Maxim product to use Charlieplexing is the Maxim MAX6951 LED driver, which drives 8 numeric digits with only 9 pins […]
[1] (4 pages) - ^ EDN Staff, ed. (1997-05-08). "EDN's 1996 Innovator / Innovation Competition". EDN. Archived from the original on 2021-12-10. Retrieved 2021-12-10.
- ^ Sherman, Len (2016-12-16). "Almost 30 years of the MAX232". BISinfotech. Archived from the original on 2021-12-10. Retrieved 2021-12-10.
[…] The MAX232's success was as much a tribute to the vision of its definer, Charlie Allen, as it was to the ingenuity of its designer, Dave Bingham. […]
- ^ Fox, Brett J. (2021). "What Makes Your Great Engineers Great?". Archived from the original on 2021-12-10. Retrieved 2021-12-10.
[…] The launch of the MAX232 family is particularly insightful. Charlie Allen, a brilliant, customer focused, applications engineer, noticed that our customers were using a product called the ICL7660, which Dave [Bingham] also designed, to provide the negative power supply for RS-232 line drivers and receivers. So, Charlie approached Dave, and asked Dave if he could design an IC that integrated the functionality of the ICL7660 with an RS-232 line driver and receiver. […]
- ^ a b MAX6950/MAX6951 - Serially Interfaced, +2.7V to +5.5V, 5- and 8-Digit LED Display Drivers (PDF). Revision 1. Sunnyvale, California, USA: Maxim Integrated Products. December 2001. 19-2227. Archived (PDF) from the original on 2021-12-10. Retrieved 2021-12-10. (19 pages)
- ^ a b c Lancaster, Don (August 2001). "N-Connectedness" (PDF). Tech Musings. No. 152. Thatcher, Arizona, USA: Synergetics. pp. 152.2 – 152.5. Archived (PDF) from the original on 2021-12-09. Retrieved 2021-12-09. (4 pages)
- ^ Rebic, Jean-Claude (1999-11-19) [1998-11-06]. "Complementary LED drive" (PDF). Pioneer-Standard, USA: Microchip Technology Inc. DS91029A. Application Note TB029. Archived (PDF) from the original on 2021-02-13. Retrieved 2021-12-09. (3+1 pages)
- ^ "TIP #2: Input/Output Multiplexing". Microchip Tips 'n Tricks - 8-pin FLASH PIC Microcontrollers - Outperform the Competition (PDF). Chandler, Arizona, USA: Microchip Technology Inc. 2003. p. DS40040B-page 3. DS40040B. Archived from the original (PDF) on 2007-01-28. (2+ii+38+2 pages)
- ^ a b Daniel, Graham (1998-07-19). "loads of flashing LEDs". piclist.com. 060918a. Archived from the original on 2021-12-11. Retrieved 2021-12-11. [2] (NB. With contributions by Paul B. Webster, Mark Willis, Dwayne Reid and Alan King.)
- ^ a b Daniel, Graham (1998-07-20). "12 LED hex file, 12c508". piclist.com. 045923a. Archived from the original on 2021-12-11. Retrieved 2021-12-11.
- ^ Malinowski, Christopher W.; Rinderle, Heinz; Siegle, Martin (1982-03-09) [1979-10-16]. "Three-state signaling system" (PDF). Heilbronn, Germany: Licentia Patent-Verwaltungs-G.m.b.H. / Telefunken Electronic GmbH. US Patent 4319227A. Archived (PDF) from the original on 2021-12-09. Retrieved 2021-12-09.
- ^ "unknown". Model Railroader. 1972.
{{cite magazine}}: Cite uses generic title (help) - ^ Lapedus, Mark (2019-03-29). "MicroLEDs: The Next Revolution In Displays? Technology offers improved brightness, colors, and lower power, but they're expensive and difficult to manufacture". Manufacturing, Packaging & Materials. SemiconductorEngineering. Sperling Media Group LLC. Archived from the original on 2023-04-25. Retrieved 2023-04-11. (NB. Micro-led array using active matrix.)
- ^ Pino, Jose (2009-08-25). "'Almost No Parts' 12/24hrs LED Clock". Jose Pino's Projects & Tidbits. Archived from the original on 2021-10-10. Retrieved 2021-12-10. (NB. Using Charlieplexed 7-segment LED displays.)
- ^ a b Joshi, Kartik (2008-04-24). "Novel Switch Interface Scheme Reduces Microprocessor Pin Count". Electronic Design. Archived from the original on 2021-02-24. Retrieved 2021-12-10. (1 page) (NB. Charlieplexing for input data.)
- ^ Triggs, Robert (2023-03-25). "How fingerprint scanners work: Optical, capacitive, and ultrasonic explained. Fingerprint scanners are everywhere, but how do they work?". Mobile Technology. AndroidAuthority. Authority Media. Archived from the original on 2023-06-23. Retrieved 2023-06-23.
- ^ Gadre, Dhananjay V. (2008). "GuGaplexed Valentine LED Heart". instructables circuits. Archived from the original on 2021-02-28. Retrieved 2021-12-25. [3]
- ^ Jepson, Brian (2008-06-23). "Charlieplexing times two". Make:. Make Community LLC. Archived from the original on 2021-02-24. Retrieved 2021-12-10.
- ^ Jaquenod, Guillermo (2008-11-27). Rowe, Martin; Granville, Fran (eds.). ""Chipiplexing" efficiently drives multiple LEDs using few microcontroller ports" (PDF). Design Ideas. EDN. La Plata, Argentina. pp. 59–60. Archived from the original (PDF) on 2012-12-18. [4] (2 pages)
- ^ Staff writer, ed. (2008-12-09). "Chipiplexing LEDs". Electronics Weekly. Archived from the original on 2021-12-25. Retrieved 2021-12-25.
- ^ "austriamicrosystems announces new 144-channel dot matrix LED driver with industry's highest efficiency and smallest size". Company Newsfeed. LEDs Magazine. Vol. 7, no. 8. PennWell Corporation. 2010-08-23. ISSN 2156-633X. Archived from the original on 2022-05-12. Retrieved 2022-05-13.
[…] Only 18 lines are required to drive all 144 LEDs. This is accomplished with austriamicrosystems' multiplexing technique called cross-plexing. This allows reducing the line count on the PCB as well as fewer pins on the connectors, saving space & costs. […] Other features include […] open and shorted LED error detection […]
(NB. Announcement of the AMS AS1119.) - ^ "Application Note - Cross-Plexing - AS1119 - 144 LED Cross-Plexing Driver with 320mA Charge-Pump". 1.00. Unterpremstätten, Austria: austriamicrosystems AG. 2010. Archived from the original on 2022-05-13. Retrieved 2022-05-13. (5+1 pages); "Demo Board Manual - AS1119 - 144 LED, I²C Interfaced, Cross-Plexing Driver with a 320mA Charge-Pump" (PDF). 1.00. Unterpremstätten, Austria: austriamicrosystems AG. 2010. Archived (PDF) from the original on 2022-05-13. Retrieved 2022-05-13. (1+5+1 pages); "Application Note AN02 – SW Manual - AS1119 - 144 LED Cross-Plexing Driver with 320mA Charge-Pump". 1.00. Unterpremstätten, Austria: austriamicrosystems AG/ams AG. 2010. Archived from the original on 2022-05-13. Retrieved 2022-05-13. (6+1 pages)
- ^ "austriamicrosystems launches 132 LED driver featuring industry's highest efficiency and smallest size". Company Newsfeed. LEDs Magazine. Vol. 8, no. 10. PennWell Corporation. 2011-10-04. ISSN 2156-633X. Archived from the original on 2022-05-13. Retrieved 2022-05-13.
[…] Only 12 lines are required to drive all 132 LEDs. This is accomplished with austriamicrosystems' multiplexing technique called cross-plexing. It reduces line count on the PCB as well as pins on the connectors, saving space & costs. Other features include […] open and shorted LED error detection […]
(NB. Announcement of the AMS AS1130.) - ^ "AS1130 - 132-LED Cross-Plexing Driver with Scrolling Function" (PDF). 2.01. Unterpremstätten, Austria: ams AG. 2016-10-12 [2016-09-21]. Archived (PDF) from the original on 2021-08-14. Retrieved 2022-05-13. (66+1 pages); "Demo Kit Manual - AS1130 - Standard Board - AS1130-WL_DK_ST". 2.00. Unterpremstätten, Austria: ams AG. 2014-11-14 [2011-10-11]. Archived from the original on 2022-05-13. Retrieved 2022-05-13. (32 pages); "Application Note: 4 pin RGBs in a Cross-Plexing Matrix - AS1130 - 132 LED, I²C Interfaced, Cross-Plexing Driver with scrolling Function". 1.00. Unterpremstätten, Austria: austriamicrosystems AG. 2012. Archived from the original on 2022-05-13. Retrieved 2022-05-13. (6+1 pages)
- ^ "IS31FL3731 - Audio Modulated Matrix LED Driver" (PDF). Rev. F. Lumissil Microsystems/Integrated Silicon Solution Inc. (ISSI). 2019-11-04 [2012-03-14]. Archived (PDF) from the original on 2022-05-12. Retrieved 2022-05-13. (24+1 pages)
- ^ "IS31FL3731C - Audio Modulated Matrix LED Driver" (PDF). Rev. B. Integrated Silicon Solution Inc. (ISSI). 2014-04-01. Archived (PDF) from the original on 2022-05-13. Retrieved 2022-05-13. (22+1 pages)
- ^ "ISSI Expands FxLED Family with Audio Modulated LED Driver to drive 144 LEDs - IS31FL3732 supports special effect LED functions for automotive, gaming, white goods and IoT platforms" (PDF). San Jose, California, USA: Integrated Silicon Solution Inc. (ISSI). 2015-02-24. Archived (PDF) from the original on 2022-05-16. Retrieved 2022-05-16. (2 pages)
- ^ "IS31FL3732 - Audio Modulated Matrix LED Driver" (PDF). Rev. D. Lumissil Microsystems/Integrated Silicon Solution Inc. (ISSI). 2017-07-04 [2015-09-06]. Archived (PDF) from the original on 2022-05-13. Retrieved 2022-05-13. (27+1 pages)
- ^ "IS31FL3732A - Audio Modulated Matrix LED Driver" (PDF). Rev. C. Lumissil Microsystems/Integrated Silicon Solution Inc. (ISSI). 2017-07-04 [2016-11-03]. Archived (PDF) from the original on 2022-05-12. Retrieved 2022-05-13. (27+1 pages)
- ^ Rust, Peter (2013-04-10). "LED-Displays - Matrixtreiber-Topologien unter der Lupe" [LED displays - Matrix driver topologies in focus]. elektroniknet.de (in German). WEKA FACHMEDIEN GmbH. Archived from the original on 2022-05-12. Retrieved 2022-05-13.
[…] Die möglichen Ghosting-Effekte und Probleme mit offenen LEDs haben die Verbreitung der Charlieplexing-Topologie in der Vergangenheit stark gebremst. Eine »Crossplexing« genannte Verbesserung des Verfahrens verspricht nun, die Nachteile des bisherigen Verfahrens zu eliminieren […] Die Kurzschluss- und Defekterkennung des ICs beruht […] auf der Vorwärtsspannung der in der Matrix verwendeten LEDs. Das Bauelement bestimmt eine optimale Spannungsschwelle für Defektsituationen und konfiguriert sie automatisch. Die Kenntnis der Position eines Kurzschlusses oder Defekts eliminiert natürlich noch nicht die Ghosting-Effekte. Wird jedoch eine Unterbrechung festgestellt, kann das System die Koordinaten des Defekts abspeichern. […] Jedes Mal, wenn der Treiber angewiesen wird, diese LED anzusteuern, wird diese Instruktion ignoriert. Diese Maßnahme vermeidet das unbeabsichtigte Aufleuchten von LEDs im Rest des Punktmatrixdisplays. […]
- ^ Scharfglass, Kerry (2019-03-23). "Tucoplexing: A New Charliplex for Buttons and Switches". Hackaday. Archived from the original on 2021-12-10. Retrieved 2021-12-10.
- ^ Johnson-Davies, David (2021-10-19) [2019-02-19]. "Twelve PWM outputs from an ATtiny85". Technoblogy. Archived from the original on 2021-12-10. Retrieved 2021-12-10.
- ^ "ATtiny - Charlieplexed 7-Segment Display and 1 Switch or Sensor". 2017. Archived from the original on 2021-05-11. Retrieved 2021-12-10.
- ^ Satomi, Mika; Perner-Wilson, Hannah (2015) [2012]. "Circuits and Code - ATtiny: 7-Segment Display". How to get what you want. Archived from the original on 2021-04-18. Retrieved 2017-11-13.
Further reading
[edit]- Gadre, Dhananjay V. (2007-01-18). "Microcontroller drives logarithmic/linear dot/bar 20-LED display". EDN. p. 83. CA6406730. Archived from the original on 2021-12-25.
- Gadre, Dhananjay V.; Chugh, Anurag (2007-05-24). "Eight-Pin Microcontroller Handles Two-Digit Display With Multiple LEDs". Electronic Design. Paramus, New Jersey, USA. ED Online 15512. Archived from the original on 2012-02-13.
- Gadre, Dhananjay V. (2007-09-27). "Microcontroller drives 20 LEDs". EDN. CA6483826. Archived from the original on 2021-12-25.
Charlieplexing
View on GrokipediaBackground
Etymology
The term "Charlieplexing" is derived from the first name of its inventor, Charlie Allen, an engineer at Maxim Integrated Products, combined with "plexing," an electronics jargon shorthand for multiplexing. This portmanteau was coined in Maxim Integrated's Application Note 1880 ("Charlieplexing—Reduced Pin-Count LED Display Multiplexing"), published on February 10, 2003, to describe Allen's innovative approach to driving multiplexed displays using tri-state logic for efficient pin utilization.[1][2] The name first gained formal recognition in Maxim Integrated's documentation, particularly in the aforementioned application note, which attributes the technique's development to Allen and uses the term to differentiate it from traditional multiplexing methods.[4]Origin
Charlieplexing was invented by Charlie Allen in early 1995 while he was an applications engineer at Maxim Integrated Products, a semiconductor company specializing in analog and mixed-signal integrated circuits.[2] The technique emerged as a solution to the challenge of driving multiple LEDs in displays using limited microcontroller I/O pins, particularly in resource-constrained embedded systems prevalent during the mid-1990s, such as pagers and early portable communication devices that required compact, low-pin-count designs to minimize power consumption and board space.[1] Allen proposed the method initially on an internet mailing list, highlighting its potential for efficient LED multiplexing without dedicated driver hardware.[5] The tristate multiplexing technique on which Charlieplexing is based originated earlier, with a 1979 German patent by Christopher Malinowski (U.S. Patent 4,319,227 granted in 1982) describing the control of multiple LEDs using few lines via tri-state logic, where pins dynamically serve as anodes or cathodes.[6] The first formal documentation using the name "Charlieplexing" appeared in a Maxim application note published in 2003, which detailed its implementation for reducing pin requirements in LED display drivers.[1] This note coincided with the introduction of Maxim's MAX6951 LED driver IC in 2001, the company's inaugural product incorporating the technique to control eight 7- or 8-segment digits using just nine pins.[1] No specific patent was filed by Allen for the core method, as it built upon these earlier tri-state logic concepts.[1] Charlieplexing evolved from conventional multiplexing schemes, which typically required separate rows and columns of pins leading to linear scalability (n² elements with 2n pins), by innovating the use of tri-state outputs to allow each pin to serve dynamically as either an anode or cathode, achieving near-exponential control (n² - n elements with n pins).[7] This advancement was driven by the need for higher integration in battery-powered gadgets, enabling designers to allocate scarce pins to other functions like sensors or communication interfaces.[1]Principles
Tri-state Logic Fundamentals
Tri-state logic, also known as three-state logic, refers to a digital output stage that can assume one of three distinct states: a high state (logical 1, typically connected to Vcc), a low state (logical 0, typically connected to ground or GND), or a high-impedance state (denoted as Z), where the output is effectively disconnected from the circuit, presenting very high resistance to current flow.[8] This high-impedance state is crucial for preventing electrical conflicts in shared signal paths, as it isolates the device from the line without influencing the voltage level.[8] The high-impedance state enables bidirectional control on a single pin or bus line by allowing the device to alternate between actively driving the line (high or low) and acting as an input receiver, where it avoids interfering with other drivers.[9] In bidirectional applications, such as data buses, multiple devices can connect to the same wire; only the active device drives the line while others remain in high-impedance, ensuring no short circuits occur if one attempts to drive high while another drives low.[9] This capability is implemented using control signals to enable or disable the output transistors in the buffer circuit, typically involving complementary MOSFETs or BJTs configured to float the output when inactive.[8] A fundamental implementation is the tri-state buffer, which has a data input (IN), an enable input (EN), and an output (OUT). For an active-high, non-inverting tri-state buffer, the behavior is described by the following truth table:| EN | IN | OUT |
|---|---|---|
| 0 | 0 | Hi-Z |
| 0 | 1 | Hi-Z |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Complementary Drive Mechanism
In Charlieplexing, the complementary drive mechanism leverages tri-state logic outputs to generate opposing voltage signals across specific LED pairs, enabling selective illumination while isolating other segments. This approach builds upon the high, low, and high-impedance states of microcontroller pins to ensure current flows only through the intended LED, without unintended paths forming due to voltage gradients.[1] The core process involves configuring one pin to drive high (acting as the anode) and another to drive low (acting as the cathode) for a targeted LED, while all remaining pins are set to high-impedance to prevent any current leakage or back-biasing that could affect adjacent elements. This configuration exploits the unidirectional nature of LEDs, allowing forward bias only across the selected pair, as the high-impedance state effectively disconnects unused pins from the circuit. By dynamically reassigning pin roles in sequence, the mechanism avoids ghosting—unwanted illumination of non-targeted LEDs—through precise control of voltage differentials.[1] The waveform for driving involves rapid sequential switching: for each time slot, a unique high-low pair is activated briefly, with the high-impedance state on other pins ensuring isolation throughout the cycle. This pulsed operation multiplexes the display, refreshing each LED in turn to maintain perceived continuous illumination without overlap or interference. For instance, in a three-pin setup (N=3), up to six LEDs can be controlled by cycling through the six possible unique high-low combinations across the pins.[1] Consider a simple diagram for N=3 pins (labeled P1, P2, P3) connected to six LEDs oriented between each pair: LED12 (anode at P1, cathode at P2), LED21 (anode at P2, cathode at P1), LED13 (anode at P1, cathode at P3), LED31 (anode at P3, cathode at P1), LED23 (anode at P2, cathode at P3), and LED32 (anode at P3, cathode at P2). To light LED12, set P1 high, P2 low, and P3 high-impedance; current flows only from P1 through LED12 to P2, with P3 isolated. Subsequent states similarly activate each LED by swapping the high-low assignments.[1] The maximum number of controllable elements in this scheme is given by the equation: where represents the number of available pins, derived from the unique directed pairs formed by selecting one pin high and one low, excluding self-pairs. For N=3, this yields 6 elements, as each pin can pair as anode with the other two as cathodes.[1]Matrix Expansion Techniques
Charlieplexing scales the number of controllable LEDs quadratically with the number of available pins, enabling efficient use of limited I/O resources for larger displays. With N pins, the technique supports up to N × (N − 1) LEDs, as each ordered pair of pins can independently drive one LED by directing current from one pin (set high) to another (set low), while all other pins remain in high-impedance state.[12] This formula arises from the tri-state logic, where the directed nature of LED polarity allows two LEDs per unordered pin pair without interference.[1] For practical scaling, 10 pins can thus drive 90 LEDs, demonstrating the method's efficiency for displays requiring dozens to hundreds of indicators.[1] A concrete illustration is a 4-pin matrix (pins labeled P1, P2, P3, P4), which controls 12 LEDs connected between every pair of pins in opposing orientations (e.g., one LED anode to P1 and cathode to P2, another reversed). To light a specific LED, the software sets the anode pin high, the cathode low, and the unused pins to high impedance; all other LEDs remain off due to the lack of complete current paths. The full set of states requires systematic enumeration to avoid conflicts, often implemented via a lookup table mapping each LED to its pin configuration. The table below outlines the configurations for all 12 LEDs:| LED ID | Anode (High) | Cathode (Low) | P1 State | P2 State | P3 State | P4 State |
|---|---|---|---|---|---|---|
| 1 (P1→P2) | P1 | P2 | High | Low | Z | Z |
| 2 (P2→P1) | P2 | P1 | Low | High | Z | Z |
| 3 (P1→P3) | P1 | P3 | High | Z | Low | Z |
| 4 (P3→P1) | P3 | P1 | Low | Z | High | Z |
| 5 (P1→P4) | P1 | P4 | High | Z | Z | Low |
| 6 (P4→P1) | P4 | P1 | Low | Z | Z | High |
| 7 (P2→P3) | P2 | P3 | Z | High | Low | Z |
| 8 (P3→P2) | P3 | P2 | Z | Low | High | Z |
| 9 (P2→P4) | P2 | P4 | Z | High | Z | Low |
| 10 (P4→P2) | P4 | P2 | Z | Low | Z | High |
| 11 (P3→P4) | P3 | P4 | Z | Z | High | Low |
| 12 (P4→P3) | P4 | P3 | Z | Z | Low | High |
Implementation
LED Driving Process
The LED driving process in Charlieplexing begins with initializing all microcontroller pins to a high-impedance (tri-state) state, typically by setting them as inputs, to ensure no unintended current paths exist before multiplexing begins.[3] This setup leverages the tri-state logic where pins can be driven high, low, or left floating, allowing selective activation of LEDs without additional switching components.[1] To multiplex the LEDs, the process cycles rapidly through all possible unique high-low pin pairs, activating one LED at a time by setting one pin to high (anode) and an adjacent pin to low (cathode), while keeping all other pins in high-impedance to isolate the current flow.[3] For instance, in a configuration with LEDs connected between pins in both directions, reversing the high and low states on the same pair lights the oppositely oriented LED. This scanning repeats continuously, with each LED receiving brief illumination in sequence to create the illusion of simultaneous operation.[13] For a flicker-free display, the timing must ensure the full scan cycle—covering all LEDs—completes faster than the human eye's persistence threshold, typically at a refresh rate of at least 60 Hz, meaning the total cycle time should be less than 1/60 seconds or approximately 16.7 ms.[3] The duration per LED state is adjusted proportionally based on the number of LEDs, often using short delays (e.g., 1-5 ms per state) to balance brightness and speed.[13] Essential circuit components include current-limiting resistors to prevent LED damage, typically placed in series with each pin (e.g., 150-330 ohms depending on supply voltage and LED forward current, around 10-20 mA) rather than per LED, as only one path is active at a time.[3][13][14] LEDs must tolerate reverse bias up to the supply voltage during off states; if not, additional diodes can be added in anti-parallel to each LED for protection, though this is uncommon in basic implementations to minimize parts.[1] As an example workflow for a 3-pin setup equivalent to driving 6 LEDs (3² - 3 = 6, simulating a sparse 3x3 matrix), the following pseudocode illustrates one full scan cycle, assuming pins A, B, and C:# Initialize all pins to high-impedance (input mode)
// [pseudocode](/page/Pseudocode) for one full scan
# Light LED between A (high) and B (low)
set_pin(A, high); set_pin(B, low); set_pin(C, high-Z);
delay(2 ms); # Brief dwell time
# Light LED between B (high) and A (low)
set_pin(A, low); set_pin(B, high); set_pin(C, high-Z);
delay(2 ms);
# Light LED between A (high) and C (low)
set_pin(A, high); set_pin(B, high-Z); set_pin(C, low);
delay(2 ms);
# Light LED between C (high) and A (low)
set_pin(A, low); set_pin(B, high-Z); set_pin(C, high);
delay(2 ms);
# Light LED between B (high) and C (low)
set_pin(A, high-Z); set_pin(B, high); set_pin(C, low);
delay(2 ms);
# Light LED between C (high) and B (low)
set_pin(A, high-Z); set_pin(B, low); set_pin(C, high);
delay(2 ms);
# Return all to high-Z for next cycle
# Initialize all pins to high-impedance (input mode)
// [pseudocode](/page/Pseudocode) for one full scan
# Light LED between A (high) and B (low)
set_pin(A, high); set_pin(B, low); set_pin(C, high-Z);
delay(2 ms); # Brief dwell time
# Light LED between B (high) and A (low)
set_pin(A, low); set_pin(B, high); set_pin(C, high-Z);
delay(2 ms);
# Light LED between A (high) and C (low)
set_pin(A, high); set_pin(B, high-Z); set_pin(C, low);
delay(2 ms);
# Light LED between C (high) and A (low)
set_pin(A, low); set_pin(B, high-Z); set_pin(C, high);
delay(2 ms);
# Light LED between B (high) and C (low)
set_pin(A, high-Z); set_pin(B, high); set_pin(C, low);
delay(2 ms);
# Light LED between C (high) and B (low)
set_pin(A, high-Z); set_pin(B, low); set_pin(C, high);
delay(2 ms);
# Return all to high-Z for next cycle
Hardware Requirements
Charlieplexing implementations require a microcontroller equipped with general-purpose input/output (GPIO) pins that support true tri-state logic functionality, enabling each pin to operate in high (logic 1), low (logic 0), or high-impedance (input) states. This tri-state capability is essential for isolating unused pins while actively driving both high and low on the selected pair; open-drain or open-collector configurations can be used but require external pull-up resistors to achieve the high state, potentially limiting current drive and complicating the circuit. The primary components include light-emitting diodes (LEDs) arranged in a non-traditional matrix, where LEDs are connected between every pair of pins in both polarities to maximize the number of controllable elements (up to LEDs for pins).[3] Current-limiting resistors must be placed in series with each pin to regulate current and avoid exceeding the microcontroller's drive limits or damaging the LEDs; their value is determined by the formula , where is the logic high voltage, is the LED's forward voltage drop, and is the target forward current (typically 10-20 mA).[15][14] For power supply stability, especially during rapid pin state switching, bypass capacitors (e.g., 0.1 µF ceramic) are recommended across the microcontroller's supply pins to decouple noise and maintain voltage integrity.[16] Charlieplexing circuits are compatible with standard CMOS and TTL logic families prevalent in microcontrollers like AVR or PIC series.[17] Supply voltage levels, such as 5 V for TTL-compatible systems or 3.3 V for low-power CMOS devices, directly influence LED selection, as lower voltages necessitate LEDs with reduced forward voltage drops to ensure sufficient headroom for illumination.[18] To validate the high-impedance state during setup, oscilloscope measurements can trace pin voltages, confirming minimal leakage current (ideally <1 µA) and no voltage clamping when the pin is configured as an input.[19]Advantages and Limitations
Reasons for Using Charlieplexing
Charlieplexing offers significant pin efficiency by enabling a microcontroller with N pins to control up to N(N-1) LEDs, far surpassing traditional binary multiplexing methods that typically require 2√M pins for M LEDs in a row-column configuration.[3][20] For instance, with 4 pins, Charlieplexing can drive 12 LEDs, compared to only 4 LEDs using a 2x2 row-column matrix on the same 4 pins.[3] This efficiency saves over 50% of I/O pins on resource-constrained microcontrollers, allowing more functionality without expanding the chip package.[20] The reduced pin count translates to substantial cost and space savings, as smaller microcontrollers or driver ICs with fewer I/O lines are less expensive and more compact, making Charlieplexing ideal for applications like wearables and Internet of Things (IoT) devices where board real estate is limited.[1][20] For example, a 9-pin driver like the MAX6951 can manage 8 LED digits, halving the pin requirements—and thus the complexity and cost—compared to 16-pin alternatives such as the MAX7219.[1] In terms of power efficiency, Charlieplexing activates only one LED at a time, with undriven pins in a high-impedance state to prevent unintended current paths, thereby minimizing average power consumption relative to methods that energize multiple elements simultaneously.[3][20] This approach is particularly beneficial in battery-powered systems, as it avoids the need for additional logic components that could increase quiescent current draw.[3] The following table compares Charlieplexing to traditional row-column multiplexing for selected LED counts:| Number of LEDs | Pins Required (Charlieplexing) | Pins Required (Row-Column) |
|---|---|---|
| 4 | 3 | 4 |
| 9 | 4 | 6 |
| 16 | 5 | 8 |
| 25 | 6 | 10 |
Refresh Rate Challenges
In Charlieplexing, sequential scanning of the LED matrix using tri-state outputs results in each LED being illuminated only briefly during its assigned state in the cycle, potentially causing visible flicker if the time between successive activations for any individual LED exceeds the human eye's flicker fusion threshold, typically around 16 ms corresponding to a 60 Hz refresh rate per LED.[11] Persistence of vision, the optical phenomenon where retinal images linger for approximately 1/16 to 1/25 of a second after the stimulus ends, enables the perception of continuous illumination from rapid sequential flashes in multiplexed displays; however, insufficient refresh rates disrupt this, making flicker apparent and potentially causing visual discomfort, as seen in early film projections at 16 frames per second or modern low-refresh LED signage below 50 Hz.[21][22] To address flicker, the microcontroller's clock speed can be increased to shorten state transition times, or the duty cycle adjusted by minimizing each LED's on duration while ensuring the full matrix scan completes within the persistence threshold; the minimum display refresh rate is given by where is the number of control pins and is the on-time per LED state, guaranteeing each LED achieves the target refresh without perceptible gaps.[23] Larger matrices exacerbate these issues due to the quadratic increase in addressable states, demanding faster processing; for example, a 20-pin setup enables 380 LEDs but requires microcontroller speeds exceeding 10 kHz to sustain viable values at 60 Hz per LED, often limiting practical implementations to smaller configurations without dedicated driver ICs.[23]Peak Current and Tristate Issues
In Charlieplexing, each LED is driven individually in sequence, resulting in a high peak current for the active LED to ensure adequate brightness, typically limited to 20 mA for standard low-power LEDs, while the average current duty cycle across the matrix remains low due to time-sharing among multiple LEDs. This peak current is determined by the supply voltage, the LED's forward voltage drop, and the series current-limiting resistor, allowing brief high-intensity pulses without continuous high power draw. However, microcontroller I/O pins have inherent current limits, often 20–40 mA absolute maximum, which must not be exceeded to avoid damage.[3] A critical requirement for effective Charlieplexing is the use of true tri-state logic on the driving pins, where pins not involved in driving a particular LED must enter a high-impedance (Z-state) to isolate them from the circuit and prevent unintended current paths. Without this, residual voltages or currents on "off" pins can cause leakage, leading to ghosting—where unintended LEDs faintly illuminate—or reduced brightness in the intended LED due to voltage division. Attempts to simulate tri-state behavior with pull-up or pull-down resistors introduce additional leakage currents, exacerbating these issues and potentially causing thermal stress or unreliable operation, particularly in larger matrices.[1] The peak current can be precisely calculated using Ohm's law: , where is the power supply voltage (e.g., 5 V), is the LED's forward voltage (typically 1.8–2.2 V for red LEDs), and is the series resistor value chosen to limit current within safe bounds. For instance, with a 5 V supply, 2 V forward drop, and 150 Ω resistor, the peak current is approximately 20 mA, aligning with common LED ratings and MCU capabilities. Exceeding this through insufficient resistance or high supply voltages risks MCU pin failure or LED burnout.[3] To mitigate peak current and tri-state limitations in demanding applications, such as high-brightness displays or larger arrays, external drivers like NPN/PNP transistors or dedicated ICs (e.g., MAX6951) can be integrated to provide higher current sinking/sourcing (up to 40 mA per segment) and built-in high-impedance states, offloading the burden from the microcontroller while preserving the pin-efficiency of Charlieplexing. These solutions ensure reliable operation but add minor hardware complexity.[1]Forward Voltage Considerations
In Charlieplexing configurations that incorporate multi-color LEDs within a shared matrix, variations in forward voltage (V_f) across different LED colors pose significant challenges to uniform illumination. For instance, typical red LEDs exhibit a V_f of approximately 2 V, whereas blue LEDs require around 3 V at standard operating currents.[24] These differences arise from the semiconductor materials used, with longer-wavelength colors like red needing less energy to emit photons compared to shorter-wavelength blue.[24] In the asymmetric drive paths of Charlieplexing, where one pin is set high and another low without individual current-limiting elements, this V_f mismatch directly influences the operating current for each LED.[1] The primary effect is uneven brightness, with higher V_f LEDs appearing dimmer due to reduced current flow under the same drive voltage. This results in current imbalances across the matrix, where lower V_f LEDs (e.g., red) draw disproportionately more current, potentially leading to thermal variations and accelerated degradation in mixed-color arrays.[25] Such disparities are exacerbated in Charlieplexing's tri-state logic, as the shared paths lack dedicated regulation, amplifying the impact compared to conventional multiplexing with per-LED resistors.[1] The underlying relationship can be expressed through the effective voltage drop across the LED, given by , where is the logic-high output voltage from the driver pin. The resulting current is then approximately , with representing the LED's small internal dynamic resistance (typically 10–50 Ω near operating point).[15] This equation illustrates how even small V_f differences yield large current variations, as is low and does not provide inherent limiting. For example, with a 5 V supply, a red LED (V_f = 2 V) experiences a 3 V drop, while a blue LED (V_f = 3 V) sees only 2 V, potentially halving the current and brightness if uncompensated.[15] To address these issues, designers often employ LED binning to select components with closely matched V_f values within the array, ensuring more consistent performance across colors.[26] Adding series resistors to individual LEDs allows precise current balancing by tailoring resistance to each V_f (e.g., lower resistance for higher V_f LEDs), though this increases part count and may partially offset Charlieplexing's efficiency gains.[25] Alternatively, software compensation via pulse-width modulation (PWM) adjusts the on-time or duty cycle for specific LED types, normalizing perceived brightness without hardware modifications; for instance, increasing the duty cycle for blue LEDs relative to red can equalize luminous output.[25]Variants and Applications
Input Data Multiplexing
Charlieplexing, originally developed for driving multiple LEDs, can be adapted for multiplexing input devices such as keypads or switches by leveraging the tri-state capabilities of microcontroller pins to scan for closures in a resource-efficient manner. In this configuration, pins are configured in high-impedance (input) mode during scanning to detect switch states, while pull-up resistors—either internal to the microcontroller or external—ensure that inactive inputs read high. When a switch closes, it pulls the input low, signaling activation. To prevent bidirectional current flow inherent in mechanical switches, which could cause ghosting or false detections, a series diode is typically placed with each switch, oriented to allow current only in the direction of detection. This adaptation inverts the output-oriented use of Charlieplexing, focusing instead on input polling while maintaining the same pin efficiency.[12] For an N-pin setup, this method supports up to switches, as each unique pair of pins defines a directed path for detection, similar to the LED configuration but accounting for the diode's directionality. For example, with 4 pins, up to 6 keys can be multiplexed, connecting each key between a unique pair of pins with the diode anode toward the pin driven low during scanning. The scanning process involves sequentially configuring one pin as an output driven low (acting as a virtual "row") and setting the remaining pins to high-impedance input mode (as "columns") to read their states via the pull-ups. If a connected input reads low, it indicates a closure on that pin pair, allowing the system to identify the specific key. This cycle repeats rapidly across all pin combinations to poll the entire matrix.[12][27] Due to mechanical bouncing in switches, debouncing is essential, typically implemented in software by sampling inputs multiple times over a short period (e.g., 10-50 ms) or using hardware capacitors, to filter transient signals and ensure reliable detection. This approach is particularly advantageous in embedded systems with limited I/O pins, such as microcontrollers in wearables or IoT devices, where it enables efficient I/O multiplexing without additional hardware like dedicated matrix scanners, conserving both pins and power while supporting compact designs.[12]Projected Capacitance Interfaces
Charlieplexing extends to projected capacitance interfaces by applying tri-state logic to scan a matrix of micro-capacitors formed at intersections of conductive traces connected to microcontroller (MCU) pins, enabling efficient touch detection with minimal hardware. In this method, the MCU configures pins in high, low, or high-impedance (tri-state) states to sequentially charge and discharge specific lines, creating a scanning sequence that isolates individual capacitive nodes without requiring additional diodes or multiplexers. A finger touch alters the local capacitance by coupling to ground, which is detected as a change in the charge or discharge time of the node; if the measured time exceeds a predefined threshold, it indicates a touch event. This approach leverages the inherent capacitance between traces in a diagonal or asymmetric matrix configuration, allowing for self-capacitive sensing where each node operates independently during its scan cycle.[28] Implementation involves the MCU driving one pin high to charge a trace while setting others to high-impedance or low states to prevent interference, then measuring the discharge time on a sense pin using an internal timer or ADC to quantify capacitance variations. For instance, during sequential scanning, the MCU cycles through all possible pin combinations (e.g., pin 1 high and pin 2 sense, with others tri-stated), timing how long it takes for the voltage to drop below a reference level; increased capacitance from a touch slows this process, triggering detection logic. This tri-state scanning minimizes pin usage compared to traditional row-column matrices, as inactive pins float without affecting active measurements. Self-capacitive keypads exemplify this, where 4 pins can support up to 10 keys by utilizing both single-pin sensors (4 keys) and intersection nodes (6 keys) in a charlieplexed arrangement, scanned rapidly to maintain responsiveness. However, multi-touch is limited, as simultaneous touches on adjacent nodes can cause crosstalk or ghosting, typically restricting reliable detection to isolated or widely spaced contacts unless advanced noise filtering is applied.[28][29] In modern low-pin-count IoT devices, such as wearables and smart home interfaces, charlieplexing-based projected capacitance has gained relevance post-2010 through MCU advancements like integrated high-resolution timers and auto-tuning algorithms, enabling precise timing measurements with reduced power consumption. For example, MCUs with enhanced peripherals, such as Atmel's QTouch Charge Transfer method, allow single-pin-per-channel sensing that scales to matrices via tri-state control, supporting wake-on-touch for battery-powered UIs. These developments have facilitated seamless integration into resource-constrained systems, providing robust touch detection over distances up to several centimeters while maintaining low latency. As of 2023, integrations in ARM Cortex-M based MCUs have expanded use in edge AI devices for gesture recognition.[30][29][31]GuGaplexing and Chipiplexing
GuGaplexing is a multiplexing technique that extends Charlieplexing by incorporating additional discrete components to double the number of controllable LEDs while using the same number of microcontroller I/O pins. Developed by Dhananjay V. Gadre, it employs N–1 pairs of complementary transistors (such as NPN and PNP types) to generate inverted signal versions, enabling the use of both low-low and high-high pin states alongside the traditional low-high and high-low combinations. This allows control of 2×N×(N–1) LEDs with N pins, for example, 24 LEDs with 4 pins, compared to Charlieplexing's N×(N–1). The method requires the LED forward voltage to exceed half the supply voltage to ensure proper isolation between states, and it maintains the one-LED-at-a-time activation typical of Charlieplexing.[32] Chipiplexing, coined by Guillermo Jaquenod, is another variant that modifies Charlieplexing to enable simultaneous activation of multiple LEDs, addressing limitations in brightness and peak current by distributing the load across time slots. It uses N microcontroller ports paired with N bipolar transistors (typically PNP with base-emitter resistors) to create a fixed low-voltage reference, allowing up to N+1 LEDs to illuminate concurrently when ports are set high, while high-impedance states turn them off. For instance, with 3 ports, it drives 4 LEDs at once, providing a 30% duty cycle per LED for 5 ports versus Charlieplexing's 5%, which reduces peak currents proportionally. This approach adds hardware overhead but simplifies software by permitting grouped LED control without complex sequencing.[33] In comparison, GuGaplexing prioritizes maximizing LED count per pin at the cost of additional transistor pairs for signal inversion, whereas Chipiplexing emphasizes improved duty cycles and multi-LED operation through transistor-based voltage referencing, trading some pin efficiency for enhanced brightness uniformity. Both variants emerged in the late 2000s from electronics design communities: GuGaplexing was introduced in an EDN Design Idea in October 2008 by Gadre, building on hacker interest in pin-efficient displays, while Chipiplexing appeared in a November 2008 EDN article by Jaquenod. Commercial integrated solutions like the Maxim MAX6968, an 8-port open-drain constant-current LED driver released around 2005, automate tri-state functionality similar to Chipiplexing principles, enabling multiplexed LED arrays with minimal external components and serial interfacing for up to 55 mA per output.[32][33][34]Cross-plexing, Tucoplexing, and PWM Adaptations
Cross-plexing represents a hybrid approach that integrates Charlieplexing principles with traditional row-column multiplexing to drive larger LED arrays while selectively employing tri-state logic on specific lines for efficiency. This variant optimizes pin usage by treating portions of the array as a standard matrix for high-density regions and applying tri-state control to expand addressing without proportional increases in I/O requirements. For instance, the AS1130 LED driver IC from ams OSRAM utilizes cross-plexing to control 132 LEDs across 12 lines by exploiting the unidirectional forward bias of LEDs, configuring pins alternately as sources or sinks in a cross-connected topology.[35] Tucoplexing extends Charlieplexing through time-division multiplexing combined with RC-based sensing and UART-like serial protocols, enabling efficient control of both outputs and inputs over extended distances, such as in remote LED matrices or switch arrays. In this method, a base 3-wire Charlieplexed setup drives 4 LEDs while simultaneously scanning 4 buttons via rapid line toggling to detect shorts, followed by capacitor charging to differentiate presses; serial expansion propagates control signals to off-board nodes, reducing local pin demands. Developed for compact remote interfaces, Tucoplexing achieves this with minimal overhead, as demonstrated in firmware implementations for USB switch controllers.[36] PWM adaptations enhance Charlieplexing by modulating the duration each LED is active within its scan cycle, allowing for analog-like dimming and up to 8-bit grayscale resolution without additional hardware. This technique allocates variable on-time slots during the multiplex period, where the duty cycle determines perceived brightness; for example, in an 8-bit system, the formula integrates as \text{Duty} = \left( \frac{\text{on_time}}{\text{scan_period}} \right) \times 255, ensuring smooth intensity control across the array. Commercial drivers like the IS31FL3731 from ISSI Microelectronics incorporate this for 144-LED matrices, supporting per-LED PWM at frequencies up to 1 kHz via I²C configuration, a method widely adopted in displays and indicators since the early 2010s.[37]Practical Examples
Code Implementation Example
A practical implementation of Charlieplexing in software can be demonstrated using C code for an Arduino microcontroller, controlling 12 LEDs connected to 4 pins (yielding LEDs for ). This example uses tri-state logic on digital pins 8 through 11, configured via a predefined matrix that specifies pin modes (OUTPUT or INPUT for high-impedance) and states (HIGH or LOW) for each LED. The code scans through all LEDs sequentially in a loop, activating one at a time to multiplex the display and prevent flicker when delays are minimized.[13] The following code initializes pins as INPUT in setup for high-impedance, with tri-state control occurring dynamically in thelightOn function, followed by an allOff call to ensure proper deactivation. It includes inline comments explaining the state configurations, where each LED corresponds to a unique pair of pins: one driven HIGH (anode) and the other LOW (cathode), with unused pins in INPUT mode (high-impedance). For robustness, an error check could be added in production code to validate LED indices against the matrix size, though this basic version assumes valid inputs within 0 to 11.
// Charlieplexing example for 4 pins controlling 12 LEDs
// Pins: A=8 (anode/cathode for LEDs 0,1,4,6), B=9, C=10, D=11
#define A 8
#define B 9
#define C 10
#define D 11
#define PIN_CONFIG 0 // Index for pin modes (OUTPUT=drive, INPUT=high-impedance)
#define PIN_STATE 1 // Index for logic levels (HIGH=anode, LOW=cathode)
#define LED_NUM 12 // Total LEDs: N*(N-1) for N=4
// 3D array: [LED][config/state][pin A/B/C/D]
// Each LED row defines modes and states to light only that LED
int matrix[LED_NUM][2][4] = {
// LED 0: A high, B low (others input)
{ {OUTPUT, OUTPUT, INPUT, INPUT}, {HIGH, LOW, LOW, LOW} },
// LED 1: B high, A low
{ {OUTPUT, OUTPUT, INPUT, INPUT}, {LOW, HIGH, LOW, LOW} },
// LED 2: B high, C low
{ {INPUT, OUTPUT, OUTPUT, INPUT}, {LOW, HIGH, LOW, LOW} },
// LED 3: C high, B low
{ {INPUT, OUTPUT, OUTPUT, INPUT}, {LOW, LOW, HIGH, LOW} },
// LED 4: A high, C low
{ {OUTPUT, INPUT, OUTPUT, INPUT}, {HIGH, LOW, LOW, LOW} },
// LED 5: C high, A low
{ {OUTPUT, INPUT, OUTPUT, INPUT}, {LOW, LOW, HIGH, LOW} },
// LED 6: A high, D low
{ {OUTPUT, INPUT, INPUT, OUTPUT}, {HIGH, LOW, LOW, LOW} },
// LED 7: D high, A low
{ {OUTPUT, INPUT, INPUT, OUTPUT}, {LOW, LOW, LOW, HIGH} },
// LED 8: B high, D low
{ {INPUT, OUTPUT, INPUT, OUTPUT}, {LOW, HIGH, LOW, LOW} },
// LED 9: D high, B low
{ {INPUT, OUTPUT, INPUT, OUTPUT}, {LOW, LOW, LOW, HIGH} },
// LED 10: C high, D low
{ {INPUT, INPUT, OUTPUT, OUTPUT}, {LOW, LOW, HIGH, LOW} },
// LED 11: D high, C low
{ {INPUT, INPUT, OUTPUT, OUTPUT}, {LOW, LOW, LOW, HIGH} }
};
void lightOn(int led) {
// Error handling: Ensure valid LED index
if (led < 0 || led >= LED_NUM) {
return; // Skip invalid requests to avoid pin misconfiguration
}
// Set pin modes for tri-state: OUTPUT for active pins, INPUT for off
pinMode(A, matrix[led][PIN_CONFIG][0]);
pinMode(B, matrix[led][PIN_CONFIG][1]);
pinMode(C, matrix[led][PIN_CONFIG][2]);
pinMode(D, matrix[led][PIN_CONFIG][3]);
// Apply logic states: HIGH/LOW only on OUTPUT pins
digitalWrite(A, matrix[led][PIN_STATE][0]);
digitalWrite(B, matrix[led][PIN_STATE][1]);
digitalWrite(C, matrix[led][PIN_STATE][2]);
digitalWrite(D, matrix[led][PIN_STATE][3]);
}
void allOff() {
// Set all pins to INPUT for high-impedance off state
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(C, INPUT);
pinMode(D, INPUT);
}
void setup() {
// Initial pin setup to high-impedance
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(C, INPUT);
pinMode(D, INPUT);
}
void loop() {
// Scan all LEDs sequentially for [multiplexing](/page/Multiplexing)
for (int l = 0; l < LED_NUM; l++) {
lightOn(l); // Activate specific LED via matrix config
delay(1000 / LED_NUM); // ~83 ms per LED for visible sequential lighting; reduce to ~1 ms for flicker-free multiplex
allOff(); // Deactivate all LEDs before next activation
}
// Full cycle repeats; total time ~1 second with above delay, but <1 ms per state transition in optimized use
}
// Charlieplexing example for 4 pins controlling 12 LEDs
// Pins: A=8 (anode/cathode for LEDs 0,1,4,6), B=9, C=10, D=11
#define A 8
#define B 9
#define C 10
#define D 11
#define PIN_CONFIG 0 // Index for pin modes (OUTPUT=drive, INPUT=high-impedance)
#define PIN_STATE 1 // Index for logic levels (HIGH=anode, LOW=cathode)
#define LED_NUM 12 // Total LEDs: N*(N-1) for N=4
// 3D array: [LED][config/state][pin A/B/C/D]
// Each LED row defines modes and states to light only that LED
int matrix[LED_NUM][2][4] = {
// LED 0: A high, B low (others input)
{ {OUTPUT, OUTPUT, INPUT, INPUT}, {HIGH, LOW, LOW, LOW} },
// LED 1: B high, A low
{ {OUTPUT, OUTPUT, INPUT, INPUT}, {LOW, HIGH, LOW, LOW} },
// LED 2: B high, C low
{ {INPUT, OUTPUT, OUTPUT, INPUT}, {LOW, HIGH, LOW, LOW} },
// LED 3: C high, B low
{ {INPUT, OUTPUT, OUTPUT, INPUT}, {LOW, LOW, HIGH, LOW} },
// LED 4: A high, C low
{ {OUTPUT, INPUT, OUTPUT, INPUT}, {HIGH, LOW, LOW, LOW} },
// LED 5: C high, A low
{ {OUTPUT, INPUT, OUTPUT, INPUT}, {LOW, LOW, HIGH, LOW} },
// LED 6: A high, D low
{ {OUTPUT, INPUT, INPUT, OUTPUT}, {HIGH, LOW, LOW, LOW} },
// LED 7: D high, A low
{ {OUTPUT, INPUT, INPUT, OUTPUT}, {LOW, LOW, LOW, HIGH} },
// LED 8: B high, D low
{ {INPUT, OUTPUT, INPUT, OUTPUT}, {LOW, HIGH, LOW, LOW} },
// LED 9: D high, B low
{ {INPUT, OUTPUT, INPUT, OUTPUT}, {LOW, LOW, LOW, HIGH} },
// LED 10: C high, D low
{ {INPUT, INPUT, OUTPUT, OUTPUT}, {LOW, LOW, HIGH, LOW} },
// LED 11: D high, C low
{ {INPUT, INPUT, OUTPUT, OUTPUT}, {LOW, LOW, LOW, HIGH} }
};
void lightOn(int led) {
// Error handling: Ensure valid LED index
if (led < 0 || led >= LED_NUM) {
return; // Skip invalid requests to avoid pin misconfiguration
}
// Set pin modes for tri-state: OUTPUT for active pins, INPUT for off
pinMode(A, matrix[led][PIN_CONFIG][0]);
pinMode(B, matrix[led][PIN_CONFIG][1]);
pinMode(C, matrix[led][PIN_CONFIG][2]);
pinMode(D, matrix[led][PIN_CONFIG][3]);
// Apply logic states: HIGH/LOW only on OUTPUT pins
digitalWrite(A, matrix[led][PIN_STATE][0]);
digitalWrite(B, matrix[led][PIN_STATE][1]);
digitalWrite(C, matrix[led][PIN_STATE][2]);
digitalWrite(D, matrix[led][PIN_STATE][3]);
}
void allOff() {
// Set all pins to INPUT for high-impedance off state
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(C, INPUT);
pinMode(D, INPUT);
}
void setup() {
// Initial pin setup to high-impedance
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(C, INPUT);
pinMode(D, INPUT);
}
void loop() {
// Scan all LEDs sequentially for [multiplexing](/page/Multiplexing)
for (int l = 0; l < LED_NUM; l++) {
lightOn(l); // Activate specific LED via matrix config
delay(1000 / LED_NUM); // ~83 ms per LED for visible sequential lighting; reduce to ~1 ms for flicker-free multiplex
allOff(); // Deactivate all LEDs before next activation
}
// Full cycle repeats; total time ~1 second with above delay, but <1 ms per state transition in optimized use
}
digitalWrite and pinMode incur negligible overhead (~microseconds per call), allowing refresh rates above 60 Hz for smooth visuals.[13]
