19 May

Собираем игру «Змейка» на макетной плате. Часть 2: «векторный» дисплей

Circuit designDIYElectronics for beginners
В первой части мы собрали автомат с логикой игры. Точнее, не всей игры, а только движения самой змеи. В этой, заключительной, части мы разберёмся с подключением экрана и закончим всю схему целиком.


Большое разрешение — по клику

Рисуем хвост


У нас уже есть голова, которая одиноко бегает по полю 8×8, теперь надо нарисовать хвост. Это уже не одна точка, а много, и просто передать координаты (X, Y) на дешифраторы у нас не получится.

Обычно на таких матрицах, как у нас, используется «динамическая индикация», причем построчный вариант: когда по очереди выдаётся содержимое каждой строки целиком. В наших условиях для этого придётся либо хранить где-то все 64 бита, либо каким-то сложным способом вычислять значение для каждой строки. Но есть ещё один вариант индикации, он тоже вполне динамический в том плане, что не все точки загораются одновременно. Мы можем воспользоваться чем-то похожим на «векторный дисплей» — выводить каждую точку по очереди, подавая на экран её координаты. В каждый отдельный момент времени будет гореть только один пиксель, который мы будем водить по экрану.

Поскольку количество точек у нас может быть разным (в зависимости от длины хвоста), то и яркость получающейся картинки тоже будет меняться с течением игры и ростом самой змеи. Чтобы такого не происходило, мы зарезервируем фиксированное количество кадров (10 = 1 кадр для головы, 1 для яблока и 8 для хвоста) и будем гасить экран для ненужных точек.


A — яблоко, H — голова, T# — клетки хвоста. Нарисовано в wavedrom

Для отображения нам тоже понадобится автомат. Этот автомат будет иметь несколько частей: одна из них — счётчик кадров, который будет просто обходить по кругу 10 состояний. Возьмем для этих целей ИЕ18 и немного логики.



Самое простое — вывод головы, в этом кадре мы просто включим экран и подадим на шину x/y то значение, которое нам даёт автомат хода. Для этого воспользуемся буфером АП6 (можно взять и АП5, но у него не такая удобная распиновка).
Далее нам надо нарисовать хвост. Для этого мы запомним в нашем состоянии то, что только что нарисовали. Добавим к нему направление роста хвоста (с помощью схемы из предыдущей части) и выведем на экран. Чтобы знать, что нам надо выводить хвост мы просто сравним номер кадра с длиной хвоста с помощью 4-битного компаратора СП1 (U13). Хранить предыдущие координаты будем в 8-битном регистре ИР37 (или ИР27, просто они закончились...), а для получения новых воспользуемся EEPROM, таблицу для которой мы уже сгенерировали в первой части. Направление нужной секции хвоста заберём из автомата игры с помощью мультиплексоров КП15, подав на адресные входы номер кадра. Причём надо не забыть, что храним мы направление головы, которое противоположно направлению роста хвоста, а значит одну из компонент нужно проинвертировать. К счастью, отдельный инвертор ставить не придётся, ведь у КП15 есть инверсный выход. Итого:


Автомат получился немного более запутанный, но, тем не менее, принцип работы у него такой же, как и у всех остальных.

Яблоко


Это самая «грязная» часть нашей схемы. Во-первых, потому что тут требуется случайное положение яблока, а наши автоматы не имеют ни капли случайности. Во-вторых, нам понадобиться прокинуть сигнал поедания яблока из одного автомата в другой, при этом автоматы имеют разный тактовый сигнал. По-умному это называется clock domain crossing, но мы сделаем простой костыль.

Где взять рандом? Можно придумать псевдо-рандомный генератор, но на это понадобится нетривиальное количество логики. Другой вариант — взять тактовый генератор с другой частотой, желательно не очень стабильный, но наши NE555 и так стабильностью не отличаются. В схему мультивибратора можно добавить каких-нибудь шумных или нелинейных элементов по вашему вкусу (я добавил последовательно с резистором JFET с болтающимся в воздухе затвором). Получать рандомную координату и запоминать её мы будем в 6-битном счётчике. Готовых чипов на 6 бит нет, поэтому соединим два корпуса ИЕ10:



В этом же узле мы поставим буфер для вывода яблока на экран по разрешающему сигналу. А также компаратор для того чтобы понять, что то, что у нас сейчас выводится на экран, совпадает с яблоком (два СП1). Не будем только сравнивать яблоко с самим собой, для этого воспользуемся 4-м битом компаратора и подадим на него сигнал разрешения с одной стороны и единицу — с другой.

И вот тут нас поджидает грязный хак: в зависимости от серии микросхемы, задержки сигнала разрешения, паразитной емкости макетки и фазы луны компаратор может включиться чуть раньше, чем выключится драйвер U23. Более наглядно, что происходит:



Из-за выбранной схемы синхронизации (про неё далее) такой глюк будет нам мешать. Правильно было бы его подавить с помощью задержки, например из нескольких инверторов, или вообще разнести включение и сравнение на разные фазы. Но я уже достаточно устал и просто задавил его конденсатором C5, раз уж это грязная часть схемы :)

Тактирование и выбор нового яблока


Основной генератор U7 тактирует кадры, их у нас 10, дальше эту частоту мы поделим на 16 с помощью ещё одного счётчика ИЕ10 (U19) и воспользуемся для тактирования шагов. Сигнал о совпадении головы с яблоком появляется только на одном кадре из 10 и не продержится до фронта импульса, переключающего кадр. Вот здесь нам нужна схема синхронизации. Я решил взять самый простой вариант: мы заведём сигнал в асинхронный вход триггера, а сбрасывать его будем на каждый новый шаг принимающего автомата.



На выходе триггера мы получим сигнал для добавления ещё одной клетки хвоста (U6), а также для запуска счётчика, хранящего координаты головы (U21, U22), это сгенерирует новое, по возможности рандомное, яблоко.

Вся схема



Большая схема по клику. А как это выглядит на макетке — в начале статьи

Детали и компоненты


макетные платы


Макетные платы можно взять китайские с али, но тогда на проблемы с плохими контактами уйдёт гораздо больше времени, чем на сборку непосредственно схемы. Хорошие платы рекомендует Ben Eater, это платы BB830 (белые) или WBU-202 (желтые). Набор проводов тоже лучше всего взять Wisher (WJW-60B), а в качестве мягких сойдёт любой китайский набор, даже самый дешёвый.

микросхемы


Я старался собрать на самой популярной отечественной серии, КР1533. На западе это серия 74ALS, но там она популярностью совсем не пользовалась. В данной схеме нет никаких критических параметров по таймингам или нагрузочной способности, поэтому можно спокойно взять серию К555 (74LS) или вообще К155 (SN74). Из импортных можно взять 74HC (но тогда для совместимости уровней придётся почти все чипы брать из этой серии) или 74HCT, которая полностью совместима с ТТЛ- и КМОП-сериями.

Найти отечественные микросхемы оказалось непростой задачей: в популярных онлайн-магазинах они никому не нужны и все остатки давно распродали. Какие-то чипы я насобирал в местных оффлайн-магазинах, другие пришлось заказывать в интернете, но многим поставщикам неинтересно возиться с мелкими заказами, так что это было то ещё развлечение…

Итоговый BOM получился такой (через слэш указаны возможные замены):

──────────────────────────────────────────────────────
логика          │ 1× к*лн1 74*04
                │ 1× к*ла3 74*00
                │ 1× к*ла1 74*20
триггер         │ 1× к*тм2 74*74
буферы          │ 2× к*ап6 74*245 / к*ап5 74*244 (другая распиновка)
компараторы     │ 3× к*сп1 74*85
мультиплексоры  │ 2× к*кп15 74*251 / *кп7 *151
счетчики        │ 1× *ие18 *163
                │ 4× *ие18 *163 / *ие10 *161
регистры        │ 3× *ир27 74*377 / *ир37 74*574 (другая распиновка)
                │ 1× *ир37 74*574 / *ир27 74*377 (другая распиновка)
EEPROM          │ 3× AT28C16 / CAT28C16
дешифраторы     │ 1× *ид7 74*138 / ид4 74*155 (другая схема)
                │ 1× К561ИД1 CD4028 (другая схема) / записанный AT28C16
генератор       | 2× КР1006ВИ1 NE555
──────────────────────────────────────────────────────

Итог


Надеюсь, эта схема вам понравилась и, возможно, у кого-нибудь поднимется рука её повторить, или сделать что-то ещё более интересное ))

Видео можно посмотреть на ютубе:

в комментах к предыдущей части советовали фильтр на светодиодную матрицу, это очень хорошая штука, но при неярком освещении можно обойтись без него

Архив со схемой и дампами EEPROM можно скачать здесь.



Использованные материалы


1. Книга Харрис&Харрис, которую не устаёт рекомендовать YuriPanchul — для общего руководства.

2. Справочник Бирюкова С.А — для поиска распиновки конкретных микросхем.

обе книги можно найти в PDF, но бумажный вариант приятнее

3. Сайт Ben Eater’a и его ютуб-канал — для вдохновения ))

4. Wavedrom — для рисования диаграмм

Всем, кто дочитал до конца, спасибо за внимание!
Tags:Схемотехникатеория автоматовSnakeЗмейкаретро-игры
Hubs: Circuit design DIY Electronics for beginners
+45
4.5k 45
Comments 14
Popular right now
Профессия Product Manager
December 2, 2020108,500 ₽Нетология
Python для анализа данных
December 2, 202019,000 ₽SkillFactory
Профессия Project Manager
December 2, 202098,000 ₽Нетология
Профессия Data Scientist
December 2, 2020135,000 ₽SkillFactory
Разработка приложений на Kotlin
December 2, 202020,900 ₽Нетология