Чарлиплексинг

Чарлиплексинг

Чарлиплексирование — это интересный метод, позволяющий использовать большое количество светодиодов,  чем контактов микроконтроллера.

В его основе лежит логика трех состояний портов ввода-вывода, чтобы значительно уменьшить количество контактов и повысить эффективность по сравнению с мультиплексированием:

  • H — контакт настраивается на выход, который переводится в высокие состояние (в логическую 1);
  • L — контакт настраивается на выход, который переводится в низкое состояние (в логический 0);
  • Z — контакт настраивается как высокоимпендансный вход (т.е. очень большое сопротивление порта, этот режим включен по умолчанию).

Метод носит название от своего изобретателя Чарли Аллена, который изобрел его в 1995 году.

Чарлиплексирование позволяет управлять светодиодами в количестве, рассчитанной по формуле:

\[N \times (N — 1)\]

где N — количество используемых контактов.

Например, для управления 12-ю светодиодами нам необходимо использовать всего лишь 4 контакта контроллера:

\[4 \times (4-1) = 12\]

По своей сути, светодиоды — это диоды, а в диодах, как известно, ток протекает только в одном направлении. Это свойство и используется в чарлиплексинге. Мы подключаем два светодиода параллельно друг другу, но с противоположной полярностью, чтобы одновременно включался только один светодиод.

Если вы работаете над проектом, в котором вам нужно подключить ЖК-дисплей, кучу светодиодов и датчиков, то у вас может не хватить на все свободных контактов. В этой ситуации вы можете подключить светодиоды по методу чарлиплексинга, чтобы уменьшить количество используемых контактов.

В примере ниже мы будем использовать метод Charlieplexing для управления 6 светодиодами с помощью 3-х выводов в программе Proteus.

Использование метода Чарлиплексинга в Proteus

Добавим 3 пары светодиодов на рабочую область и подключим как показано на рисунке 1. Механические переключатели будем использовать для имитации Z-состояния (высокоомного состояния). Логическими переключателями будем устанавливать соответствующие уровни: ВЫСОКИЙ или НИЗКИЙ.

Чарлиплексинг в протеусе
Рисунок 1. Простая схема для демонстрации работы Чарлиплексинга в программе Proteus

Состояния, которые должны быть установлены на входах для конкретного светодиода, указаны в Таблице 1. На рисунке 1 Вход 1 расположен сверху, Вход 2 — по-центру, Вход 3 — снизу.

СветодиодВход 1Вход 2Вход 3
Все отключеныLOWLOWLOW
D1LOWHIGHZ
D2HIGHLOWZ
D3ZLOWHIGH
D4ZHIGHLOW
D5LOWZHIGH
D6HIGHZLOW
Таблица 1. Таблица истинности для включения светодиодов по методу Чарлиплексинга. LOW — низкий уровень напряжения, HIGH — высокий уровень напряжения, Z — высокоомное состояние.

Видео с симуляцией в протеусе:

https://youtu.be/dMLbiXVyTIM

Чарлиплексинг и Ардуино

Попробуем в протеусе посмотреть как работает метод с микроконтроллером, а точнее с платой Arduino. Если мы будем использовать 4 контакта платы, то сможем управлять двенадцатью светодиодами (формула выше).

Подключать светодиоды будем по следующей схеме:

Чарлиплексинг. 4 контакта и 12 светодиодов
Рисунок 2. Схема подключения 12 светодиодов по методу Чарлиплексинга

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

Подключение 12 светодиодов к ардуино нано
Рисунок 3. Схема подключения светодиодов к Ардуино

Таким образом, чтобы включить светодиод D1 мы должны установить на контакте 9 ВЫСОКИЙ уровень напряжения, на контакте 8НИЗКИЙ, а контакты 10 и 11 должны быть отключены (то есть должны быть переведены в состояние высокого импеданса, или по-другому в Z-состояние, в нашем случае с платой Ардуино — вывод должен быть настроен как вход INPUT). Тот же принцип используется для включения других светодиодов. Полная таблица истинности состояния контактов для каждого светодиода приведена ниже:

СветодиодКонтакт 8Контакт 9Контакт 10Контакт 11
D1LOWHIGHINPUTINPUT
D2HIGHLOWINPUTINPUT
D3INPUTINPUTLOWHIGH
D4INPUTINPUTHIGHLOW
D5INPUTLOWHIGHINPUT
D6INPUTHIGHLOWINPUT
D7LOWINPUTHIGHINPUT
D8HIGHINPUTLOWINPUT
D9INPUTLOWINPUTHIGH
D10INPUTHIGHINPUTLOW
D11LOWINPUTINPUTHIGH
D12HIGHINPUTINPUTLOW
Таблица 2. Таблица истинности для светодиодов

Скетч для управления светодиодами

Полный код с видео приведен в конце этой статьи, а сейчас проясним код, чтобы понять работу проекта.

В начале определяем все контакты, к которым подключены светодиоды.

// Контакты, к которым подключены светодиоды
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);
}
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии