Панель режимов на самодельном приборе: шесть светодиодов, а свободных пинов осталось три — всё съели шина и сервопривод. Сдвиговый регистр из урока про 74HC595 и shiftOut — верный путь, но ради шести огоньков тащить микросхему, резисторы и лишние провода жалко, когда вся техника помещается в шести строчках pinMode. Charlieplexing — приём, которым производители бюджетных игрушек пользуются десятилетиями: три пина, шесть диодов, ноль микросхем, и каждый диод сидит между парой пинов напрямую.
Идея вырастает из свойства пина, о котором забывают: у него три состояния, а не два. OUTPUT HIGH, OUTPUT LOW — и INPUT, который по факту Hi-Z, «отключён»: мегаомное сопротивление, ток не течёт. Чтобы зажечь диод между пинами A и B, пин A становится OUTPUT HIGH, пин B — OUTPUT LOW, а третий пин уходит в INPUT (Hi-Z) и из схемы выпадает. Смена направления пина на лету — pinMode туда-сюда посреди loop() — и есть вся магия техники.
Арифметика прироста: N пинов несут N·(N−1) диодов — 3 пина дают шесть, 4 пина двенадцать, 5 пинов двадцать. План урока: таблица адресации и код с перестановкой pinMode, мультиплексирование с инерцией зрения и расчёт duty, цена техники — сквозной ток при забытом Hi-Z и размытые фазы, если позвать delay() в середине кадра.
Три состояния пина и таблица пар
Разберём, почему Hi-Z выпадает из схемы. Диод между D9 и D10, анодом к D9. Зажигаем: D9 — OUTPUT HIGH, D10 — OUTPUT LOW, ток идёт через диод. Третий пин D11 — INPUT: внутри него не выход, а вход с мегаомным сопротивлением. Через D11 ток не потечёт ни в какую сторону: в сторону D10 его диод развёрнут навстречу, а в сторону D9 у D11 нет выхода — он вход. Схема видит два активных пина и одного призрака. Стоит же оставить D11 в OUTPUT LOW — он станет вторым катодом: через диод D9→D11 потечёт лишний ток, загорятся два огонька сразу, а резистор на пинах один — вот тебе и сквозной ток, об этом ниже отдельным примечанием.
Встречная пара — сердце техники. Между D9 и D10 сидят два диода навстречу друг другу: анод-катод и катод-анод. D9 HIGH / D10 LOW зажигает первый, D10 HIGH / D9 LOW — второй. Каждая пара пинов несёт два диода, пар на трёх пинах три: D9-D10, D10-D11, D9-D11 — шесть адресов. Обратная сторона: диод между D9 и D11 горит, только пока D10 в Hi-Z — сделаешь D10 OUTPUT LOW, и он перетянет потенциал на себя: сосед подмигнёт, нужный потускнеет. Отсюда железное правило: активна ровно одна пара пинов, все остальные — INPUT.
Шесть диодов одновременно без потери яркости не зажечь — светят по очереди, по фазе на кадр. Инерция зрения (persistence of vision) держит картинку примерно 40 мс: кадр из шести фаз по 3 мс укладывается в 18 мс — глаз видит все шесть горящими разом. Duty каждой фазы — 1/6, поэтому для былой яркости пик тока поднимают вшестеро: вместо 5 мА — 30 мА пиковых; средний ток не меняется, считай по уроку про ШИМ и analogWrite. А переключение фаз веди на millis() из урока про millis() вместо delay(): delay() внутри кадра размазывает фазы и роняет яркость — разберём ниже.
// Charlieplexing: 6 светодиодов на 3 пинах, бегущий огонёк.// pinMode-перестановки движок симулятора не исполняет - скетч для Arduino IDE.const byte PINS[3] = {9, 10, 11};const byte KADR[6][2] = { // [анод, катод] для каждого диода {9, 10}, {10, 9}, // встречная пара на D9-D10 {10, 11}, {11, 10}, // встречная пара на D10-D11 {9, 11}, {11, 9}, // встречная пара на D9-D11}; void svetOdin(byte nomer) { for (byte i = 0; i < 3; i++) pinMode(PINS[i], INPUT); // все в Hi-Z pinMode(KADR[nomer][0], OUTPUT); digitalWrite(KADR[nomer][0], HIGH); pinMode(KADR[nomer][1], OUTPUT); digitalWrite(KADR[nomer][1], LOW);} void setup() { Serial.begin(9600); } void loop() { for (byte k = 0; k < 6; k++) { svetOdin(k); Serial.print("Горит диод "); Serial.print(k); Serial.print(": анод D"); Serial.print(KADR[k][0]); Serial.print(" -> катод D"); Serial.println(KADR[k][1]); delay(500); // статичная демонстрация по 0,5 с }}Разбор по строкам. svetOdin() начинается с зачистки: все три пина уходят в INPUT — так прошлая фаза гарантированно мертва, и никакой третий пин не притянет потенциал. Дальше две строки зажигания: анод — OUTPUT HIGH, катод — OUTPUT LOW; третий пин остаётся INPUT, и ток идёт ровно по одному пути. Резисторы ставь по одному на каждый пин (три штуки по 100-220 Ом при 5 В) — ток течёт через пару, и один резистор всегда в цепи, где бы ни горел диод. Резистор в разрыв каждого диода вместо пинных шести не нужен: встречные пары не горят одновременно.
Про яркость и пики тока. Статичный огонёк из скетча жрёт полный ток: (5 В − 2 В на диоде) / 150 Ом ≈ 20 мА — предел комфортный для пина ATmega, datasheet обещает до 40 мА абзацем выше рекомендуемых. Мультиплекс шестёрки ставит duty 1/6: чтобы средний ток диода вернулся к былым 5 мА, пик нужен 30 мА — впритык к разумному, ещё один диод на этих трёх пинах — и резисторы придётся ужесточать, а яркость терять. Отсюда моё мнение: charlieplexing — территория до десятка диодов; дальше честнее 74HC595 из соседнего урока.
Фазы против delay(). Статичная демонстрация с delay(500) жива, но гирлянда на millis()-планировщике фазы не размазывает: кадр 18 мс из шести фаз по 3 мс — и loop() свободен. Хочешь ещё стабильнее — переложи смену фаз в прерывание таймера, карта в обзоре таймеров ATmega328. Кнопку листания кадров обрабатывай по уроку про антидребезг четырьмя способами — дребезг на переключателе фаз выглядит как пропущенный кадр, и искать его в гирлянде мучительно.
| Диод | D9 | D10 | D11 | Где живёт |
|---|---|---|---|---|
| 0 | OUTPUT HIGH | OUTPUT LOW | INPUT Hi-Z | пара D9-D10, анод к D9 |
| 1 | OUTPUT LOW | OUTPUT HIGH | INPUT Hi-Z | пара D9-D10, анод к D10 |
| 2 | INPUT Hi-Z | OUTPUT HIGH | OUTPUT LOW | пара D10-D11, анод к D10 |
| 3 | INPUT Hi-Z | OUTPUT LOW | OUTPUT HIGH | пара D10-D11, анод к D11 |
| 4 | OUTPUT HIGH | INPUT Hi-Z | OUTPUT LOW | пара D9-D11, анод к D9 |
| 5 | OUTPUT LOW | INPUT Hi-Z | OUTPUT HIGH | пара D9-D11, анод к D11 |
- 1. Сколько светодиодов несут 4 пина в charlieplexing?
- 2. Почему третий пин в Hi-Z не портит горящий диод?
- 3. Кадр из шести фаз по 3 мс. Что видит глаз и чего стоит яркость?
- N пинов несут N(N−1) диодов: 3 пина — 6, 4 — 12; каждая пара пинов — два встречных диода
- зажигание: анод OUTPUT HIGH, катод OUTPUT LOW, остальные пины INPUT (Hi-Z); перед каждым кадром все пины в INPUT
- забытый OUTPUT на третьем пине — сквозной ток и горящие соседи; Hi-Z обязателен
- фазы по 2-3 мс на millis() или таймере: кадр меньше инерции зрения, duty 1/6 — пик тока вшестеро выше среднего
Частые вопросы по теме урока
- Сколько светодиодов несут 4 пина в charlieplexing?
- Каждая пара пинов несёт два встречных диода, пар у N пинов — N(N−1)/2, диодов вдвое больше: N(N−1). Четыре пина — 12 адресов, пять — 20. 12 — по формуле N·(N−1) = 4·3
- Почему третий пин в Hi-Z не портит горящий диод?
- INPUT — третье состояние: не источник, не сток, сопротивление мегаомы. Ток течёт только между двумя OUTPUT-пинами активной пары. вход с мегаомным сопротивлением не даёт току пути — он выпадает из схемы
- Кадр из шести фаз по 3 мс. Что видит глаз и чего стоит яркость?
- Кадр 6 × 3 мс = 18 мс — меньше ~40 мс инерции зрения, мерцания глазу нет. Каждый диод горит 1/6 времени: для былой яркости пик тока поднимают вшестеро. глаз видит все шесть горящими: кадр 18 мс меньше инерции зрения, а каждый диод светит с duty 1/6