Семисегментный индикатор прожорливее любой гирлянды: семь сегментов плюс точка — восемь линий управления, и это ровно один байт. Пара 595 и индикатор складывается так аккуратно не по красоте, а по арифметике: регистр отдаёт ровно восемь выходов, индикатор просит ровно восемь, и ни один провод не гуляет. Классика макеток, которую я собираю чаще любого датчика: счётчик, таймер на одну цифру, индикатор режима — везде та же схема с той же таблицей байтов.
С самим индикатором мы знакомились в уроке про подключение сегментника: там он сидел на семи пинах напрямую, сегмент за сегментом. Здесь между Arduino и индикатором встаёт 74HC595 из первого урока тройки — и на всё про всё остаются три провода: DS, SHCP, STCP. Те же три, что и в гирлянде, — разводить макетку заново не придётся.
Макетка собирается по обычным правилам переноса схемы, но резистор в цепи катода ставится иначе, чем в гирлянде, — и это главный практический сюрприз урока: у общего вывода индикатора своя арифметика тока. И она отличается от гирляндовой в обе стороны.
Таблица сегментов: цифра как байт
Байт раскладывается на сегменты один к одному: бит 0 — сегмент a, бит 1 — b, и так до бита 6 — g; седьмой бит остаётся точке dp. Для индикатора с общим катодом единица в бите значит «сегмент горит»: регистр выставил HIGH на выходе — светодиод сегмента светит. Общий анод зеркалит всё это, о нём — заметка ниже. С общим катодом связка удобна ещё и в уме: HIGH на выходе регистра зажигает сегмент ровно как digitalWrite зажигал бы обычный светодиод, и отладочная логика не раздваивается — семь светодиодов просто слушают семь бит.
Цифры превращаются в константы: ноль — 0b00111111 (шесть палочек по кругу, средняя спит), единица — 0b00000110, восьмёрка — 0b01111111. Таблицу из десяти байтов я держу в массиве и не выдумываю заново ни в одном проекте: скопировал, залил, работает. Точка dp на седьмом бите ждёт своего часа: счётчику она не нужна, а одноразрядному термометру 0-9 без неё не обойтись.
Порядок битов стоит проговорить заранее: при Q0-Q6 на сегментах a-g и точке на Q7 байт 0b00111111 с MSBFIRST доезжает до мест без переворотов — старший бит, он же точка, уходит первым и оседает на дальнем выходе Q7. Разведёте сегменты в другом порядке — поправьте таблицу или переключите на LSBFIRST, но сделайте это один раз и запишите в комментарий к скетчу.
| Биты байта | Сегменты | Выходы 595 | Как это выглядит |
|---|---|---|---|
| 0-2 | a, b, c | Q0-Q2 | у единицы горят только b и c: 0b00000110 |
| 3-6 | d, e, f, g | Q3-Q6 | у нуля g спит, остальные шесть горят: 0b00111111 |
| 7 | dp | Q7 | точка, пока не нужна — ноль в байте |
| общий катод | общий вывод | GND через резистор | один резистор на разряд или свой на каждый сегмент |
// Счётчик 0-9 на индикаторе с общим катодом через 74HC595.// DS -> D11, SHCP -> D12, STCP -> D8; Q0-Q6 -> a-g через резисторы 330 Ом,// общий катод -> GND (про резистор в этой цепи — текст урока).const int DS = 11;const int SHCP = 12;const int STCP = 8;const int BTN = 2; byte CIF[10] = { 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111}; int cifra = 0;int prevBtn = HIGH;unsigned long tBtn = 0; void show(byte pattern) { digitalWrite(STCP, LOW); shiftOut(DS, SHCP, MSBFIRST, pattern); digitalWrite(STCP, HIGH);} void setup() { pinMode(DS, OUTPUT); pinMode(SHCP, OUTPUT); pinMode(STCP, OUTPUT); pinMode(BTN, INPUT_PULLUP); Serial.begin(9600); show(CIF[0]);} void loop() { int btn = digitalRead(BTN); if (btn == LOW && prevBtn == HIGH && millis() - tBtn > 200) { tBtn = millis(); cifra++; if (cifra > 9) cifra = 0; show(CIF[cifra]); Serial.print("cifra="); Serial.print(cifra); Serial.print(" bajt="); Serial.println(CIF[cifra], BIN); } prevBtn = btn; delay(5);}В симуляторе ниже движок индикатор знает: он садится на семь пинов напрямую, D12-D6. Регистр движок не эмулирует и shiftOut не поддерживает, поэтому скетч раскладывает байт цифры по сегментам сам — ровно то, что после защёлки сделал бы 595 со своими Q0-Q6. Логика байта при этом общая: та же таблица, те же сдвиги и маски.
Сверьте строку bajt в мониторе с таблицей выше ещё до кнопки: ноль печатается как 111111 без ведущих нулей — это тот самый 0b00111111, у которого бит 7 и бит 6 нули. Привычка дописывать нули в голове переезжает сюда из гирлянды и пригождается каждый раз, когда байт цифры кажется короче восьми знаков. Ведущие нули — не прихоть: в мультиплексе байты цифр станут кадрами, и привычка видеть все восемь бит сбережёт нервы.
На каждый шаг в мониторе печатается байт цифры. Сверьте его с таблицей выше: у шестёрки горят шесть сегментов, у единицы два — разница между цифрами видна и в байте, и на индикаторе. Кнопка крутит кольцо 0-9, на девятке снова ноль, и ни одна цифра не требует от loop лишних строк. Антидребезг на millis стоит здесь не для красоты: окно в двести миллисекунд съедает дребезг контактов, и одно нажатие даёт ровно один шаг кольца. Кольцо — это ещё и защита массива: без проверки cifra > 9 обращение CIF[10] молча читало бы чужую память.
На реальной плате этот же байт уходит через shiftOut в регистр, и индикатор подключён к регистру, а не к Arduino. Приём тот же, что с гирляндой из второго урока: логика в коде не меняется, меняется исполнитель, и три провода вместо семи — та цена, за которую платят таблицей байтов. Счётчик на индикаторе без регистра мы собирали в уроке про счётчик цифр — сверьте скетчи: разница умещается в одну функцию show(): на плате она отправляет байт через shiftOut, в симуляторе — раскладывает по семи пинам.
Ток разряда и граница применимости
Посчитаем оба варианта аккуратно. Свой резистор на каждый сегмент: 330 Ом даёт (5 − 2) / 330 ≈ 9 мА на палочку, все семь сегментов восьмёрки — около 63 мА сквозь корпус, впритык к пределу 70 мА. Общий резистор на катоде: 220 Ом держит разряд на 14 мА при любом числе горящих сегментов — безопасно для микросхемы, тускло для комнаты. Номиналы по полной схеме считались в уроке про подбор резистора. Добавьте к расчёту режим работы: в мультиплексе каждый разряд горит долю времени, и экономия резисторов на катодах оборачивается подбором номиналов под конкретное число разрядов.
Второй разряд меняет картину: два регистра в каскаде обслуживают две цифры теми же тремя пинами, но разряды надо мигать по очереди десятки раз в секунду — гасить один, показывать другой, бороться с призраками остаточного свечения при переключении. Это классическая динамическая индикация, и она съедает loop: типовой ритм — пять миллисекунд на разряд, двести кадров в секунду, и любой лишний delay в соседнем коде вылезает мерцанием младшего разряда.
Моя граница — четыре разряда. Один-два через 595 собираются за вечер и живут годами; дальше я беру MAX7219: он сам мигает разрядами, сам держит ток через один резистор на всё и занимает те же три провода. Выбор не про пины — про время, которое вы готовы отдавать loop под перекладывание байтов. Часы на четыре цифры через пару 595 я держал месяцами, но каждый новый интервал в скетче требовал ревизии таймингов; MAX7219 снял вопрос целиком, а его корпус DIP-24 даже влезает на макетку — редкость для драйверов.
- 1. Почему байт 595 так удобно ложится на семисегментный индикатор?
- 2. Что делает сегмент g в цифре 0?
- 3. Что даёт один резистор на общем катоде вместо восьми по сегментам?
- 4. Как зажечь сегмент на индикаторе с общим анодом?
- 5. Сколько пинов Arduino занимает связка 595 плюс индикатор?
- Байт цифры раскладывается на сегменты по битам: бит 0 — a, бит 6 — g, бит 7 — точка dp
- Ноль — 0b00111111, единица — 0b00000110, восьмёрка — 0b01111111: таблица из десяти байтов кочует между проектами
- Резистор на общем катоде ограничивает ток разряда (около 14 мА при 220 Ом), но яркость плывёт от цифры к цифре
- Резистор 330 Ом на каждый сегмент держит яркость ровной и вписывает разряд в 70 мА корпуса
- Один-два разряда — 595; четыре и больше — динамическая индикация или MAX7219, который делает её сам
Частые вопросы по теме урока
- Почему байт 595 так удобно ложится на семисегментный индикатор?
- Восемь линий управления индикатора (a-g и dp) совпадают с восемью выходами регистра: одна защёлка — одна цифра, без мультиплексирования. Ровно один байт на кадр и ровно одна защёлка. семь сегментов плюс точка — ровно восемь бит
- Что делает сегмент g в цифре 0?
- Ноль — это шесть палочек по кругу: байт 0b00111111, бит 6 (сегмент g) равен нулю. Именно отсутствие средней черты отличает ноль от восьмёрки. У шестёрки, кстати, g горит — их различают по остальным сегментам. спит: у нуля средняя черта не нужна
- Что даёт один резистор на общем катоде вместо восьми по сегментам?
- Общий резистор ограничивает суммарный ток разряда, и он делится между горящими палочками: единица из двух сегментов светит ярче восьмёрки из семи. Для статичного счётчика это терпимо, для часов — уже нет. экономию деталей, но яркость зависит от числа горящих сегментов
- Как зажечь сегмент на индикаторе с общим анодом?
- Общий анод сидит на 5 В, ток идёт, когда вывод сегмента притянут к земле: сегмент горит от LOW, паттерны инвертируются вычитанием из 255. Проверка мультиметром занимает секунды и спасает вечер. нулём на выводе сегмента при аноде на 5 В
- Сколько пинов Arduino занимает связка 595 плюс индикатор?
- Индикатор подключён к регистру, а не к плате: плате нужны только три линии регистра, и они же обслужат каскад из нескольких разрядов. Четвёртый и десятый разряд пинов не добавляют. один