Матричные светодиодные (и не только светодиодные) индикаторы используются в любительских устройствах реже, чем индикаторы других типов. Исключением являются матричные жидкокристаллические знакосинтезирующие дисплеи (1602, 2004, и им подобные), которые имеют встроенные управляющие контроллеры.
Причина этого в более сложном управлении такими индикаторами. Поэтому, если нет необходимости выводить на индикатор буквы и специальные символы, ограничиваются привычными 7-сегментными индикаторами. А если буквы нужны, то используют готовые жидкокристаллические дисплеи, размер символов которых не всегда бывает достаточным.
Поэтому матричные светодиодные индикаторы по прежнему находят свое применение. Кроме того, у них есть одно, не самое заметное с первого взгляда, преимущество - их можно изготовить самостоятельно, причем любого размера, из обычных светодиодов.
Устройство и работа матричных индикаторов
Внутренний мир таких индикаторов прост, если не рассматривать модели с встроенным контроллером. Светодиоды действительно собраны в матрицу
В данном случае матрицу 8х8. На самом деле, такое деление на включение с общим анодом и с общим катодом излишне. Во всяком случае, для индикаторов с числом строк равным числу столбцов. Мы всегда можем считать строки столбцами, и наоборот.
Для матричных индикаторов принципиально необходимо использование динамической индикации. Иначе просто невозможно сформировать требуемый отображаемый символ. Про динамическую индикацию я уже рассказывал в статье "Динамическая индикация".
В случае с матричными индикаторами мы должны последовательно перебирать, например, строки. А на столбцы будем подавать сигналы обеспечивающие зажигание необходимых светодиодов (точек) соответствующей строки.
В результате можно получить изображение различных символов, например так (для матрицы 8х5)
Причем совсем не обязательно ограничиваться символьной информацией. Из таких индикаторов можно собрать и графический дисплей. Но давайте обо всем по порядку.
Вывод символьной информации
Сначала, что бы более наглядно показать принцип работы с матричными индикаторами, я приведу аппаратное решение. А потом уже программное.
Генератор G и двоичный счетчик СТ2 обеспечивают динамическую индикацию непрерывно перебирая строки индикатора через дешифратор DC. У нас индикатор состоит из 8 строк, поэтому счетчик 3-разрядный. Код символа поступает на старшие разряды адреса ПЗУ, которое выполняет роль знакогенератора. Младшие разряды адреса ПЗУ перебираются счетчиком динамической индикации.
У нас индикатор состоит из 8 столбцов, поэтому и выход ПЗУ должен быть 8-разрядным. И каждый символ в ПЗУ-знакогенераторе занимает 8 байт. А всего емкость ПЗУ должна быть 2048 байт, если нужно отображение всех 256 символов.
Программное решение может напрямую реализовывать тот же алгоритм, который используется в аппаратном. В качестве генератора импульсов динамической индикации, скорее всего, будет использоваться прерывание от таймера. Тут есть одна не совсем очевидная сложность, но о ней чуть позже.
Здесь нет ничего сложного. Определяется таблица знакогенератора, которая соответствует ПЗУ в аппаратном решении. Отображаемый символ хранится в глобальной переменной. Предполагается, что есть два 8-битных порта, которые подключены к индикатору (возможно, через дополнительные ключи). Так же предполагается, что микроконтроллер уже настроен.
Вся работа выполняется в процедуре обработки прерывания от таймера. Так как у нам 8 строк, а минимальная частота динамической индикации 50 Гц (20 мс), то период между прерываниями таймера не должен превышать 2.5 мс.
Сначала индикатор гасится. Потом в порт управляющий строками выводится высокий уровень напряжения для очередной отображаемой строки, а в порт управляющий столбцами информация очередной строки символа из таблицы знакогенератора. После этого увеличиваем номер отображаемой строки, с обработкой переполнения.
Все просто, никакой магии. Но в этой простоте скрыта одна небольшая проблема, как я и говорил ранее. Код обработчика прерывания должен выполняться как можно быстрее, а у нас он содержит обращение к двумерному массиву, да еще в памяти программ. А это не самая быстрая операция.
В данном случае нас спасает то, что вторая размерность равна 8, а значит умный компилятор может использовать для вычисления адреса элемента массива сдвиги, а не умножение, которое не всегда может быть выполнено аппаратно. Это быстрее, но все таки.
О том, как устроены и работают массивы я когда то давно написал статью "Однородные структуры данных - массивы и матрицы". В ней рассказывается о вычислении адреса элемента по индексам массива.
Есть два способа решения проблемы быстродействия. Первый, использовать указатель вместо индексов. Теперь, вместо кода символа, мы сразу (в основной программе) вычисляем адрес начала информации о символе в таблице знакогенератора. А в процедуре DispSrv мы этот указатель используем, прибавляя к нему cnt для последовательной выборки всей информации о символе. Это уже гораздо быстрее, но ситуацию немного портит то, что все равно будут обращения к памяти программ, куда компилятор поместит таблицу знакогенератора (константы). Доступ к памяти программ может быть медленным.
Второй, выделить в ОЗУ дополнительный буфер размером 8 байт (для нашего примера). В этот буфер основная программа скопирует информацию о символе. Теперь не нужен ни код символа, ни дополнительный указатель. Мы будем в DispSrv использовать этот буфер в ОЗУ.
Процедура ShowSym выполняет заполнение буфера в ОЗУ информацией из таблицы знакогенератора. Эта процедура вызывается из основной программы. Мы значительно сократили время выполнения обработчика прерывания.
Так же нужно отметить, что в процедуре ShowSym перед циклом нужно запрещать прерывания от таймера, а после цикла разрешать. Это не позволит выводить на индикатор искаженную в процессе заполнения буфера информацию. Это не очень критично, если отображаемый символ меняется не слишком часто. В противном случае это может стать заметным.
Я не стал показывать запрет/разрешение прерываний, так как это аппаратно-зависимо. А я сегодня не ставлю цель погружаться в подробности разных микроконтроллеров.
Немного о схемотехнике управления индикатором
Я буду считать, что вы прочитали статью о динамической индикации, ссылку на которую я давал выше. Поэтому буду краток.
Я уже говорил о необходимости использования внешних токовых ключей для управления общими электродами индикаторов. И в данном случае это особенно актуально, так как используется динамическая индикация 1:8, что требует ощутимого повышения тока через светодиоды индикатора.
Если используется сканирование строк, то ключи нужно устанавливать между портом микроконтроллера и выводами строк индикатора. В каждой строке может одновременно гореть до 8 светодиодов, и на этот суммарный максимальный ток и должны быть рассчитаны ключи.
Токоограничивающие резисторы нужно устанавливать в цепи столбцов. Так как в каждом столбце может гореть максимум один светодиод (в каждый момент времени), то ток здесь значительно меньше. И все таки, он может превысить возможности порта микроконтроллера, так как динамическая индикация требует больших токов через светодиоды. Если ток превышает допустимый для микроконтроллера, придется установить ключи и в цепях столбцов.
Я не буду рисовать схему, так как она проста и не сильно отличается от той, что приведена в статье про динамическую индикацию. Если все таки возникнут вопросы, можете задать их в комментариях.
Построение многоразрядных дисплеев
А вот тут все не так просто. Мы не можем просто подключить дополнительные индикаторы объединив выводы, например, столбцов. Во первых, у нас число строк резко возрастет, что сделает весьма затруднительным управление ими. Во вторых, кратность динамической индикации станет недопустимо большой.
Действительно, если взять 4-разрядный дисплей, то, с учетом того, что для одного разряда индикация уже 1:8, кратность составит 32. Это уже не получится скомпенсировать увеличением тока через светодиоды.
Нам на помощь приходят сдвиговые регистры с параллельным выходом. Можно использовать классические популярные 74HC595, но еще лучше будут MBI5167, MBI5168, STP08DP05 (и им подобные), о которых я говорил в статье "Драйверы светодиодов и 7-сегментные светодиодные индикаторы". Они и предназначены для подобного применения.
Я специально показал, что сигналы D и CLK это всего один бит, хотя такое показывать не принято. И не стал как то привязываться к конкретному типу сдвиговых регистров. Я показал сам принцип объединения индикаторов в многоразрядный дисплей. Но показал ключи управления строками, так как теперь это стало не просто важно, но и критично, так как количество светодиодов, которые могут гореть, резко возросло.
Теперь мы должны сначала загрузить (вдвинуть) в сдвиговые регистры информацию сразу для всех разрядов. И только после этого включить нужную строку. Я не буду приводить пример программы, так как основное отличие (кроме разрядности) будет заключаться в замене строки
COL_PORT=buf[cnt];
на цикл сдвига для загрузки в регистры.
Кстати, такая вот схема включения позволяет очень просто реализовать режим бегущей строки. Просто на нужно не загружать сдвиговые регистры сразу полностью, а вдвигать очередной столбец постепенно. И символы на дисплее побегут с заданной скоростью.
А что насчет быстродействия. Специализированный драйвер STP08DP05 допускает частоту тактирования до 50 МГц, так что тут особых проблем не будет. А вот для микроконтроллера не все так радужно. Да, можно использовать максимальную тактовую частоту, на которой он может работать, но количество машинных циклов, которые использует обработчик прерывания существенно возрастает с увеличением разрядности дисплея.
А это может привести к тому, что микроконтроллеру все меньше времени будет оставаться на выполнение основной задачи, все силы будут уходить на работу с дисплеем. Поэтому большие матричные дисплеи и содержат контроллер внутри себя. Это может быть или специализированный контроллер, и обычный микроконтроллер, который только дисплеем и управляет. Освобождая основной микроконтроллер для более полезных дел.
Кстати, управление строками тоже можно осуществлять с помощью сдвигового регистра. Только тут уже специализированные драйверы не подойдут. А вот обычный сдвиговый регистр, или 74HC595, вполне подойдут.
Многострочные многоразрядные дисплеи и графические дисплеи
Мы не можем просто добавить дополнительные строки из матричных индикаторов к дисплею. Да, для сканирования строк можно использовать сдвиговые регистры, но это не решит проблемы роста кратности динамической индикации.
Поэтому многострочный дисплей будет состоять из нескольких многоразрядных, каждый со своим контроллером. И у нас появится дополнительная степень свободы - номер строки. Именно номер строки и будет выбирать контроллер, в который идет запись информации для отображения.
Что же касается графических дисплеев, то это надмножество многострочных многоразрядных дисплеев, в которых знакогенератор, обычно, отсутствует. Зато есть большое ОЗУ, которое непрерывно сканируется контроллером дисплея для вывода ни индикатор. Так же, как я описал выше.
Но в это ОЗУ есть и второй канал доступа, через который заносится микроконтроллером информация для отображения. Контроллеры таких дисплеев или специализированные, что далеко выходит за рамки сегодняшней статьи, или дисплей собирается из нескольких блоков-модулей, каждый из которых формирует свой кусочек изображения из своей области ОЗУ.
И вот такой "дисплей из кусочков", только небольшого размера, вполне можно построить используя то, что написано в статье. Только вот стоит ли это делать? По моему - нет. Большой или графический дисплей лучше приобрести готовый.
Заключение
Работать с матричными индикаторами, управляя ими напрямую, не так просто. Но вполне по силам любителям, которые могут их использовать (и используют) в своих конструкциях. Можно легко построить и многоразрядный дисплей. Но такие дисплеи вряд ли целесообразно делать более чем двухстрочными (16 строк светодиодов).