В настоящее время широкое распространение получили различные графические и символьные ЖК дисплеи с встроенным контроллером и памятью. Но газоразрядные, вакуумные люминесцентные, светодиодные 7- и много-сегментные, матричные светодиодные, и прочие индикаторы по прежнему применяются. Да и интерес к "ретро" индикаторам, тем же газоразрядным и люминесцентным, не уменьшается.
Но при построении многоразрядных дисплеев из таких индикаторов возникает одна проблема - слишком большое число соединений индикаторов со схемой управления.
Это не новая проблема, она существовала задолго до появления и распространения микроконтроллеров. И даже до широкого применения микросхем. В былые времена можно было немного снизить остроту проблемы разместив дешифраторы на плате индикаторов. Но сегодня у микроконтроллера может просто оказаться недостаточно выводов для управления индикаторами.
Для примера возьмем 4-х разрядный дисплей. Если используются газоразрядные индикаторы, то потребуется 44 вывода (10 цифр и точка, в каждом разряде), что бы была возможность отображения всех цифр в каждом разряде. Для 7-сегментных светодиодных индикаторов потребуется 32 вывода (с учетом точки). Для 11-сегментных 48.
Использование такого количества выводов не выглядит разумным решением, ведь микроконтроллер должен управлять не только индикаторами. Количество требуемых выводов микроконтроллера можно уменьшить если использовать внешние микросхемы регистров, но это все равно остается довольно затратным. Кроме того, это не уменьшает количества соединительных проводников между модулем управления и самим индикатором.
Решение проблемы было найдено довольно давно и называется динамической индикацией. Я не сомневаюсь, что все, как минимум, слышали этот термин. А очень многие, но все таки не все, знают, как это работает.
Сегодняшняя статья для тех, кто не знает, как работает динамическая индикация. Причем коснусь и старых схемотехнических решений на дискретной логике, и программной реализации для микроконтроллеров.
До широкого распространения микроконтроллеров динамическая индикация реализовывалась на обычных цифровых микросхемах и дискретных элементах, что было сложно и дорого, но позволяло создавать дисплеи на базе, например, таких 14-ти разрядных (13 разрядов и знак) индикаторов (ИВ-27).
Без использования динамической индикации такой индикатор имел бы минимум 123 вывода (13 разрядов по 8 элементов (анодов) в каждом, плюс 3 элемента в знаковом разряде, плюс общий для всех разрядов катод (совмещенный с накалом), плюс 14 выводов сеток).
Принцип работы динамической индикации
Динамическую индикацию можно рассматривать как некий аналог развертки, применяемой в телевидении. В каждый момент времени информацию отображает лишь один разряд индикатора, остальные погашены.
Для примера давайте возьмем 7-сегментные индикаторы собранные в 4-х разрядный дисплей. На иллюстрации ниже каждая строка представляет собой "снимок дисплея" в последовательные моменты времени.
Красным цветом показан разряд, который отображается. Так как у нас 4-х разрядный дисплей, для отображения всех разрядов требуется 4 кванта времени, что составляет полный период индикации. После отображения последнего разряда цикл повторяется.
За счет инерционности зрения человека, если частота обновления дисплея достаточно высока (период индикации мал), мы увидим отображаемую информацию такой, как будто она отображается статически. Точно так же мы видим плавное изображение движущихся предметов в кино и на телевидении вместо смены статических кадров.
Минимальная комфортная для зрения частота обновления индикации должна быть не менее 50 Гц. То есть, период индикации должен быть не более 20 мс. Разделив длительность периода индикации на количество разрядов дисплея мы получим время работы одного разряда.
Для нашего 4-х разрядного дисплея каждый разряд будет работать (светиться) не более 5 мс. Но лучше выбрать период индикации более коротким. Особенно, если и дисплей, и оператор, будут размещаться на некоей подвижной платформе, например, в автомобиле.
Динамическая индикация на дискретной логике
Прежде чем мы перейдем к микроконтроллерам и программам реализующим динамическую индикацию, будет полезным и интересным познакомиться с тем, как это реализовывалось ранее. Я не предлагаю сегодня повторять эти схемы, но небольшой исторический экскурс считаю целесообразным.
Я не буду приводить принципиальную схему реального блока многоразрядной индикации, она слишком большая и сложная. Но я покажу функциональную схему такого блока
Это действительно упрощенная функциональная схема. Реальные блоки динамической индикации гораздо сложнее. В них не редко использовали, в том числе, микросхемы ОЗУ или регистры для временного хранения информации в течении цикла индикации.
Готовя иллюстрацию я пропустил один сегмент - g при изображении дешифратора. Извиняюсь за допущенную ошибку, но перерисовывать не уже не буду.
Давайте посмотрим, из каких функциональных узлов состоит этот блок индикации.
- Счетчики, в большинстве случаев двоично-десятичные, которые и являются источником информации для отображения на дисплее. В данном случае их четыре, так как мы рассматриваем 4-х разрядный дисплей. На иллюстрации они расположены слева и обозначены СТ. Собственно говоря, счетчики в большинстве случаев являются частью устройства, а не блока индикации.
- Мультиплексоры, которые обеспечивают коммутацию выходов счетчиков при выборе отображаемого разряда. Поскольку счетчики у нас двоично-десятичные, то каждый из них имеет 4 выхода. А значит нам нужно 4 мультиплексора. Количество входов каждого мультиплексора равняется количеству разрядов дисплея. А количество входов определяет и количество входов адреса, который задает номер выбранного входа данных. На иллюстрации мультиплексоры обозначены MUX, а из адресные входы A0и А1, так как разрядов всего 4.
- Дешифратор, преобразующий двоичный код с выходов счетчиков (после мультиплексоров) в сигналы управления сегментами a-g индикаторов. Обозначен на иллюстрации DC. Я не стал показывать сигналы управления десятичными точками, что бы не усложнять иллюстрацию.
- Генератор задающий время отображения очередного разряда. Обозначен на иллюстрации G.
- Счетчик номера отображаемого разряда. Это уже двоичный счетчик, поэтому и обозначен на иллюстрации как CT2. На вход счетчика поступают импульсы с генератора G. Выходы счетчика подключены к адресным входам мультиплексоров и к входам дешифратора выбора разряда.
- Дешифратор выбора разряда. В данном случае у него 4 выхода, которые и определяют отображаемый в данный момент разряд.
- Собственно дисплей. В данном случае 4-х разрядный. Он может быть как единым компонентом, так собранным из единичных индикаторов. Выводы сегментов всех разрядом соединены между собой "поименно". То есть, сегменты a объединены между собой. Сегменты b объединены. И так далее. А вот выводы разрядов отдельные.
Нам сейчас не важно, что именно представляет из себя дисплей. Он может быть светодиодным. Тогда сегменты могут быть катодами светодиодов, а вывод разрядов общим анодом. Или наоборот. Он может быть люминесцентным, тогда сегменты это аноды, а выводы разрядов это сетки. Он может быть газоразрядным.
Если дисплей газоразрядный, то вместо выводов сегментов будут выводы отдельных цифр или символов. При этом в нашем блоке просто будет использоваться другой дешифратор. Работа блока при этом не изменится.
Для наглядности я показал информационные входы мультиплексоров и соединительные шины разными цветами. Синий цвет это выходы "1" счетчиков. Зеленый это выходы "2" счетчиков. Бордовый это выходы "4" счетчиков. Желтый это выходы "8" счетчиков.
Непрерывно работающий счетчик динамической индикации СТ2 определяет и номер отображаемого разряда, и адрес счетчика, выходы которого подключаются через мультиплексоры к дешифратору индикаторов.
Проблемы динамической индикации и псевдо-динамическая индикация
Кроме очевидной сложности схемотехнических решений у динамической индикации есть еще одна, довольно серьезная, проблема. Дело в том, что чем больше разрядов у дисплея, тем меньшее время (и в абсолютном, и в процентном соотношении) работает каждый разряд. А это приводит к снижению видимой яркости индикаторов. И тем большей, чем большая разрядность у дисплея.
В некоторых случаях проблему можно решить выбрав индикаторы со светодиодами с повышенной яркостью. Или повысить ток через светодиоды сегментов.
В некоторых случаях проблему решить нельзя, так как яркость индикаторов повысить невозможно. Например, для газоразрядных или люминесцентных, когда когда повышение тока ведет не столько к повышению яркости, сколько к ускорению износа индикаторов.
В те времена, когда использовались аппаратные решения для динамической индикации, яркость индикаторов была не высокой, в большинстве случаев. Но было найдено компромиссное решение, которое позволяло снизить количество соединений между устройством и блоком индикации, но собственно индикация осуществлялась статически.
Эта схема сложнее, чем чисто динамическая индикация. Но она позволяет убить сразу двух зайцев. Во первых, снизить количество соединений между устройством и блоком индикации, который заключен на иллюстрации в красную пунктирную рамку. Во вторых, не жертвовать и так не очень высокой яркостью индикаторов.
В данном случае у нас мультиплексоры вынесены из блока индикации в собственно устройство. Это и позволяет уменьшить количество соединений между блоками. А в блоке индикации теперь каждый индикатор имеет собственный дешифратор подключенный к промежуточному регистру хранения информации.
Таким образом, мы теперь заносим данные очередного разряда в промежуточный регистр, а не отправляем на индикацию. А собственно дисплей теперь работает в статическом, а не динамическом режиме.
Кроме того, мы теперь не ограничены в частоте обновления дисплея. И вполне допустимым будет обновлять всего несколько раз в секунду. Например, 5 раз. Или даже только при изменении отображаемых данных.
Правда и тут есть ограничение. Мы в этой схеме не может использовать дисплеи выполненные в виде единого компонента, если у них нет отдельных выводов от каждого сегмента. В большинстве случаев такой дисплей будет состоять из отдельных индикаторов.
Программная реализация динамической индикации для микроконтроллеров
Программная реализация динамической индикации довольно проста. Конечно, используемый микроконтроллер влияет на детали, но общий принцип остается неизменным. При этом нужно учитывать и схему подключения индикаторов. Вот один из вариантов
Не обращайте внимание на номера выводов микроконтроллера и индикаторов. Просто я взял фрагмент схемы панели управления одного из своих старых проектов.
Нам, в данном случае, не важны ни использованные индикаторы, ни микроконтроллер, ни транзисторы, ни номиналы резисторов. Важно лишь:
- 7-сегментные светодиодные индикаторы имеют общий анод. В том проекте использовались раздельные индикаторы еще производства СССР. Но их можно заменить единым 4-разрядным дисплеем с общим анодом. При этом межсегментные соединения будут внутри дисплея.
- Токозадающие резисторы обязательно должны стоять в цепях сегментов. Абсолютно неверно устанавливать один резистор на разряд в цепи общего электрода, так как яркость свечения будет сильно зависеть от количества зажженных сегментов.
- PNP транзисторы ключей разрядов нужны если суммарный ток светящихся сегментов одного разряда превышает допустимый максимальный ток вывода микроконтроллера. То есть, в большинстве случаев. Одновременно могут быть включены все 7 сегментов и десятичная точка. Что дает суммарный ток 80 мА при токе через один светодиод 10 мА. А это больше допустимого тока вывода для большинства микроконтроллеров.
Поскольку мы не привязываемся ни к какому конкретному микроконтроллеру (но будем считать, что он 8-битный), текст программы будет в максимально общем виде. Но я буду учитывать ту схему подключения индикаторов, которую привел выше.
Что бы один из индикаторов (разряд дисплея) мог работать нам нужно подать напряжение (положительный вывод источника) на его общий электрод. А для этого нужно открыть соответствующий транзистор установив низкий уровень напряжения на соответствующем выводе порта В.
Включение одного из сегментов разряда производится установкой низкого уровня на соответствующем вывод порта С.
Этого достаточно для начала разработки программы управления дисплеем. Я предполагаю, что переменные PORTB и PORTC, соответствующие физическим портам, уже где то описаны. Скорее всего в подключаемом заголовочном файле описания микроконтроллера.
Точно так же, где то вне наших примеров описан буфер дисплея. Например, так
uint8_t buffer[4];
Причем этот буфер является глобальной переменной. Дисплей у нас 4-х разрядный, и буфер такого же размера. Каждый элемент буфера хранит маску сегментов соответствующего разряда. Если все биты элемента равны 1, то светящихся сегментов нет (разряд полностью погашен, пробел).
Определим, что буфер отображается на дисплее слева направо. То есть, самый левый разряд дисплея (старший разряд отображаемого числа) соответствует элементу buffer[0].
Так же будем предполагать, что начальная настройка микроконтроллера и портов ввода-вывода уже выполнена, причем вне наших примеров программ.
Теперь мы можем написать процедуру обновления дисплея, вывода очередного разряда
Сразу бросается в глаза отсутствие цикла в процедуре. При этом я ранее говорил, что дисплей обновляется непрерывно, циклически. Но дело в том, что если мы разместим полный цикл обновления в этой процедуре, то она никогда не завершится, а микроконтроллер только и будет занят работой с дисплеем.
Поэтому процедура просто выводит на дисплей очередной разряд (цифру). А цикл обновления дисплея должен быть внешним по отношению к процедуре. Просто нужно ее периодически вызывать. Но об этом чуть далее.
Поскольку у нас процедура обновляет именно очередной разряд, то она должна сохранять свое состояние между вызовами. Поэтому две переменные, dig_select и buf_ptr и объявлены статическими.
dig_select хранит маску для управления транзисторами ключей разрядов. Я знаю, что использовать "магические числа" в программах плохо. Но поскольку это небольшой и чисто демонстрационный пример, в данном случае, считаю это допустимым.
Содержимое dig_select просто выводится в порт В, так как этот порт в нашем микроконтроллере имеет выводы только 4 старших разрядов. Но во многих случаях придется использовать логические операции для выделения бит порта, которые используются для управления дисплеем.
buf_ptr хранит номер элемента дисплейного буфера, который должен отображаться.
Перед обновлением дисплея мы его гасим закрывая ключи разрядов. Это не обязательная операция, но она позволяет избежать небольшой паразитной засветки лишних сегментов.
После отображения очередного разряда мы проверяем, не является ли этот разряд последним (самый правый индикатор). Если это так, мы устанавливаем маску разрядов и указатель буфера для отображения первого разряда. Если нет, просто сдвигаем маску разрядов влево, так как указатель буфера был изменен ранее.
Процедура очень простая, поэтому дополнительных комментариев и не требует. Поэтому поговорим о том, как и когда вызывать нашу процедуру.
Все, за очень редким исключением, программы для микроконтроллеров работаю в бесконечном цикле и никогда не завершаются. Если время одной итерации не превышает максимальной длительности отображения одного разряда (не более 5 мс для 4 разрядного дисплея), то мы можем разместить вызов процедуры обновления прямо в главном цикле. Примерно так
При этом нет необходимости точно выдерживать длительность одной итерации главного цикла. Если одна итерация может занимать больше времени, чем допустимо для обновления дисплея, то вызов процедуры можно разметить в цикле несколько раз. Разумеется, не подряд.
Другим хорошим местом для размещения вызова процедуры обновления дисплея является обработчик прерывания от таймера, который задает кванты времени для программы. А такое использование таймера является довольно распространенным.
Но в таком случае необходимо учитывать, что обновление дисплея увеличивает время обработки прерывания, пусть и ненадолго. Другим ограничением может быть невозможность обращения из процедуры обновления дисплея к функциям, которые вызываются и из основной программы, а не только из прерывания. Такое ограничение иногда накладывается компиляторами.
Заключение
Динамическая индикация используется довольно широко и давно. Но у новичков не так редко вызывает много вопросов. Особенно ри использовании динамической индикации в более сложных случаях, чем описаны в статье. Например, при управлении матричными индикаторами.
Ранее, до использования микроконтроллеров, динамическая индикация имела ограниченное применение из-за сложности схемотехнических решений и их высокой стоимости. Но появление специализированных микросхем и микроконтроллеров изменило ситуацию. И теперь динамическая индикация является весьма распространенным элементов различных устройств. Причем не только для управления индикаторами.