Чарлиплексирование — это интересный метод, позволяющий использовать большое количество светодиодов, чем контактов микроконтроллера.
В его основе лежит логика трех состояний портов ввода-вывода, чтобы значительно уменьшить количество контактов и повысить эффективность по сравнению с мультиплексированием:
- 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); }