[Из песочницы] Детская игрушка на логических элементах
В этой, с позволения сказать, статье я хочу рассказать о своем первом проекте в электротехнике. Должен заметить, что я по роду деятельности далек от схемотехники и радиоэлектроники, но интерес к этой теме не давал мне покоя с малых лет. Для людей с опытом информация ниже может показаться слишком очевидной, а многое сделанное мной — «изобретением велосипеда». Но возможно какой-нибудь нуб, как и я, сможет открыть для себя что-то новое и интересное. Кому интересно, прошу под кат.
Все началось с идеи сделать для моей маленькой дочери развивающую доску. Хотелось, во-первых, размять руки и сделать что-то самому. Во-вторых, хотелось размять мозг и придумать что-то, чего нет на обычных досках такого типа.
После наблюдений за тем, что больше всего любит делать ребенок в повседневной жизни, было решено, что кроме стандартных цепочек-ручек-щеколд нужно добавить кнопок для нажимания и некое устройство, отображающее реакцию на нажатие. Так как отображаться должно было что-то несложное, но яркое, выбор пал на красную светодиодную матрицу 8×8.
До времени создания игрушки у меня уже некоторое время пылилась на полке Arduino Uno — ожидала, пока я смогу придумать что-то полезное кроме системы автополива цветов, которая, кроме скуки кромешной сама по себе, была чуть менее чем совсем мне не нужна. Я подумал, что вот и наступил ее (Arduino) час, ведь нужно с чего-то начинать. Почитав мануалы для матрицы, я узнал, что кроме того, что просто так к Arduino ее не подключить (только для нее одной нужно 16 выводов, которых в моей Arduino нет), управлять всеми светодиодами одновременно нельзя. Можно одновременно светить определенными диодами либо в одной строке, либо в одном столбце (управление общим катодом, либо общим анодом). И если делать это последовательно и достаточно быстро, человек перестает воспринимать мигание и видит стабильную картинку. Также я узнал, что для Arduino существуют готовые драйверы и библиотеки, которые берут на себя боль управления этим процессом. И вот факт отсутствия такого драйвера на тот момент предрешил исход всего проекта.
Пока я все прокрастинировал и откладывал выбор лучшего места для покупки драйвера, мне попала на глаза статья о работе триггерных систем. Для моего мозга гуманитария она стала настоящим открытием, дающим понимание того, как на примитивном уровне устроена память. Тогда-то я и задался вопросом, смогу ли я обойтись без Arduino и сделать свой проект на основе триггеров и логических схем.
Итак, вначале нужно было решить, что показывать, и как это делать. Было понятно, что необходимо по очереди подавать сигнал на восемь строк матрицы и для каждой итерации подавать параллельный сигнал на определенные столбцы. Хорошо, это дало мне понимание трех основных компонентов — генератора импульсов, преобразователя тактового импульса в восемь последовательных сигналов и преобразователя, который для каждого из восьми сигналов будет выводить определенную комбинацию параллельных сигналов. Все не так и сложно.
После некоторых раздумий в голове образовалась схема, в которой тактовый сигнал с помощью трех последовательно подключенных JK-триггеров преобразовывается в двоичный код, а затем с помощью логических схем — в восьмеричный. Детально о данном виде триггеров можно почитать хотя бы на Википедии. Если коротко, то у него есть два входа (J и K) и два выхода (Q и Q̄), а также вход синхронизации (CLK). При подаче логической единицы на один из входов при следующим импульсе синхронизации единица отобразится на соответствующем выходе и сохранится на нем независимо от того, будет ли снова подаваться синхронизирующий импульс и будет ли меняться значение на выбранном вводе при условии, что на втором вводе будет оставаться ноль. Если подать единицу на второй ввод, а на первый ноль, то при следующем импульсе синхронизации значение первого выхода поменяется на ноль, а второго на единицу. А вот если на оба входа триггера подать единицу, то при каждом импульсе синхронизации единица будет попеременно появляться на одном из выходов. И если взять два триггера, на синхронизирующий вход первого подать тактовый импульс, а на синхронизирующий вход второго выход сигнал с выхода Q̄ первого, то в результате выход Q1 будет выводить единицу каждые два такта, а Q2 — каждые четыре. Таким образом получится двухразрядный двоичный счетчик. И если добавить таким же образом третий триггер, то за счет третьего разряда можно досчитать бинарным кодом до восьми — то, что надо.
Далее нужно было создать таблицу истинности и подобрать набор логических ключей так, чтоб двоичный код превратить в восемь последовательных сигналов. Если для кого-то таблица истинности и булевы операции — это что-то новое и неизвестное, то можно о них почитать опять таки на Википедии тут и тут.
Казалось бы, половина дела есть, но на самом деле, все было не так просто. Когда я собрал на макетке первую часть схемы для теста и представил, как аналогичным образом реализовать вторую часть, моя фантазия нарисовала долгие месяцы (а может и годы — время заниматься хобби есть чуть больше часа после работы) рисования схем и составления таблиц истинности. Ведь для восьми строк каждой картинки нужно сгенерировать уникальную комбинацию столбцов. И чем больше будет картинок, тем монструознее получится схема. Я понял, что сделать задуманное на одних лишь логических ключах не получится. Нужно было искать нечто, что могло упростить данный процесс.
Решением стала микросхема памяти. Для моей задачи хорошо подходила память EEPROM (Electrically Erasable Programmable Read-Only Memory) — программируемая память с возможностю электрического стирания с параллельным вводом/выводом. У памяти есть насколько адресных входов, которые, по сути, являются разрядами бинарного адреса ячеек памяти. То есть, если у памяти n адресных входов, можно запрограммировать 2^n ячеек. Количество выводов памяти — это так называемая «длина слова», или же фактическая длина бинарной строки, которую можно записать в каждую ячейку. Произведение количества ячеек на длину слов определяет объем памяти в битах.
Входящий сигнал в виде бинарного кода у меня был доступным на выходе из JK-триггеров. Осталось дополнить его битами от кнопок, которые должны отвечать за вывод разных картинок, и дело в шляпе.
И опять отсутствие опыта не дало мне адекватно оценить сложность процесса. Ведь память нужно запрограммировать, а для этого нужен программатор — прибор ощутимо дорогой для того, чтоб приобрести его для разовой игрушечной поделки. Гугление показало, что теоретически можно было сделать это с помощью Arduino. Но для программирования нужно одновременно подавать сигналы и на адресные входы чипа памяти и на выводы, которые в последствии должны воспроизводить сигнал. А еще нужны сигналы управления записью чипа. То есть, опять больше, чем доступно пинов. Дополнительное гугление открыло для меня сдвиговый регистр — чип, который запоминает задаваемую последовательность нулей и единиц и отображает их на параллельных выходах. Зачастую такие чипы работаю еще и как буфер и имеют выход, который может последовательно воспроизвести сигналы на входе. То есть, если подключить к нему следующий такой же регистр, то можно параллельно отобразить в два раза большую последовательность, чем для одного. По мере ввода строки, первая ее часть пройдет через первый регистр как через буфер на второй, а остальная часть останется на первом регистре. Добавив третий регистр, можно утроить длину строки и т.д. Для реализации этого нужно было написать скетч на незнакомом мне языке программирования. Но имея некий опыт в Python и множество примеров в интернете, после череды проб и ошибок эта задача оказалась вполне выполнима. Скетч можно взять на гитхабе.
И вот скетч написан, микросхема подсоединена, запуск и… ничего — память не программируется. Несколько проб, изменение параметров записи, и никаких результатов. Микросхема у меня была W27C512–45Z. Внимательное чтение мануалов показало неприятный момент. Для записи на определенный контакт микросхемы необходимо подать ток 0.03А напряжением 12В. Я подумал, что просто купил не совсем подходящий чип. Но прошерстив прилавки местных магазинов электро компонентов, я убедился, что 12В нужно всем. Лабораторного блока питания у меня не было. Блоков на 12В в доме полно, но все они импульсные, к тому же ток порядка 1А. Да простят меня опытные инженеры за такое кощунство, но отчаявшись, я решил попробовать, не случится ли чуда с теми блоками, что были под рукой. Не случилось. Первые два прохода записи не дали ничего, а после третьего микросхема перестала подавать признаки жизни.
В интернете я нашел упоминания о некой микросхеме ST662AB — преобразователе 5В-12В — который в сборе с нужным набором конденсаторов должен давать необходимые ток и напряжение. По факту найти микросхему оказалось непросто. В результате заказал ее из Китая, еще и SMD. А что же делать от четырех до шести недель доставки? Правильно, учиться. Пролистывая статьи по программированию памяти, я натолкнулся на упоминание о микросхеме, которую можно программировать при 5В. Речь шла о AT28C256. И действительно, в даташитах к ней никакого упоминания о 12В не было. Нужно брать! Правда микросхема для моих нужд была немного избыточна, так как позволяла сохранить 256Кб: 8-битный выход для 32К адресов, что с учетом занятых трех адресных пинов для сигналов синхронизации строк, оставляло возможность закодировать аж 4096 изображений (мне бы хватило и 10). Кроме того, доставку пришлось сделать аж из Великобритании. Но других вариантов я не нашел, и в конце концов, память можно повторно перепрограммировать, и когда игрушка утратит актуальность, чип можно будет использовать где-то еще. Так через четыре дня память была у меня. Тестовый прогон скетча, и счастье — все работает.
Осталось последнее — решить, сколько будет кнопок, нарисовать картинки 8×8 и реализовать добавление сигналов от кнопок в схему. Прикинув место на доске, я остановился на пяти кнопках. Учитывая никчёмный спрос в сравнении с ресурсом памяти, самым простым способом было подавать сигнал от каждой кнопки напрямую на отдельный вход, не применяя никакого кодирования. Правда, пришлось решать еще задачу переключения между картинками. Можно было использовать кнопки с фиксацией нажима. Но такая реализация не подходила для использования годовалым ребенком, ведь тогда перед нажатием на следующую кнопку надо было отжать работающую, да и была достаточно примитивна сама по себе. Хотелось придумать схему для кнопок без фиксации, при которой нажатие каждой кнопки бы сохранялось, да еще и отменяя нажатие предыдущей. Я читал про особенности применения разных видов триггеров, надеясь что какой-то из них может решить эту задачу самостоятельно, но увы. Посидев немного с листком и карандашом, я придумал следующую схему (пример для трех кнопок).
Вначале необходимо все кнопки подключить на некий коллектор, который на выходе будет давать единицу при нажатии на любую из кнопок. Для этого подойдет OR ключ. Так как чаще всего микросхемы ключей имеют только два входа, необходимо подключить первые две кнопки на один ключ, далее его выход подключить на первый вход второго ключа, а на его второй вход — третью кнопку. Таким способом можно продолжить подключать больше кнопок, добавляя новый ключ для каждой последующей. Кроме того, каждую кнопку нужно подключить на отдельный XOR ключ и на J вход отдельного JK-триггера. На второй вход XOR ключей подключить выход OR буфера, а выход каждого XOR ключа — на K вход соответствующего JK-триггера. Таким образом, нажимая, например, на кнопку 1, на J1 будет подаваться единица, а XOR1 срабатывать не будет, так как на него подается единица и от кнопки, и от OR буфера. На выходе Q1 также появится и будет сохраняться единица. В то же время сработают XOR2 и XOR3, подавая единицу на K2 и K3. И если на Q2 или Q3 до этого была единица, она сменится нулем.
Придумывание картинок 8×8 также было отдельным испытанием. Слишком мало точек для того, чтоб воспроизвести узнаваемое изображение. Но включив фантазию, все же удалось нарисовать несколько, например такого андроида.
Для картинок я создал таблицы истинности. Но так как на матрицу нужно для строк подавать единицу, а для столбцов ноль, таблицу пришлось инвертировать. Получившийся бинарный код я записал в шестнадцатеричной кодировке для более удобного использования в скетче Arduino.
Для сборки всей схемы я хотел заказать готовую плату. Но из списка доступных фирм, предлагавших услуги по изготовлению плат по макету, самый дешевый вариант двусторонней платы мне предложили почти за $25. Не знаю, может это и нормальная стоимость, но мне показалась многовато. Кроме того, у меня совсем нет опыта проектирования макетов. И еще я нахожу процесс пайки очень приятным и успокаивающим. Поэтому я купил универсальную плату, рулон разноцветной проволоки, необходимые компоненты и на несколько вечеров засел за сборкой. Так как все компоненты работают от напряжения от 5В до 12В. Для удобства, я сделал питание от батарейки 9В.
Как все в результате работает можно посмотреть тут.
В качестве «сердца» всей схемы я использовал генератор импульсов. Я не был уверен, какая точно нужна частота тактового импульса, поэтому воспользовался готовой схемой с регулировкой. Осциллографа у меня, к сожалению, нет, но по сопоставлению регулировок и даташита схемы, используется где-то 1КГц. Здесь на видео показано как меняется частота с низкой до более высокой, можно рассмотреть, как прорисовываются строки матрицы.
Спасибо за внимание.