Текстовая анимация с помощью Arduino

Я видел много статей о том, как подключить панель ЖК-дисплея к Arduino, и статьи, которые помогают рисовать пользовательские символы, но я не видел таких, которые бы использовали функцию пользовательских символов для анимации.

Нам понадобится

Что вам понадобится для этого:
- Arduino Uno
- HD44780-совместимый ЖК-дисплей
- Макет-прототип
- Один резистор 10 кОм
- Один потенциометр 10 кОм
- Паяльники и паяльные материалы

Дополнительно, если вы припаяете ЖК-дисплей к отдельной плате:
- Еще одна небольшая макетная плата с, по меньшей мере, двумя рядами и шестнадцатью отверстиями в ряду (по желанию)
- 16-контактный разъем типа «мама» или что-то подобное (например, разъемы для чипа)

Даже если вы не припаяете ЖК-дисплей к отдельной плате, вам, вероятно, понадобится 16-штырьковый ряд штекерных разъемов типа «папа-папа», чтобы вы могли прикрепить свой ЖК-дисплей непосредственно к макету без пайки.

Зачем это небольшое хакерство нужно вообще? Конечно, здесь нет большой полезности, если делать таким образом для общих целей анимации. Для этого нужен настоящий ЖК-дисплей, а не основной текстовый дисплей. Тем не менее, общий метод может быть интересен тем, у кого есть ограниченный компонент отображения, и необходим какой-то анимированный индикатор прогресса или уровня.

Шаг 1: подключите ЖК-дисплей к макету

Шаг 1: подключите ЖК-дисплей к макету

Шаг 1: подключите ЖК-дисплей к макету

Вы можете найти другие инструкции, которая объясняет, как сделать этот шаг для подключения ЖК-панели к вашему Arduino. Прежде чем вы сможете это сделать, у вас должно быть несколько проводов или заглушек, прикрепленных к отверстиям штифта ЖК-панели.

Мне посчастливилось найти ЖК-монитор, подключенный к макету, который кто-то использовал. Это была небольшая штуковина с двумя рядами по семь ножек на одном конце, а провода на «RA» и «RK» на другом конце.

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

Если вы посмотрите на заднюю панель, вы увидите, что есть числа, обозначающие контакты 1, 2, 13 и 14, поэтому мне было ясно, где каждый вывод. Если вы подключаете по своему усмотрению, то я настоятельно рекомендую использовать провода разных цветов, чтобы вы ничего не перепутали. В первый раз, когда я так сделал, я переключал каждую пару проводов, начиная с провода 3, и должен был пройтись по всем.

Я аккуратно согнул провода и вставил голые контакты в макет. Сначала я проделал со всеми нечетными проводами, вставив их все в свои отверстия и припаяв контакты 1 и 13 только для того, чтобы все было на месте. Затем я вставил все провода с четными номерами и спаял 2 и 14. После стало проще и можно было уже припаять каждый по очереди.

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

Наконец, я согнул каждый из синих концов провода к соответствующему контакту и добавил пайки между каждой парой.

После этого я проверил каждую пару, чтобы убедиться, что я не сделал никаких ошибок.

Шаг 2: Подключение цепей

Шаг 2: Подключение цепей

На этом этапе вы должны иметь ЖК-дисплей с контактами, которые можно легко подключить к макетной плате и схеме на ней. Аналогичные инструкции вы найдете на других веб-страницах.

Выполняйте все эти подключения перед подключением питания к Arduino! И проверьте, и перепроверьте, и трижды проверьте провода, которые идут на Vcc и Ground, чтобы убедиться, что вы соединили их в правильном порядке.

Короткое замыкание и обратная проводка могут сжечь вашу ЖК-панель, плюс сжечь контакты и повредить Arduino. В этой цепи нет резисторов и диодов, чтобы предотвратить негативные последствия. Поэтому, пожалуйста, будьте осторожны! Я не могу нести ответственность, если вы подключите неправильно, или вы используете неправильную панель ЖК-дисплея для этого.

Типичная схема 44780 соединяет выводы в этом порядке:

LCD 1 (ЖК-дисплей 1) = Земля
LCD 2 = Vcc (+ 5V)
LCD 3 = контракт - подключается к среднему выступу потенциометра; Соедините одну сторону с землей, а другой через резистор 10 кОм к Vcc.
LCD 4 = Сброс (reset) = Arduino 7
LCD 5 = Чтение / запись = связь с землей, так как записываем, не читаем
LCD 6 = Включить (Enable) = Arduino 8
LCD 7 через 14 = линии данных DB0..DB7, соответственно. Меня интересуют только последние четыре бита, поэтому connect
LCD 11 - Arduino 9
LCD 12 - Arduino 10
LCD 13 - Arduino 11
LCD 14 - Arduino 12

Из-за этих настроек код эскиза (скетча) должен инициализировать объект LiquidCrystal:

(в моем прикрепленном изображении вы могли заметить, что я неправильно подключил потенциометр! Я исправил это после того, как сделал снимок!)

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

Шаг 3. Нарисуйте то, что вы анимируете

Шаг 3. Нарисуйте то, что вы анимируете

Чип HD44780 позволяет вам создавать и использовать до восьми пользовательских символов, а библиотека LiquidCrystal позволяет вам «создать» персонаж. Но функция createChar (index, byteArray) фактически заменяет биты определения символа, и если у вас есть какой-либо рисунок на экране, биты обновляются немедленно, поэтому это больше похоже на вызов «defineChar» или вызов «createOrUpdateChar» ,

В своей анимации я хотел нарисовать танк, проходящий через экран. Я решил нарисовать его как три символа на бумаге и оставить четвертый для смещения битов. Поскольку каждый символ имеет ширину в 5 пикселей и высоту в 8 пикселей, это дает мне площадь 15x8 пикселей для рисования танка.

В этом первоначальном рисунке вы можете увидеть, что я нарисовал гусеницы и нарисовал «колеса» внутри, но в результате я все бросил и использовал один сплошной контур по причинам, которые вы увидите позже.

Шаг 4: строим биты танка в коде

Я перевел чертеж танка в длинные целые числа. Длинные целые дают вам 32 бита и поэтому я могу представить танк, используя восемь длинных целых чисел, каждая из которых действительно использует только 15 бит для начального рисунка.

Кусок кода для этого есть здесь. Его легче читать шрифтом фиксированной ширины.

Я мог бы определить их, используя шестнадцатеричные значения, но я полагал, что использование двоичной нотации Bnnnnnn сделает ее более читаемой.

Шаг 5: Смещение символов

Чтобы переместить танк, я определил позицию x для рисования. Поскольку я имел дело с символами шириной в пять пикселей, я мог бы выполнить целочисленное деление позиции танка x, чтобы выяснить, где я буду рисовать каждый символ.

Я также просто возьму по модулю позицию x танка (tankx % 5), чтобы выяснить, как сдвинуть биты. Если бы модуль был равен нулю, я рисовал бы символы и определял бы биты символов. Но если бы модуль был ненулевым, это означало, что символы уже на экране, и я могу просто переопределить биты. Я также отрисовал бы ведущее пространство, чтобы исключить любой предшествующий рисунок пользовательского символа 0 (самый левый), когда бы я «двигал» фигуру.

Итак, для начала я бы инициализировал позицию tankx до некоторой величины, которая бы четко разделилась на пять.

Затем, внутри loop(), я бы сделал разделение и модуль, чтобы выяснить, что рисовать и как рисовать. (Остерегайтесь того, как работает модуль с отрицательными числами.)

Еще один способ сделать это, ретроспективно, состоял бы в том, чтобы сделать tankx всегда неотрицательным и сдвинуть позицию символа х на -3 перед рендерингом.

Это часть кода loop(), которая выводит на экран пользовательские символы. В лучшем исполнении этого кода, я превратил функции рисования в функцию safeDrawCharAt, которая выполняет проверку позиции. Но здесь вы видите более раннюю версию, где я выполнял проверку позиции. Так как в любое время символы могут быть за кадром, мне нужно было выполнить проверку позиции перед вызовами setCursor() или write().

Шаг 6: двигаем биты танка

Теперь, когда символы на экране, вы можете изменять их биты. В конечном счете, вам нужно вызвать функцию createChar(index, byteArray), чтобы получить биты на ЖК-дисплее, а это означает, что для каждого символа требуется массив из восьми байтов. Я использую четыре настраиваемых символа, поэтому я использовал четыре массива байт.

Внутри loop() я взял побитовое деление по модулю, чтобы получить смещение. Здесь эффективность длинных целых вступает в игру. Во-первых, я бы скопировал long int из статического танка в локальную переменную. Тогда я бы переложил всю long int обратно на количество бит, которое мне понадобится.

Наконец, когда все байтовые массивы были вычислены, я направил их на LCD.

Если вы вычисляете это путем смещения байтов, вам придется убедиться, что вы «переносите» последний бит в следующий байт по горизонтали, но так как я остаюсь в пределах 32-битного long int с каждым раундом, процессор делает перенос бита для меня.

В конце цикла я перемещаю танк, а затем перебираю цикл до начала после того, как танк ушел за пределы экрана.

Наконец, вы видите задержку. Важно использовать задержку, которая подходит для вашего ЖК-дисплея. У моего LCD синий экран с белой подсветкой, и исчезает всё довольно медленно, поэтому короткая задержка будет в итоге очень размытой.

Шаг 7: Анимация гусениц танка

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

Чертеж танка должен был использовать эту конфигурацию для начала, но на самом деле это означало, что я мог сначала включить все пиксели протектора (внутри длинного массива int), а затем отключить каждый третий пиксель. В зависимости от позиции tankx, по модулю 3, я бы выключил другой набор пикселей.

Однако исходным требованием было то, что общее количество пикселей в протекторе было кратным трем. В противном случае анимация будет показывать пустые пиксели.

Таким образом, я определил отдельное положение treadx (на самом деле не позиция x, скорее как счетчик, который будет содержать циклы 0, 1, 2, 0, 1, 2, ...), и на основе его значений я бы выяснил, какой бит протектора выключить. На моем рисунке это произойдет только в самых нижних четырех строках «y», которые соответствуют значениям 4, 5, 6 и 7 .

Поскольку все биты протектора танка были запущены, я мог бы использовать функцию C XOR, чтобы отключить их. Я применил бы это изменение к длинным целым, прежде чем я переместился бы в свою 0...4 побитовую позицию сдвига. Это произойдет, естественно, до того, как длинные целые числа будут разбиты на байты.

Шаг 8: смотрим как работает

Конечным результатом является танк, который перемещается по экрану.

Следует отметить, что разные ЖК-панели имеют разные физические схемы и характеристики. На этой плате имеется линия, ширина которой составляет пиксель между каждым символом, как по вертикали, так и по горизонтали. Дисплей имеет ширину 8 символов и высоту 2 символа. Я экспериментировал с различными настройками по модулю, позволяя компенсировать движение персонажа в каждом шестом сдвиге, а не в каждом пятом. Это то, с чем вам нужно играть, в зависимости от того, что вы пытаетесь сделать. Другая ЖК-панель, которую я получил от принтера HP, и она не имеет ширины одного пикселя, разделяющего ряды, но между каждым символом все еще есть расстояние.

Другое, чего нужно остерегаться - время затухания и контраст. Потенциометр позволяет устанавливать различные контрастные параметры, что облегчает просмотр пикселей. Время затухания может варьироваться между панелями. Чем дольше вы затухаете, тем больше задержка вам нужна, иначе вы столкнетесь с размытой анимацией. Кто-то, вероятно, найдет способ воспользоваться этим угасанием. Мне кажется, что может быть умный способ генерировать «серые» уровни путем быстрого включения и выключения пикселей, но только в том случае, если время действительно точное.

Наконец, с точки зрения кодирования, это может быть не самый эффективный способ что-то делать. Вместо этого вы можете предварительно визуализировать все биты башни и все комбинации бит протектора и даже предварительно сдвинуть их во все необходимые места. (Давайте посмотрим, это будет пять комбинаций для первых четырех линий, представляющих турель (башню), и трижды пять для смещенных по битам комбинаций протектора, умноженных на восемь длинных целых чисел, всего 5x8 + 3x5x8 = 4x5x8 = 160 long ints = 640 байт.

Фактический код на шаге 9 (см.ниже).

Шаг 9: Код танка для 44780 / RT0802B-1 Ver 2.0

Ардуино+
Больше интересного ↓