Подключение жидкокристаллического дисплея LCD1602 (HD44780) к микроконтроллеру ATmega8 в 4-битном режиме
Примечание:
Статья не является оригинальным переводом. Статья созданы на базе статьи (см. источник информации указанный ниже) путем его перевода, использования основного текста оригинала и дополнена автором; данный код протестирован на реальном устройстве ф. Winstar.
LCD-дисплеи (Liquid Crystal Displays) используют для отображения состояния или параметров в различных приборах.
LCD1602 – это 16-выводное устройство, имеющее 8 выводов для передачи данных (D0-D7) и 3 вывода управления (RS, RW, EN). Остальные 5 выводов предназначены для питания и подсветки ЖК-дисплея. Цифры «1602» указывают на формат выводимой (отображаемой) информации: 16×02 символов (рисунок 1).
Выводы управления помогают нам настроить LCD-дисплей в командном режиме или режиме передачи данных. Они также помогают настроить режим чтения или записи, а также время чтения или записи.
LCD-дисплей 16×2 можно использовать в 4-битном или 8-битном режиме в зависимости от технических требований. Чтобы использовать его, нам необходимо отправить определенные команды на LCD-дисплей в командном режиме, и как только ЖК-дисплей будет настроен в соответствии с нашими требованиями, мы сможем отправить необходимые данные в режиме передачи данных.

В 4-битном режиме данные/команды отправляются в 4-битном (полубайтном) формате.
Для этого сначала необходимо отправить «старшие» (верхние) 4 бита, а затем отправить «младшие» (нижние) 4 бита данных/команд.
Только 4 выводы данных (D4 — D7) LCD-дисплея 16×02 подключены к микроконтроллеру, а другие управляющие выводы RS (выбор регистра), RW (чтение/запись), E (сигнал разрешения) подключены к другим GPIO выводам микроконтроллера (рисунок 2).
Таким образом, благодаря такому подключению мы можем сэкономить четыре GPIO вывода микроконтроллера, которые можно использовать для других целей.

Подстрочный резистор R1 предназначен для точной подстройки контрастности дисплея. Резистор R2 предназначен для ограничения тока на аноде подсветки дисплея.
Функция инициализации дисплея:
1. Необходимо подождать не менее 15 мс, время инициализации включения питания для LCD1602.
2. Отправить команду 0x02, которая инициализирует LCD-дисплей 16×2 в 4-битном режиме.
3. Отправить команду 0x28, которая переводит LCD-дисплей в 2-строчный, 4-битный режим и 5×8 точек.
4. Отправить одну из команд включения курсора дисплея (0x0E, 0x0C).
5. Отправить команду 0x06 (сдвиг курсора вправо).
void LCD_Init (void) /* LCD Initialize function */ < LCD_Dir = 0xFF; /* Make LCD port direction as o/p */ _delay_ms(20); /* LCD Power ON delay always >15ms */ LCD_Command(0x02); /* Send for 4 bit initialization of LCD */ LCD_Command(0x28); /* 2 line, 5*7 matrix in 4-bit mode */ LCD_Command(0x0c); /* Display on cursor off */ LCD_Command(0x06); /* Increment cursor (shift cursor to right) */ LCD_Command(0x01); /* Clear display screen */ _delay_ms(2); >
Теперь мы успешно инициализировали LCD-дисплей, и он готов принимать данные в 4-битном (полубайтном) режиме для отображения.
Чтобы отправить команду/данные на LCD -дисплей 16×02, мы должны отправить «старший» (верхний) полубайт, а затем «младший» (нижний) полубайт. Поскольку выводы D4-D7 LCD-дисплея 16×02 подключены как выводы данных, мы должны сдвинуть младший полубайт вправо на 4 перед передачей.
Функция записи команд (инструкций):
1. Сначала отправим более «высокий» полубайт команды.
2. Установим «низкий» уровень на выводе RS, RS=0 (регистр команд)
3. Установим вывод RW на «низкий» уровень, RW=0 (операция записи) или подключим его к земле.
4. Подадим импульс от «высокого» до «низкого» при включении (E).
5. Отправим «младший» полубайт команды.
6. Подадим импульс от «высокого» до «низкого» при включении (E).
void LCD_Command( unsigned char cmnd ) < LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0);/* Sending upper nibble */ LCD_Port &= ~ (1<Функция записи данных:
1. Сначала отправим более «высокий» полубайт данных.
2. Установим вывод RS на «высокий» уровень, RS=1 (регистр данных)
3. Установим вывод RW на «низкий» уровень, RW=0 (операция записи) или подключим его к земле.
4. Подадим импульс от «высокого» до «низкого» при включении (E).
5. Отправим «младший» полубайт данных.
6. Подадим «импульс» от «высокого» до «низкого» при включении (E).
void LCD_Char( unsigned char data ) < LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0);/* Sending upper nibble */ LCD_Port |= (1<#define F_CPU 8000000UL /* Define CPU Frequency e.g. here 8MHz */ #include /* Include AVR std. library file */ #include /* Include Delay header file */ #define LCD_Dir DDRB /* Define LCD data port direction */ #define LCD_Port PORTB /* Define LCD data port */ #define RS PB0 /* Define Register Select pin */ #define EN PB1 /* Define Enable signal pin */ void LCD_Command( unsigned char cmnd ) < LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0); /* sending upper nibble */ LCD_Port &= ~ (1<void LCD_Char( unsigned char data ) < LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0); /* sending upper nibble */ LCD_Port |= (1< void LCD_Init (void) /* LCD Initialize function */ < LCD_Dir = 0xFF; /* Make LCD port direction as o/p */ _delay_ms(20); /* LCD Power ON delay always >15ms */ LCD_Command(0x02); /* send for 4 bit initialization of LCD */ LCD_Command(0x28); /* 2 line, 5*7 matrix in 4-bit mode */ LCD_Command(0x0c); /* Display on cursor off*/ LCD_Command(0x06); /* Increment cursor (shift cursor to right)*/ LCD_Command(0x01); /* Clear display screen*/ _delay_ms(2); > void LCD_String (char *str) /* Send string to LCD function */ < int i; for(i=0;str[i]!=0;i++) /* Send each char of string till the NULL */ < LCD_Char (str[i]); >> void LCD_String_xy (char row, char pos, char *str) /* Send string to LCD with xy position */ < if (row == 0 && pos<16) LCD_Command((pos & 0x0F)|0x80); /* Command of first row and required position<16 */ else if (row == 1 && pos<16) LCD_Command((pos & 0x0F)|0xC0); /* Command of first row and required position<16 */ LCD_String(str); /* Call LCD string function */ >void LCD_Clear() < LCD_Command (0x01); /* Clear display */ _delay_ms(2); LCD_Command (0x80); /* Cursor at home position */ >int main() < LCD_Init(); /* Initialization of LCD*/ LCD_String("Hello World"); /* Write string on 1st line of LCD*/ LCD_Command(0xC0); /* Go to 2nd line*/ LCD_String("4 bit"); /* Write string on 2nd line*/ while(1); > Для удобства использования оформим описанный выше код в виде библиотеки. Для этого создадим два файла LCD1602.h и LCD1602.c.
Листинг файла LCD1602.h
#ifndef LCD1602_H_ #define LCD1602_H_ #define LCD_Dir DDRB #define LCD_Port PORTB #define RS PB0 #define EN PB1 #include #include void LCD_Command( unsigned char cmnd ); void LCD_Char( unsigned char data ); void LCD_Init (void); void LCD_String (char *str); void LCD_String_xy (char row, char pos, char *str); void LCD_Clear(); #endif /* LCD1602_H_ */Листинг файла LCD1602.c
#include "LCD1602.h" void LCD_Command( unsigned char cmnd ) < LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0); LCD_Port &= ~ (1<void LCD_Char( unsigned char data ) < LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0); LCD_Port |= (1< void LCD_Init (void) < LCD_Dir = 0xFF; _delay_ms(20); LCD_Command(0x02); LCD_Command(0x28); LCD_Command(0x0c); LCD_Command(0x06); LCD_Command(0x01); _delay_ms(2); >void LCD_String (char *str) < int i; for(i=0;str[i]!=0;i++) < LCD_Char (str[i]); >> void LCD_String_xy (char row, char pos, char *str) < if (row == 0 && pos<16) LCD_Command((pos & 0x0F)|0x80); else if (row == 1 && pos<16) LCD_Command((pos & 0x0F)|0xC0); LCD_String(str); >void LCD_Clear() Для подключения библиотеки необходимо файлы LCD1602.h и LCD1602.c поместить в папку с проектом, в программе Atmel Studio правой клавишей мыши кликнуть на имя проекта, выбрать Add - Existing Item, найти и выбрать все два файла, нажать OK.
Далее пишем код:
#include #include "LCD1602.h" int main() < LCD_Init(); LCD_String("Hello World"); LCD_Command(0xC0); LCD_String("4 bit"); while(1) < >>После загрузки прошивки на дисплее LCD1602 мы увидим следующий результат, показанный на рисунке 3.
Расшифровка наиболее употребляемых команд, посылаемых от микроконтроллера в дисплей LCD1602 (HD44780) приведена в таблицах 1, 2.
Таблица 1 – Расшифровка наиболее употребляемых команд, посылаемых от микроконтроллера в дисплей LCD1602 (HD44780)
Команда ЖКИ
HEX-код
Выполняемые действия
Время вып., мкс
Пустой экран, очистка памяти, курсор в левой верхней позиции
Возвращает курсор в начало
Курсор в левой верхней позиции, память не очищается
Сдвиг курсора влево
После вывода очередного символа курсор автоматически сдвигается на одно знакоместо влево
Сдвиг курсора вправо
После вывода очередного символа курсор автоматически сдвигается на одно знакоместо вправо
Полное отсутствие изображения на экране ЖКИ
Разрешается вывод изображения, но курсор не виден
Прямоугольная форма курсора
Разрешается вывод изображения, курсор в виде темного мигающего прямоугольника
Линейная форма курсора
Разрешается вывод изображения, курсор в виде нижней подстрочной немигающей линии
Комплексная форма курсора
Разрешается вывод изображения, курсор в виде мигающего прямоугольника с подчеркиванием
Интерфейс 4 бита, 1 строка
Связь с однострочным ЖКИ через 4 линии шины данных
Интерфейс 4 бита, 2 строки
Связь с двухстрочным ЖКИ через 4 линии шины данных
Интерфейс 8 бит, 1 строка
Связь с однострочным ЖКИ через 8 линий шины данных
Интерфейс 8 бит, 2 строки
Связь с двухстрочным ЖКИ через 8 линий шины данных
Доступ к ОЗУ знакогенератора
Запись данных по этим адресам позволяет создавать 16 своих символов
Установка позиции курсора
Курсор устанавливается в позицию согласно табл. 2
Время выполнения команд указано приблизительно. Оно определяется частотой внутреннего RC-генератора LCD-дисплея, которая, в свою очередь, зависит от технологического разброса и температуры нагрева корпуса.
Таблица 2 – Команды для перехода на определенное знакоместо верхней или нижней строки экрана для дисплея LCD1602 (HD44780)
Верхняя строка ЖКИ
Электромеханический 7-сегментный дисплей своими руками
Любительский проект по сборке с нуля уникального настенного дисплея с функцией часов и возможностью дополнительного апгрейда. Вооружаемся шаговыми двигателями, МДФ, платами, кучей проводов и вперёд.
Цель проекта была двоякая: мне хотелось создать стильные часы, которые украсили бы собой голую стену, и одновременно обеспечить максимально тихую работу механизма. Вдохновили меня на эту затею другие впечатляющие проекты, которые я перечислил ниже, хотя во многих задействовались шумные сервоприводы. Взяв за основу собственную идею по модернизации тихих шаговых двигателей для 3D-принтеров, я с нуля собрал всю конструкцию, протестировал её и написал необходимый код, на что ушло где-то 2-3 месяца.
Все программные и аппаратные файлы доступны на GitHub
Примеры решений
Вот пара ссылок, которые оказались полезны для понимания принципа действия шаговых двигателей:
- 28BYJ-48 — 5V Stepper Motor
- Control 28BYJ-48 Stepper Motor with ULN2003 Driver & Arduino
Выбор двигателя
Чтобы добиться максимально тихой механической работы, я хотел полностью избежать использования серводвигателей (что исключило 5 из 6 имевшихся примеров решений). Серводвигатели изначально не задуманы для тихой работы. Даже ряд имеющихся у меня передовых решений от Robotis довольно сильно шумят.
Поэтому я выбрал один из самых популярных шаговых моторов, 28BYJ-48 (версию 12В). Хотя в связи с наличием в них внутренних шестернёй, у меня все равно оставались сомнения относительно их шумности.
Предварительный тест драйвера шагового двигателя
В качестве первого основного теста я подключил моторчик 28YJ-48 к имевшейся под рукой плате Adafruit TB6612 (подключение 12В здесь не показано).
В начальном тесте использовался базовый образец программного обеспечения: Stepper: setSpeed(rpms)
В сравнении с любым серводвигателем уровень шума оказался намного ниже. Тем не менее из теста стало понятно, что «обычный» драйвер вроде TB6612 с понижением шума от мотора и шестернёй справляется слабо.
Использование тихих драйверов
Я взял TMC2208-V3.0 от BIGTREETECH. Эти модули используются в основном в 3D-принтерах, чтобы сделать их движение максимально тихим. В них имеется режим UART, позволяющий параллельно подключить несколько модулей, задействовав всего один контакт микроконтроллера. Замена предыдущего драйвера на этот сразу же привела к значительному улучшению — практически полной тишине! Недостаток здесь в том, что реализация этих драйверов окажется намного сложнее…
Нюансы системы
Каждому TMC2208 нужно не менее четырёх сигналов: активация (EN), направление (DIR), STEP и UART. Чтобы избежать нехватки цифровых контактов ввода-вывода, я решил использовать для контактов активации и направления каждого драйвера сдвиговые регистры. Помимо этого, как я уже сказал, подключения UART могут быть общими для всех драйверов, задействуя всего один контакт микроконтроллера.
Можно было бы и каждый сигнал STEP отправить на сдвиговые регистры, но это бы сильно ударило по быстродействию при управлении всеми 28 моторами с одного микроконтроллера.
Системная архитектура для одного числа
Высокоуровневая схема подключения для одного 7-сегментного числа, использующая предыдущую схему. Линия STEP для каждого бесшумного шагового драйвера с сигналами EN и DIR, загружаемыми последовательно в сдвиговые регистры.
Единственный дополнительный необходимый сигнал, который здесь не показан, это линия UART_TX, подключенная к каждому отдельному драйверу.
Для показа одной цифры на часах потребуется 7 двигателей, 7 драйверов и 2 сдвиговых регистра.
Сдвиговые регистры на макетной плате
Чтобы не захламлять пространство на макетке, я собрал на микросхемах NXP 74HC595 плату с последовательным подключением сдвиговых регистров. В этом мне помогла полезная библиотека ShiftRegister74HC595. А неплохой образец последовательного подключения нескольких 74HC95 можно посмотреть в статье Multiple Shift-out Registers on Arduino — part 1.
“Заключительное” тестирование макетной платы
Все драйверы (7) установлены для управления всеми 7 двигателями (показаны только 4). Слева та самая плата со сдвиговыми регистрами. Всем управляет Mega2560, показанный сверху слева. На каждый мотор я прикрепил скрепку, просто чтобы сделать вращательное движение более наглядным при тестировании
К сожалению, подключить коннектор 28BYJ-48 напрямую в плату мне не удалось, так как провода располагались крест-накрест. В качестве быстрого решения я просто прокинул от коннекторов дополнительные соединительные провода.
Оригинальная гифка (15 МБ).
Первое тестирование всех чисел. Простейшая конфигурация, в которой я использовал картон и клейкую смесь Blu Tack, позволила мне протестировать функциональность схемы и подстроить базовые компоненты ПОКонцепция -> Схема -> Макет
Обрадовавшись рабочей схеме на макетной плате, я открыл KiCAD и набросал схему для платы управления одной цифрой. Она включала все компоненты и микросхемы, необходимые для управления моторами одной цифры часов (пассивные компоненты, сдвиговые регистры, контактные разъёмы и входы питания). По сути, я заменил макетную плату.
Для цельного дисплея часов потребуется четыре таких платы.
Кастомные печатные платы
Закончив первую ревизию платы управления двигателем, я отправил её на JLCPBC.com для изготовления. Четыре двухслойных платы + одна резервная обошлись мне около $5. Это без учёта доставки из Китая в UK.
Чтобы решить некоторые проблемы с трассировкой, я решил установить драйверы на плате вверх ногами.
Я мог существенно уменьшить общую схему, если бы вместо использования модулей драйверов разместил все необходимые компоненты по отдельности. Но мне захотелось сделать как проще.
Спустя неделю ожидания, пришли превосходные платы. После базовой проверки соединений я вручную припаял все компоненты, монтируемые в отверстия.
Переделка
В изначальном дизайне был один серьёзный косяк. Я забыл подключить входной контакт 5В к шаговым моторам. В результате у каждой микросхемы отсутствовала связь с логикой управления от микроконтроллера. В первых тестах плата работала отлично, но я не был уверен в долгосрочности такой работы.
Ошибку я исправил в очередной ревизии без переделки самих плат, просто прокинув по нижней стороне провод 22AWG.
Проектирование дисплея
Стараясь сделать понятное ПО, я хотел, чтобы все моторы смотрели в одном направлении относительно своего положения ON/OFF. Такая направленность всех моторов позволила каждому из них передавать одинаковые позиционные параметры, то есть для всех моторов использовался общий код.
Это был первый шаг по разработке дисплея, и на тот момент только для одного числа.
Конструктивные элементы
В Fusion 360 я спроектировал физические макеты всех отдельных компонентов, необходимых для сборки прототипа:
- с нуля создал модель для моторов 28BYJ-48, используя цифровой штангенциркуль;
- спроектировал несколько версий крепежа ротора, который можно было бы крепить к роторам двигателей без винтов (и печатать без суппорта);
- спроектировал опоры для двигателей;
- скомпоновал всё это вместе и создал маску, которую затем напечатал и использовал при сверлении отверстий под монтаж.
Вид модели из F360 с обратной стороны, показывающий идеальное расположение печатной платы и маски для сверления
Модель маски пришлось разделить надвое, иначе она не вмещалась на печатную площадку принтера. Для каркаса я использовал МДФ толщиной 6мм, так как 3мм мне показалось маловато.
Проблема в том, что при ручной обработке неизбежно возникают мелкие погрешности в позиционировании отверстий, что может сильно навредить общему дизайну. В идеале, эту деталь желательно изготавливать на станке с ЧПУ.
Крепёж двигателей
Вот список деталей, потребовавшихся для крепления всех 28 двигателей:
- 56 опор, напечатанных на 3D-принтере (2 для каждого двигателя);
- по 112 винтов, болтов и шайб M3 (7 двигателей * 4 отверстия * 4 цифры);
- по 56 винтов и болтов M4 (7 двигателей * 2 отверстия * 4 цифры).
Тестирование одной цифры
Завершённый одноциферный дисплей. Можно считать его надёжной платформой для тестирования всех компонентов: кастомных плат, ПО, проводных соединений, режимов работы и так далее
Фото сделано до подключения всех компонентов
Тестирование базовой работоспособности
Оригинальная гифка (18 МБ).
Прогоняю все цифры по кругу. Знаменательный моментНа заднем плане видно приблизительные значения потребления тока от БП. В пике получается примерно 1.15А, поэтому я решил, что для уверенного запитывания всех 28 двигателей и прочего, нужно оценить общее потребление мощности.
Имейте в виду, что в этот момент при каждом движении питание подавалось на все двигатели. То есть даже неподвижные механизмы потребляли столько же, сколько движущиеся. В итоге я обновил программу, включив операцию исключающего НЕ-ИЛИ, сравнивающую текущее положение каждого мотора с его новым положением, чтобы контакт EN активировался и запитывался только у требующих движения механизмов.
Вычисление мощности
В пиковом состоянии — когда одновременно срабатывают все моторы — общая потребляемая мощность составила 43.2Вт. В реальности это может случиться только один или два раза при запуске. Тем не менее нужно гарантировать, что при необходимости мощности будет достаточно.
В худшем реалистичном случае максимальное потребление составит около 20Вт. При этом чаще всего — оно будет находиться в районе 10Вт.
Если предположить использование блока питания на 12В и 50Вт, то мощности хватит не только всем моторам и смежным компонентам, но и светодиодам.
Более точные графики показывают максимальное потребление (для одной цифры / 7 моторов) в районе тех же 1.15А. Последующие изменения значений показывают гораздо меньшее потребление, поэтому после стартовой подачи питания или особых случаев максимальный ток для одной цифры будет составлять около 0.8А
Простая плата питания
Решив отказаться от использования настольного источника питания, я купил блок на 12В и 50Вт, для которого быстренько сварганил небольшую платку. Она получает 12В, преобразует их через конвертер DC/DC в 5В (для ввода-вывода шаговых моторов, микроконтроллера и светодиодов), а также запитывает небольшой пьезодинамик 12В. Красный светодиод подключён к 12В, а зелёный к 5В. Здесь ничего особенного, просто способ отказаться от использования настольного блока питания.
Кнопки управления
Для установки времени, таймера и использования прочих функций я собрал ещё одну небольшую плату, к которой подключил несколько кнопок. Некоторые из них я подключил напрямую к контактам прерывания на микроконтроллере, а другие использовал в процедурах прерывания для установки значений. Для всех кнопок в программе реализована функция антидребезга с использованием небольших задержек.
Отсчёт времени
Для отсчёта времени я купил на Amazon модуль DS3231, который подключается к контактам I2C микроконтроллера и оперативно работает со множеством открытых библиотек.
Если интересно, то в статье Interface DS3231 Precision RTC Module with Arduino сделан прекрасный обзор этого модуля. А вот ещё одно годное руководство: Arduino and DS3231 Real Time Clock Tutorial.
Финальная сборка
Подключение всех модулей и плат для одной цифры
Сборка дисплея
Порадовавшись успешной сборке комплекта для одной цифры, нужно было переходить к сборке всего этого снова, но уже в четырёхкратном масштабе. Это подразумевало пайку и тестирование оставшихся плат управления моторами, сверление и выпиливание новой МДФ-панели, а также крепление моторов. На всё про всё ушло примерно 7-8 часов.
Задняя часть панели после подключения всех четырёх плат управления двигателями и соединения всех компонентов. На этой стадии укладка кабелей ещё не делалась. Перекладина посередине просто удерживала конструкцию на столе в вертикальном положении
Тестирование всего дисплея
Оригинальная гифка (18 МБ).
Прогон базовых тестов на всём дисплее (анимация ускорена в четыре раза из практических соображений)Все 28 моторов и драйверов управляются одновременно одним микроконтроллером Mega2560.
На этой стадии МДФ-панель ещё не покрашена, поэтому золотистые сегменты цифр не особо выделяются.А так я изначально планировал покрасить заднюю стенку, двигатели и обратную сторону каждого сегмента в один тёмный цвет, чтобы цифры смотрелись отчётливо.
Эстетика
Этап покраски. Здесь я использовал баллончик WRX Spray Paint — Anthracite Grey 7016.
Подсветка
Ещё один эстетический нюанс — простая непрерывная светодиодная лента на 5В по периметру. При подвешивании дисплея к стене она должна усиливать эффект выделения. Я также добавил на плату МОП-транзистор, чтобы можно было управлять подсветкой через GPIO на микроконтроллере.
По примеру одного из сохранённых мной вариантов сборки в качестве возможного улучшения я рассматривал использование программируемых светодиодных лент, свечение которых различным образом реагирует на срабатывание таймера, нажатие кнопок и прочие действия. Хотя даже с помощью GPIO и МОП-транзистора можно реализовать некоторые простые вещи.
Конфигурация выводов
Здесь показано, что используется каждый цифровой контакт ввода-вывода Mega2560. Конечно, при необходимости можно использовать в качестве цифровых и аналоговые контакты, но пока они остаются невостребованными. Разве что A0 используется для реализации рандомности в режиме генерации слов.
Не показаны же здесь все соединения питания и заземления между платами.
Укладка проводов
Или её отсутствие…
В качестве быстрого и простого способа всё прибрать (хотя бы немного) я прикрепил часть проводов к задней стенке строительным степлером. Из-за моей ошибки, вследствие которой разъёмы моторов не совпадали с разводкой плат, здесь получилось на 50% больше проводов, чем предполагалось изначально. Боль. Можно было, конечно, исправить косяк переделкой печатных плат…
Кроме того, отказ делать собственные провода и/или спаивать компоненты вынудил меня полагаться на стоковые перемычки. В общем, будь у меня больше терпения, всё могло получиться куда опрятнее.
Заметьте, что микроконтроллер я не стал крепить посередине, чтобы можно было в дальнейшем добавить двоеточие между часами и минутами, если захочется. Там же на правой стороне организованы все дополнительные функции и питание.
Подвешивание на стену
Я добавил по кругу небольшие панельки шириной около 4см в качестве импровизированного «корпуса», чтобы удобно разместить провода и прочее, а также повесить часы на стену. Кстати, повесил я их на крючках, закрепив верёвку узлами в краях верхней поперечной панели. Вес всей конструкции составил около 6кг — на гипсокартоне держится вполне уверенно.
Кнопки, приклеенные к нижней панели
Готово!
Освещение в комнате выключено
Потенциальные доработки
- Все фрезерные и сверлильные работы должны производиться на станке с ЧПУ. В ручном режиме сделать всё идеально ровно очень сложно.
- Хотелось бы придумать новое крепление ротора/движущей рукояти, которое бы позволило слегка изменять положение сегментов цифр вручную для более точного выравнивания.
- Я решил пока не добавлять двоеточие между часами и минутами, чтобы не громоздить лишнего — но его вполне можно туда вписать.
- Изначальное более внимательное отношение к укладке проводов могло бы сильно облегчить процесс.
- Основной кабель питания из эстетических соображений лучше бы разместить за стеной.
- ruvds_перевод
- mega2560
- настенные часы
- diy
- семисегментный настенный дисплей
- Блог компании RUVDS.com
- Производство и разработка электроники
- DIY или Сделай сам
- Электроника для начинающих
Вступление
Когда ЭЛТ-мониторы преобладали, в их пользу выдвигали следующий аргумент: несмотря на все усовершенствования, ЖК-дисплеи никогда не превзойдут по качеству изображения трубочные. Они, как и прежде, будут находить применение лишь там, где требуются энергоэффективность и малая толщина [1]. Прошли десятилетия, и теперь мы знаем, правы ли были сторонники этого аргумента. Но сегодня интересно взглянуть на ЖКИ того времени: действительно ли они настолько некачественные? Каково это — смотреть на CSTN-матрицу в 2019 году?
Слева TFT, справа CSTN, оба дисплея из девяностых
ЖКИ в прошлом веке
До перехода на TFT в портативных компьютерах находили применение самые разные дисплейные технологии. Поначалу применяли такие же ЭЛТ-мониторы, как в настольных компьютерах, только поменьше. Например, в Compaq Portable (1983), IBM 5155 (1984) или Commodore SX-64 (также 1984).
IBM 5155, автор: Soupmeister, лицензия: CC-BY-SA-2.0, отсюда
Таскать такой ПК с собой повсюду было тяжело, совсем другое дело — ноутбук с TN-ЖКИ (twist nematic), например, IBM 5140 (1986), Toshiba T1000 (1987). У этих дисплеев малы контрастность и угол обзора.
Toshiba T1100 с монохромным TN-дисплеем, автор: Johann H. Addicks, лицензия: GFDL, отсюда, ссылка битая, в оригинале тоже
Некоторые производители экспериментировали с газоразрядными матрицами, так увидели свет ноутбуки Toshiba T3200 (1987) и IBM PS/2 P70 (1991). Они обеспечивали высокую контрастность и несколько градаций яркости красно-оранжевого света, но стоили довольно дорого. Наконец, были разработаны STN-ЖКИ (supertwist nematic), как, например, в Электронике МС1504 и его прототипе Toshiba T1100. Контраст получался значительно лучше — от 1:5 до 1:50, а нескольких градаций яркости было достаточно для деловых применений (использовать ноутбук в быту было пока слишком дорого). Но что если пользователь хочет цветное изображение? На этот случай ему предложили две технологии: TFT и CSTN (color supertwist nematic). Первый ноутбук с TFT — NEC PC9801NC — был представлен в 1990 году, качество изображения для тех лет было выше всех похвал, но стоила «такая игрушка» значительно дороже других и так недешёвых портативных компьютеров. Ну а CSTN-дисплей — это просто STN-дисплей, на который наложен светофильтр. Довольно долго в ноутбуках применяли матрицы обоих типов. А в вагонах нью-йоркского метро CSTN-мониторы работают до сих пор.
Один из них, источник: Transit +PLUS
CSTroN
Автору захотелось посмотреть на CSTN-дисплей. Как? Для начала — просто купить старый ноутбук с ним и попользоваться. В нём оказался процессор AMD 5x86-P133. То есть, самое динамичное, что на нём можно запустить — это DOS-игры (да ладно, он и MPEG1 потянет в программе QV — переводчик). Конечно, играть в них здорово, но захотелось посмотреть, как на таком дисплее выглядит, к примеру, YouTube или современная игра — но это невозможно.
В общем, надо как-нибудь добавить к нему VGA- или HDMI-вход — и можно подавать сигнал с чего-нибудь современного. TFT-экраны от ноутбуков так переделывают в мониторы довольно часто. Просто покупают плату, подходящую к матрице — и готово. А можно сделать и свою приставку на ПЛИС, преобразующую VGA- или HDMI-сигнал в поток данных о пикселях.
Когда-то выпускались и платы для превращения в VGA-мониторы CSTN-матриц, но такую уже не найти. Но можно приспособить для этого отладочную плату на ПЛИС ML505.
Готовый результат. Довольно непривычно наблюдать такое на CSTN-дисплее: 16 ГБ ОЗУ.
Управление матрицей
Начнём с азов. Подобно любым матричным дисплеям, CSTN-дисплей имеет строки и стобцы. Вы светодиодной матрицей от микроконтроллера когда-нибудь управляли? Здесь то же самое, но напряжения — переменные. Нужно подать определённые сигналы как на выбранные, так и на невыбранные строки и столбцы — и пиксель на пересечении выбранных строки и столбца покажет то, что нужно. Форма сигналов получается весьма сложной, значение имеют и среднеквадратическое значение напряжения, и сдвиг фаз между напряжениями на строке и столбце, и смещение… И вот так, пиксель за пикселем, формируется изображение.
К счастью, от ПЛИС не требуется вырабатывать все эти сигналы, да ещё и на таком огромном количестве линий. Всё это проделывает модуль, встроенный в дисплей. Там импульсный преобразователь повышает постоянное напряжение, оно проходит через делитель и повторитель, так получается напряжение смещения. Драйверы строк и столбцов превращают это напряжение в переменное необходимой формы. Всё, что требуется — подать в дисплейный модуль поток данных о состоянии пикселей.
На TFT-ЖКИ с интерфейсом DPI (digital parallel interface) за один такт поступают сразу все данные об одном пикселе. На линии строчной и кадровой синхронизации поступают импульсы после каждых, соответственно, строки и кадра. Пиксели просто непрерывно передаются строка за строкой, кадр за кадром. Если передача полного кадра занимает 1/60 с, значит, частота обновления составляет 60 Гц. Разрядность шины данных равна глубине цвета в битах, обычно 16 (5 бит на красный и синий, 6 на зелёный), 18 (по 6 бит на каждый из цветов), or 24 (по 8 бит на каждый из цветов). LVDS — это то же самое, только биты передаются не параллельно, а последовательно по дифференциальным парам, ну а в MIPI DSI они ещё и объединяются в пакеты. Шина SPI/i80 позволяет передавать контроллеру различные команды, а тот, выполняя их, формирует сигналы для DPI или аналогичного интерфейса. Который, в свою очередь, чем-то напоминает VGA, только данные о яркости каждого из цветов поступают не в аналоговом, а в цифровом виде. Существуют преобразователи VGA в DPI и обратно. Очень удобны платы, позволяющие получать VGA-сигнал от Raspberry Pi, хотя изначально этот компьютер вырабатывает только HDMI и композитное видео.
На дисплейный модуль CSTN-матрицы надо подавать сигналы, очень похожие на подаваемые на TFT-матрицу с интерфейсом DPI. В даташите на SX21V001 [2] показано, как управлять CSTN-дисплеем с разрешением в 640х480:
Тут изображена передача целого кадра. На линию CL1 сигнал поступает после каждой строки, на FLM — после каждого кадра. А ещё там шина данных из 16 линий. Вообще-то, на этом рисунке допущена ошибка: во время передачи первой и второй строк по линиям UD0-UD7 поступают данные Y1 и Y2, а не X1 и X2, а по LD0-LD8 — соответственно, Y241 и Y242. Здесь U и L — это, соответственно, upper и lower, то есть, дисплей состоит из двух матриц разрешением в 640х240, расположенных одна над другой. Вот он, загадочный «dual scan» из старой рекламы ноутбуков, от которого происходит горизонтальная полоса через весь экран. У STN- и CSTN-дисплеев контрастность обратно пропорциональна числу строк, поэтому такое разделение позволяет её увеличить. Но это не единственное, чем они отличаются по способу управления от TFT.
Непонятно, почему горизонтальную ось здесь назвали Y… Но в любом случае, CL2 здесь — линия для подачи тактовых импульсов, переключающих пиксели. Но по шинам UD и LD за один такт передаются не данные об одном многобитном пикселе, как в TFT, а данные сразу о нескольких пикселях по три бита на каждый. Один бит на цвет, три бита на пиксель — всего восемь цветов.
Но как же так? Понятно, что у CSTN-дисплеев количество цветов мало, например, 4096 или 32768, но ведь не 8 же. Оказывается, здесь применяется ШИМ. Светодиодами же так управляют, значит, и пикселями ЖКИ можно. Нужна, например, яркость в 50% — включаем пиксель в чётных кадрах и выключаем в нечётных. Этот способ называют FRC (frame rate control), ну а ШИМом в данном контексте называют управление яркостью пикселей тем же способом, но в пределах не двух или более кадров, а одного. FRC осуществляет внешнее устройство, а ШИМ — микросхемы дисплейного модуля, если там есть поддержка этой функции. Автору неизвестны CSTN-дисплеи с ШИМ, но он предполагает, что таковы матрицы HPA-типа. В любом случае, раз ШИМ недоступен, необходимую глубину цвета можно получить с помощью FRC.
Ценой этого будет мерцание, поэтому в CSTN-дисплеях бывают чудовищные (по сравнению с TFT) частоты кадров. Например, в этом модуле изначально было 120 Гц, а автор разогнал его до 240.
Как это было реализовано
Перед разработчиком возникло сразу несколько трудностей:
— входной сигнал имеет частоту кадров в 60 Гц, её надо удваивать или даже учетверять
— во входном сигнале кадр не делится на верхнюю и нижнюю половины по 640х240 пикселей каждая, а здесь надо разделить
— а ещё нужно реализовать FRC, иначе глубина цвета будет 3 бита на пиксель
Первые два пункта означают, что необходим фреймбуфер, и не простой, а двухпортовый. Ну а третья задача решается при помощи GLDP LUT (grayscale-level display pattern lookup table) [3]. У таблицы поиска два вида входных данных: цвет, который надо отобразить, и состояние счётчика кадров. И один вид выходных данных: те три бита, которые надо подать на субпиксели того или иного пикселя в данный момент. Значит, потребуются следующие узлы:
Первым делом надо заполнить весь экран каким-нибудь цветом. На этой стадии необязательно знать, где находится какой пиксель, достаточно убедиться, что дисплейный модуль подаёт на матрицу сигналы необходимой формы. Код для заливки в ПЛИС — здесь.
Теперь попробуем что-нибудь вывести, и с неполной яркостью в том числе. Нужны такие таблицы поиска для FRC, чтобы минимизировать мерцание. Автор придумал две таблицы, применяемые к пикселям в шахматном порядке. Поэтому каждые два соседних пикселя мерцают несинхронно. Код — здесь.
Итак, показывать изображение мы уже плату «научили», следующее, что потребуется — фреймбуфер. При 640х480 и 5 битах на каждый из цветов его объём составит около 600 килобайт. Немного, но в ПЛИС столько нет. Хорошо, на плате есть ОЗУ типа DDR2 и Xilinx MIG для управления им. Реализованы два FIFO, один на чтение, другой на запись. Арбитр решает, будет ли следующий обмен данными с DDR2 чтением или записью. Буферов два, запись идёт в один, чтение из другого, а при смене кадров они меняются местами. Код арбитра — здесь.
Осталось реализовать видеозахват, в одном из предыдущих проектов автора уже есть похожая наработка, после доработки код преобразователя из VGA в DPI стал таким.
И что же получилось?
Для автора это третий проект на ПЛИС, было интересно поработать с Xilinx MIG и DDR2, а также с несложным конвейером. Запланирован более качественный FRC с дельта-сигма-модуляцией, а также опыты с более поздними CSTN-панелями, использующими технологию HPA (High Performance Addressing) фирмы Sharp.
Спасибо за внимание!
Источники
1. Li, W., & Guo, Q. (2000). Liquid Crystal Display Application Technology. Beijing: Electrical Industry Press.
2. HITACHI (1999). SX21V001-Z4 Customer’s Acceptance Specifications.
3. Hsueh, Y., & Lee, J. (2008). Image improvement method for LCD frame rate controller. 2008 IEEE International Symposium on Consumer Electronics. doi:10.1109/isce.2008.4559534
- FPGA
- Производство и разработка электроники
- Старое железо
- Мониторы и ТВ
- DIY или Сделай сам
Как сделать жк дисплей
Добрый день!
Вопрос собственно прост: как сделать Ж/К дисплей своими (ну или не совсем) руками? Реально ли это вообще?Ситуация такова: хочу на перегородке в комнате сделать затемняющийся экран, с дисплеем часов. Смысл в том, чтобы на стекле были все время включены часы, а при необходимости весь "экран" (стекло) становилось темным, ну при нажатии на кнопочку так скажем. =)
В принципе были найдены эл.часы, с них стырен "циферблат" часов подходяжего размера и успешно смонтирован, осталось сделать только затемняющий экран.
Прошу ответить чисто технически, как сделать такой "темнеющий" экран.
02.01.2011, 10:54 Helpmaster Регистрация: 08.03.2016
Сообщений: 0
Регистрация: 11.06.2009
Сообщений: 2,426
Записей в дневнике: 3
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 6234В таких экранах два стекла. между ними спец. жидкие кристалы, за стеклом как правило светоотражающая пленка с люминофором (или подсветка). При прохождении тока через эти кристалы, они перестают пропускать свет и мы видим темные цыфры, или инверсия - на темном фоне прозрачные цыфры. я думаю самому врятли получится сделать.
Регистрация: 03.11.2009
Сообщений: 749
Записей в дневнике: 7
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 394
Вроде бы автору нужно электрохромное стекло.
Debes, ergo potes
Регистрация: 09.05.2009
Сообщений: 9,653
Сказал(а) спасибо: 0
Поблагодарили 17 раз(а) в 4 сообщениях
Репутация: 6630
А не проще ли стекло затонировать, а индикацию в часах отключать?
Регистрация: 11.04.2007
Адрес: Санкт-Петербург
Сообщений: 40,320
Записей в дневнике: 73
Сказал(а) спасибо: 885
Поблагодарили 2,792 раз(а) в 431 сообщениях
Репутация: 186775Теоретически сделать такой экран возможно, вот только будут сложности с нанесением прозрачных проводников на стекло.
Принцип работы такого индикатора достаточно прост.Индикатор состоит из некого подобия бутерброда из двух стекол с токопроводящим покрытием, жидких кристаллов между ними и двух поляризующих плёнок. Ориентация осей поляризации плёнок совпадает и по этому экран прозрачен, при подаче напряжения на жидкие кристаллы они поляризуют свет по перпендикулярной оси относительно плёночных фильтров и мы видим затемнённый участок. Самый простой пример жидких кристаллов - холестерин.


























































