![](https://habrastorage.org/files/ac0/20d/905/ac020d905fcf46f8a7458d999c31a514.jpg)
4095 светодиодов и все-все-все
Как ни удивительно, с выводом изображения на такой дисплей вполне справляется контроллер ATmega328, что лежит в основе Arduino Uno. Из этого всего получилась «карманная» консоль (весом несколько килограмм), в которую прошита игра по мотивам Space Invaders. В планах придумать что-нибудь ещё, ведь свободной памяти осталось полно.
Под катом вы сможете прочитать о том, как такой дисплей устроен и как им можно управлять.
Иногда вместо того, чтобы находить старые компьютеры в коллекцию, я делаю их самостоятельно из подручных материалов.
В этот раз хотелось сделать что-то компактное с разрешением на уровне приставок и компьютеров начала 80х. Правда дисплей в 64x64 пикселя не дотягивает до Atari 2600, но зато на целых 64 пикселя больше, чем дисплей Nokia 3310, где игры тоже были. Так что его должно было с запасом должно хватить как минимум для комфортной игры в тетрис или понг.
![](https://habrastorage.org/files/86b/dbc/720/86bdbc720d954c949f82749a98c1d080.gif)
Кроме дисплея я раздобыл плату, совместимую с Arduino Uno, и стал думать как бы теперь со всем этим добром взлететь.
Компания Adafruit продаёт подобные дисплеи и на её сайте можно найти примеры их использования. Там же есть ссылка на библиотеку для работы с ними. Библиотека поддерживает Arduino Uno и Arduino Mega.
Эта библиотека организует видеопамять, где и хранит цвета пикселей. Пользовательская программа перекрашивает эти пиксели, а изображение выводится на дисплей в обработчике прерывания таймера. С маленькими дисплеями это работает неплохо, но в моём случае такой способ не годится. Даже если на каждый пиксель выделять по полбайта (по одному биту на R, G, B и один лишний), то для матрицы 64x64 понадобится 2 килобайта памяти. А это всё что есть у ATmega328P. Можно, конечно, взять процессор помощнее, но это не путь джедая.
Ведь кто нас заставляет хранить все строки экрана сразу? Можно вычислять каждую строку заново перед выводом на экран. Для примитивной графики из нескольких спрайтов эти вычисления не должны занять слишком много времени, поэтому всё должно сработать.
![](https://habrastorage.org/files/6a2/bd1/86f/6a2bd186f3ff491d96f2dfe91a218b92.jpg)
Дело было в
- Выставляем на входах дисплея адрес выводимой строки
- Заполняем массив цветами пикселей спрайтов, которые пересекаются с текущей строкой
- Задвигаем по очереди все пиксели в сдвиговый регистр, который управляет светодиодами
- Защёлкиваем полученные данные и подаём их на выходы регистров
В итоге под видеопамять выделен массив размером только в четыре строки экрана. Почему четыре? Всё потому, что одновременно мы задвигаем данные в две строки — ведь у матрицы две группы входов: R1/G1/B1 и R2/G2/B2. Управляют они двумя строками, отстоящими друг от друга на 16 пикселей.
Но тогда почему не две строки, а четыре? Оказывается, что матрица 64x64 состоит из двух независимых матриц 32x64. Можно было бы к каждой подключить отдельные выходы процессора, но у ATmega328 их недостаточно. К счастью, заботливый производитель предусмотрел каскадирование этих матриц — выход сдвигового регистра одной можно подключить ко входу другой. Тогда получится логическая матрица 32x128, которая физически отображается как 64x64. То есть в каждой фазе нам надо задвинуть в регистры две строки по 128 пикселей — а это и есть 4 строки физического экрана.
![](https://habrastorage.org/files/763/7d6/366/7637d6366a1540558e603b704ff247b6.png)
Прототип консоли мы сделали во время летней компьютерной школы. Первой игрой стало нечто, отдалённо напоминающее Space Invaders.
В реальности светодиоды очень уж выжигали глаза. Отрегулировать их яркость с помощью ШИМ вряд ли получится — быстродействия ATmega не хватает. Надо брать какой-нибудь ARM или ПЛИС.
Финальный вариант я оформил в деревянном корпусе. Экран защищён зашкуренным оргстеклом. За счёт рассеяния света глаза теперь не выжигаются, но на видео работу приставки теперь снять сложнее — всё изображение становится размытым.
Вся программа использует 1101 байт (53%) ОЗУ и 6432 (19%) байт ПЗУ. Остаётся ещё место, чтобы сделать несколько игр и меню для их выбора.
Ссылки
- Исходники проекта: github.com/Dovgalyuk/BackspaceInvaders
- Описание работы матрицы на сайте adafruit: learn.adafruit.com/32x16-32x32-rgb-led-matrix
- Библиотека от adafruit для управления матрицей: github.com/adafruit/RGB-matrix-Panel
- Библиотека от adafruit для рисования графических примитивов: github.com/adafruit/Adafruit-GFX-Library
- Похожий проект на более мощном процессоре: learn.adafruit.com/ledgames-beaglebone-black-64x64-led-game/overview
- Статья про управление дисплеем меньшего размера: geektimes.ru/post/275548
Комментарии (32)
madf
19.04.2017 18:24+3Нет описания конкретного используемого дисплея (адафрут много чего выпускает).
В игрушке сильно не хватает взрывов захватчиков, просто пропадание — не смотрится.
Вообще статья так подана, будто старались специально многое скрыть и не рассказать. :)Dovgaluk
19.04.2017 18:33Дисплей не от adafruit, а с aliexpress. Но принцип работы у них одинаковый.
Про взрывы согласен, игрушку еще будем дорабатывать.
А детали я сознательно опускал, чтобы раскрыть основное — логическую организацию дисплея, потому что именно это не очень понятно из того, что удалось найти в интернете. Софт я еще буду перерабатывать и обязательно про это напишу.
Sun-ami
19.04.2017 21:24+1В чём проблема регулировать яркость ШИМ'ом? Для этого предназначен вывод OE. На него можно подать ШИМ частотой несколько сот герц. Для того, чтобы исключить интерференцию этого ШИМ'а с частотой переключения фаз динамической индикации нужно сделать частоту ШИМ'а кратной частоте переключения фаз. При этом ШИМ на OE можно генерировать аппаратно таймером, синхронизировать его с фазами динамической индикации не обязательно.
Dovgaluk
19.04.2017 21:25+1Да, интересная идея, надо попробовать. Я пробовал просто делать задержку после вывода каждой строки, но большой частоты так не получить.
sashabeep
20.04.2017 00:56Проще всех с яркостью — накрыть это добро полупрозрачным тонированным зеркалом. Выдумываете вечно проблемы и способы их решения «не с того угла». Да и просто в него можно будет смотреть как в зеркало, когда не светится
nochkin
20.04.2017 03:34В этом случае яркость будет фиксирована и её намного сложнее будет поменять, так как надо менять-добавлять стекло.
Tachyon
20.04.2017 11:26Делюсь с Dovgaluk секретом таксистов- они на яркий экран дешевых китайских магнитол, слепящий ночью, наклеивают кусочек тонировочной плёнки, с нужным коэффициентом затемнения. Так и слепить перестаёт и днём видно, и нет размывания изображения как у вас от матового оргстекла. С китая же как и магнитолы тонировочная плёнка будет копейки стоить, тем более её тут не много надо, возможно даже необходимый кусочек в ближайшей автомастерской в обрезках найдёте. Завидую немного тому как всё это реализовано — можно на кикстартер для гиков выводить :). Спасибо за статью.
Dovgaluk
20.04.2017 11:32Спасибо за совет.
На самом деле с размытием тоже неплохо. Почти как Spectrum, подключённый к старому телевизору.Tachyon
20.04.2017 14:59Я вот тоже про тонировочную плёнку подумал- она уменьшит яркость, но не сгладит очертания пикселей, матовое стекло размывает острые грани, объединяя отдельные пиксели в цельную фигурку, наверное даже лучше так.
Andy_Big
Под каким катом можно это прочитать?
Dovgaluk
Чего-то конкретно не хватает?
Dark_Purple
Не хватает информации по дисплею. Шаг пикселей? В дисплее есть «память» под каждый пиксель?
Dovgaluk
Размер самого модуля — около 20 см.
Строго говоря, память в нём есть — сдвиговые регистры в каждом из 16-строчных блоков.
Т.е. можно выбрать адрес, загрузить 4 строки, соответствующие этому адресу, и они сами будут светиться.
Dark_Purple
Сходил по сылке, матрица P3 — 3мм шаг.
Dovgaluk
Да, где-то так и есть. А зачем такая точность с размерами?
Dark_Purple
Я купил такую матрицу P2. Verilog изучаю. ))
Dovgaluk
Будет интересно увидеть результат.