Чарлиплексирование — это интересный метод, позволяющий использовать большое количество светодиодов, чем контактов микроконтроллера.
В его основе лежит логика трех состояний портов ввода-вывода, чтобы значительно уменьшить количество контактов и повысить эффективность по сравнению с мультиплексированием:
- H – контакт настраивается на выход, который переводится в высокие состояние (в логическую 1);
- L – контакт настраивается на выход, который переводится в низкое состояние (в логический 0);
- Z – контакт настраивается как высокоимпендансный вход (т.е. очень большое сопротивление порта, этот режим включен по умолчанию).
Метод носит название от своего изобретателя Чарли Аллена, который изобрел его в 1995 году.
Чарлиплексирование позволяет управлять светодиодами в количестве, рассчитанной по формуле:
где N — количество используемых контактов.
Например, для управления 12-ю светодиодами нам необходимо использовать всего лишь 4 контакта контроллера:
По своей сути, светодиоды — это диоды, а в диодах, как известно, ток протекает только в одном направлении. Это свойство и используется в чарлиплексинге. Мы подключаем два светодиода параллельно друг другу, но с противоположной полярностью, чтобы одновременно включался только один светодиод.
Если вы работаете над проектом, в котором вам нужно подключить ЖК-дисплей, кучу светодиодов и датчиков, то у вас может не хватить на все свободных контактов. В этой ситуации вы можете подключить светодиоды по методу чарлиплексинга, чтобы уменьшить количество используемых контактов.
В примере ниже мы будем использовать метод Charlieplexing для управления 6 светодиодами с помощью 3-х выводов в программе Proteus.
Использование метода Чарлиплексинга в Proteus
Добавим 3 пары светодиодов на рабочую область и подключим как показано на рисунке 1. Механические переключатели будем использовать для имитации Z-состояния (высокоомного состояния). Логическими переключателями будем устанавливать соответствующие уровни: ВЫСОКИЙ или НИЗКИЙ.

Состояния, которые должны быть установлены на входах для конкретного светодиода, указаны в Таблице 1. На рисунке 1 Вход 1 расположен сверху, Вход 2 – по-центру, Вход 3 – снизу.
| Светодиод | Вход 1 | Вход 2 | Вход 3 |
|---|---|---|---|
| Все отключены | LOW | LOW | LOW |
| D1 | LOW | HIGH | Z |
| D2 | HIGH | LOW | Z |
| D3 | Z | LOW | HIGH |
| D4 | Z | HIGH | LOW |
| D5 | LOW | Z | HIGH |
| D6 | HIGH | Z | LOW |
Видео с симуляцией в протеусе:
Чарлиплексинг и Ардуино
Попробуем в протеусе посмотреть как работает метод с микроконтроллером, а точнее с платой Arduino. Если мы будем использовать 4 контакта платы, то сможем управлять двенадцатью светодиодами (формула выше).
Подключать светодиоды будем по следующей схеме:

На схеме ниже вы можете увидеть 12 светодиодов подключены к 4 контактам Arduino через токоограничивающие резисторы. Всего на схеме имеется шесть пар светодиодов. В каждой паре соединено параллельно по 2 светодиода, но с противоположной полярностью. Так что одновременно включается только один из двух светодиодов.

Таким образом, чтобы включить светодиод D1 мы должны установить на контакте 9 ВЫСОКИЙ уровень напряжения, на контакте 8 – НИЗКИЙ, а контакты 10 и 11 должны быть отключены (то есть должны быть переведены в состояние высокого импеданса, или по-другому в Z-состояние, в нашем случае с платой Ардуино – вывод должен быть настроен как вход INPUT). Тот же принцип используется для включения других светодиодов. Полная таблица истинности состояния контактов для каждого светодиода приведена ниже:
| Светодиод | Контакт 8 | Контакт 9 | Контакт 10 | Контакт 11 |
|---|---|---|---|---|
| D1 | LOW | HIGH | INPUT | INPUT |
| D2 | HIGH | LOW | INPUT | INPUT |
| D3 | INPUT | INPUT | LOW | HIGH |
| D4 | INPUT | INPUT | HIGH | LOW |
| D5 | INPUT | LOW | HIGH | INPUT |
| D6 | INPUT | HIGH | LOW | INPUT |
| D7 | LOW | INPUT | HIGH | INPUT |
| D8 | HIGH | INPUT | LOW | INPUT |
| D9 | INPUT | LOW | INPUT | HIGH |
| D10 | INPUT | HIGH | INPUT | LOW |
| D11 | LOW | INPUT | INPUT | HIGH |
| D12 | HIGH | INPUT | INPUT | LOW |
Скетч для управления светодиодами
Полный код с видео приведен в конце этой статьи, а сейчас проясним код, чтобы понять работу проекта.
В начале определяем все контакты, к которым подключены светодиоды.
// Контакты, к которым подключены светодиоды
int pins[] = {8, 9, 10, 11};
Теперь создаем трехмерный массив, в котором хранятся значения режимов работы и состояния контактов для каждого светодиода. Первый индекс от 0 до 11 – выбор светодиода светодиода, второй индекс 0 или 1 – выбор между массивами режимов работы и состояния контактов. Третий индекс от 0 до 3 – конкретное значение для контакта. Например, в элементе массива states[0][1][1] хранится значение HIGH; в элементе массива state[3][0][1] – хранится значение INPUT.
Про массивы в Ардуино можно почитать здесь.
// Состояние контактов для каждого светодиода, согласно таблице истинности
int states[12][2][4] = {
// D1
{ { OUTPUT, OUTPUT, INPUT, INPUT }, { LOW, HIGH, LOW, LOW } },
// D2
{ { OUTPUT, OUTPUT, INPUT, INPUT }, { HIGH, LOW, LOW, LOW } },
// D3
{ { INPUT, INPUT, OUTPUT, OUTPUT }, { LOW, LOW, LOW, HIGH } },
// D4
{ { INPUT, INPUT, OUTPUT, OUTPUT }, { LOW, LOW, HIGH, LOW } },
// D5
{ { INPUT, OUTPUT, OUTPUT, INPUT }, { LOW, LOW, HIGH, LOW } },
// D6
{ { INPUT, OUTPUT, OUTPUT, INPUT }, { LOW, HIGH, LOW, LOW } },
// D7
{ { OUTPUT, INPUT, OUTPUT, INPUT }, { LOW, LOW, HIGH, LOW } },
// D8
{ { OUTPUT, INPUT, OUTPUT, INPUT }, { HIGH, LOW, LOW, LOW } },
// D9
{ { INPUT, OUTPUT, INPUT, OUTPUT }, { LOW, LOW, LOW, HIGH } },
// D10
{ { INPUT, OUTPUT, INPUT, OUTPUT }, { LOW, HIGH, LOW, LOW } },
// D11
{ { OUTPUT, INPUT, INPUT, OUTPUT }, { LOW, LOW, LOW, HIGH } },
// D12
{ { OUTPUT, INPUT, INPUT, OUTPUT }, { HIGH, LOW, LOW, LOW } }
};
Функция ledOn принимает значение number – это номер светодиода (отсчет начинается от 0 до 11), а затем с помощью функции pinMode настраивает режим работы контактов (согласно нашему массиву), а с помощью функции digitalWrite устанавливает состояние контакта (либо высокий уровень, либо низкий).
void ledOn( int number ) {
if(number > 11) return;
pinMode( pins[0], states[number][0][0] );
pinMode( pins[1], states[number][0][1] );
pinMode( pins[2], states[number][0][2] );
pinMode( pins[3], states[number][0][3] );
digitalWrite( pins[0], states[number][1][0] );
digitalWrite( pins[1], states[number][1][1] );
digitalWrite( pins[2], states[number][1][2] );
digitalWrite( pins[3], states[number][1][3] );
}
Функция ledsOff – переводит все контакты в режим выхода – OUTPUT и устанавливает на всех контактах низкий логичекий уровень LOW. Тем самым выключая все светодиоды.
void ledsOff() {
for(int i = 0; i < 4; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], LOW);
}
}
В бесконечном цикле void loop в цикле for мы поочередно включаем 12 светодиодов один за одним с задержкой в 500 миллисекунд, а затем выключаем все светодиоды.
void setup() {}
void loop() {
for( int k = 0; k < 12; k++ ) {
ledOn(k);
delay(500);
}
ledsOff();
delay(500);
}
Видео симуляции в протеусе:
Полный текст программы:
// Контакты, к которым подключены светодиоды
int pins[] = {8, 9, 10, 11};
// Состояние контактов для каждого светодиода, согласно таблице истинности
int states[12][2][4] = {
// D1
{ { OUTPUT, OUTPUT, INPUT, INPUT }, { LOW, HIGH, LOW, LOW } },
// D2
{ { OUTPUT, OUTPUT, INPUT, INPUT }, { HIGH, LOW, LOW, LOW } },
// D3
{ { INPUT, INPUT, OUTPUT, OUTPUT }, { LOW, LOW, LOW, HIGH } },
// D4
{ { INPUT, INPUT, OUTPUT, OUTPUT }, { LOW, LOW, HIGH, LOW } },
// D5
{ { INPUT, OUTPUT, OUTPUT, INPUT }, { LOW, LOW, HIGH, LOW } },
// D6
{ { INPUT, OUTPUT, OUTPUT, INPUT }, { LOW, HIGH, LOW, LOW } },
// D7
{ { OUTPUT, INPUT, OUTPUT, INPUT }, { LOW, LOW, HIGH, LOW } },
// D8
{ { OUTPUT, INPUT, OUTPUT, INPUT }, { HIGH, LOW, LOW, LOW } },
// D9
{ { INPUT, OUTPUT, INPUT, OUTPUT }, { LOW, LOW, LOW, HIGH } },
// D10
{ { INPUT, OUTPUT, INPUT, OUTPUT }, { LOW, HIGH, LOW, LOW } },
// D11
{ { OUTPUT, INPUT, INPUT, OUTPUT }, { LOW, LOW, LOW, HIGH } },
// D12
{ { OUTPUT, INPUT, INPUT, OUTPUT }, { HIGH, LOW, LOW, LOW } }
};
void ledOn( int number ) {
if(number > 11) return;
pinMode( pins[0], states[number][0][0] );
pinMode( pins[1], states[number][0][1] );
pinMode( pins[2], states[number][0][2] );
pinMode( pins[3], states[number][0][3] );
digitalWrite( pins[0], states[number][1][0] );
digitalWrite( pins[1], states[number][1][1] );
digitalWrite( pins[2], states[number][1][2] );
digitalWrite( pins[3], states[number][1][3] );
}
void ledsOff() {
for(int i = 0; i < 4; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], LOW);
}
}
void setup() {}
void loop() {
for( int k = 0; k < 12; k++ ) {
ledOn(k);
delay(500);
}
ledsOff();
delay(500);
}


