Подключение графического жк-дисплея 128х64 ks0108 к at89c52

Подключение графического ЖК-дисплея 128х64 KS0108 к AT89C52

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

Если вам нужно отображать информацию в графическом стиле, то графические ЖК-дисплеи будут лучшими по сравнению с символьными. Эта статья описывает основы работы с графическим ЖК-дисплеем с разрешением 128×64 и контроллером KS0108.

Для работы с дисплеем есть два регистра входной и выходной. Они выбираются комбинациями сигналов на выводах RS и RW, которые находятся в таблице 1.

Входной регистр используется для записи команд и данных в ЖК-дисплей. Он содержит данные и инструкции перед записью в DDRAM (Data Display RAM). Когда ЖК-дисплей находится в активном режиме (CS1 и CS2 имеют высокий логический уровень), входной регистр может быть выбран путем посылки битов на RS и RW выводы, как показано в таблице. Данные входного регистра записываются по заднему фронту ЕN (Enable) сигнала и автоматически записываются в DDRAM.

Выходной регистр используется для чтения данных из DDRAM. Когда ЖК-дисплей находится в активном режиме (CS1 и CS2 имеют высокий логический уровень), выходной регистр может быть выбран путем посылки битов на RS и RW, как показано в таблице. Если на R/W и RS высокий логический уровень, данные записываются в выходной регистр. Если же на R/W высокий логический уровень, а на RS низкий логический уровень данные можно считывать.

Табл.1 Комбинации сигналов RS и RW

Основные действия для работы с графическим ЖК-дисплеем:
1. Инициализация ЖК-дисплея
2. Выбор страницы
3. Выбор столбца
4. Вывод данных

Перед выводом данных на ЖК-дисплей, он должен быть инициализирован, т.е. дисплей должен быть поставлен на нужный столбец и страницу, куда нужно вывести данные. Это можно сделать следующими действиями:

а) Задать значение регистра данных

При D = 1 данные отображаются, при D = 0 нет. Если дисплей выключен, то ничего происходить не будет.

б) CS1 = 1, CS2 = 1 активация обеих половин дисплея.

в) RS = 0, R / W = 0 (для выбора режима передачи команд)

е) EN = 0 (для записи данных во входной регистр)

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

2. Выбор страницы

Прежде чем выводить какие либо данные, должна быть выбрана страница ЖК-дисплея. Страница, может быть выбрана по следующей последовательности действий:

а) Задать значение регистра данных

Всего есть 8 страниц (0-7), конкретная страница выбирается установкой битов X1-X3.

б) CS1 = 1, CS2 = 1 (для активации обеих половин дисплея)

в) RS = 0, R / W = 0 (выбор режима команд)

е) EN = 0 (для записи данных во входной регистр )

Например, если X3 = 0, X2 = 1 и X1 = 0, то выбирается вторая страница.Чтение или запись выполняются на этой странице, пока не будет выбрана следующая страница​​. В зависимости от выбора столбца, страница выбирается или из левой или из правой половины ЖК-дисплея.

3. Выбор столбцов

В данном ЖК-дисплее 128 столбцов, которые увеличиваются автоматически при каждом цикле записи. Это означает, что выбрав столбец и записав в него данные, в следующем цикле записи номер столбца будет увеличен на 1. Данные легче писать по столбцам. Столбец может быть выбран следующими инструкциями:

а) Задать значение регистра данных

Соответствующий контроллер (CS1 или CS2) выбирается в зависимости от номера столбца, как показано ниже.

б) RS = 0, R / W = 0 (выбор режима команд)

д) EN = 0 (для записи данных во входной регистр)

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

4. Отображение данных

После выбора страницы и столбца можно отправлять данные для отображения на ЖК-дисплее. Отображение данных может быть осуществлено по следующим инструкциям:

а) Задать значение регистра данных. С каждым циклом записи, данные записываются в один столбец, а затем номер столбца увеличивается на единицу. Старший бит данных (DBx = 1) соответствует зажженному пикселю, а младший бит данных (DBx = 0) соответствует погашенному пикселю. MSB соответствует 8-м ряду в столбце, а LSB первом ряду столбца.

б) Если номер столбца Следующие шаги могут быть использованы для эффективного программирования:

1. При отправке данных для записи из массива, нужно указать размерность массива. Это будет указывать, сколько нужно заполнить столбцов. Если размерность будет составлять 8, то восемь столбов будут заполнены, если 7, то семь столбцов будет заполнено.

2. Условие ‘if (column >127) ‘ может быть использовано, чтобы вернуться к основной функции, если количество столбцов дисплея превышено.

3. Функция установки столбца должна быть вызвана еще раз, если значение номера столбца не соответствует левой или правой половине ЖК-дисплея.

4. Для проверки условий 2 и 3 нужно ввести переменную, которая будет хранить номер столбца.

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

Подключение графического индикатора (KS0108) к PIC микроконтроллеру. Часть 1 — Теория

Использование графического индикатора кардинально меняет внешний вид вашего проекта. Он предоставляет больше свободы при отображении данных, чем символьный ЖК индикатор на базе контроллера HD44780. В статье мы рассмотрим как подключить графический индикатор на контроллере KS0108 (или совместимом) к микроконтроллеру PIC производства компании Microchip. Статья разделена на несколько частей, в которых мы последовательно рассмотрим аппаратную и программную части проекта.

Выбор микроконтроллера PIC16F887 связан с тем, что приложения с графическим ЖКИ требуют достаточно много ресурсов микроконтроллера (линии ввода/вывода, встроенная память) и данный микроконтроллер имеет 36 линий ввода/вывода и 14 КБайт Flash-памяти.

Графический ЖКИ, который используется в нашем проекте – это модуль WDG0151-TMI монохромного индикатора производства компании Winstar с разрешением 128×64 точки. Он выполнен на базе двух контроллеров NT7108C и NT7107C, которые совместимы с контроллерами Samsung KS0108B и KS0107B.

KS0108B – это 64 канальный точечный драйвер ЖК сегментов. Модуль WDG0151-TMI содержит два таких контроллера, чтобы обеспечить управление 128 сегментами. С другой стороны контроллер KS0107B (NT7107C) – это 64 канальный драйвер общих линий индикатора, который генерирует временные сигналы для управления двумя сегментными драйверами. Это очень распространенные и хорошо зарекомендовавшие себя контроллеры, которые применяются и в индикаторах других производителей.

Блок-схема модуля Winstar WDG0151-TMI

Контроллер NT7107C управляет 64 общими линиями дисплея (COM1 – COM64). Первый контроллер NT7108C управляет левой половиной сегментов (SEG1 – SEG64) дисплея, второй NT7108C – правой половиной сегментов (SEG65 – SEG128). Доступ к двум половинам дисплея осуществляется индивидуально посредством сигнальных линий Chip Select (CS1, CS2). Каждая половина дисплея представлена 7 горизонтальными страницами памяти, каждая высотой 8 бит (1 Байт).

Начиная с 0 страницы в левoй половине (/CS1=0), если вы передадите 1 байт данных, они будут отображены в первом столбце страницы 0. Если повторить данный процесс 64 раза и затем переключиться на вторую половину дисплея и повторить операции, пока не будет достигнута 128 позиция, мы получим отображение первых 8 линий на дисплее. Для отображения следующих 8 линий необходимо повторить эти операции, но сменив адрес страницы памяти. Общее количество байт, необходимое для отображения одного кадра (128×64 точки), в нашем случае равно 2×64×8 = 1024.

Модуль дисплея Winstar WDG0151-TMI GLCD имеет встроенный генератор отрицательного напряжения для управления контрастностью. Потенциометр регулировки контрастности (обычно 10 кОм) подключается между выводами VEE и VCC. Расположение линий ввода/вывода индикатора не стандартизировано, поэтому необходимо обратиться к технической документации на дисплей при подключении его к микроконтроллеру.

В общем случае количество выводов у графического индикатора 20. Первые два вывода – выбор контроллера левой или правой части индикатора, активный уровень – низкий, однако существуют индикаторы с высоким активным уровнем (поэтому и понадобится еще раз техническое описание используемого индикатора от производителя). С помощью вывода 6 индикатора D/I (Data/Instruction) пользователь указывает, что поступает на шину данных индикатора: данные или команды (инструкции). Управляющие сигналы R/W и E имеют такое же назначение, как и в символьных индикаторах на контроллере HD44780.

Назначение выводов модуля ЖКИ WDG0151-TMI

  • Все
  • Тематические

    Когда-то товарищ burjui рассказал нам как работать с знакосинтезирующим lcd экраном, а также обучил его русской речи и даже основам графики – нарисовал несколько значков. Вот только примитивные значки это максимум, что можно получить от символьных дисплеев — и то с некоторым трудом, без проблем только буковки-циферки, строчные-заглавные. А хочется картинок. Размеров, шрифтов разных, курсивов, там, менюшек модных.
    Для этого придумали графические дисплеи.
    Они, как и символьные, формируют изображение зажигая/гася точки-пиксели.
    Кстати, как-то мы обошли вниманием в прошлый раз тот факт, что работать с точечками напрямую было бы очень уныло — никаких выводов не напасёшься (80х16 точек у символьного и 128х64 у графического). Но добрые китайские духи электроники позаботились о нас и снабдили эти девайсы собственными контроллерами. Для символьных экранов стандартный контроллер HD44780 (ks0066) а для графических — ks0107 (ks0108).
    В случае WG12864B их там целых два — на на правую и левую часть экрана. Это потому что ks0108 может обеспечить вывод только на 64х64точки, вот и получился двухядерный дисплей=)

    Общаться с контроллерами дисплея предстоит по:

    DB0-DB7 — шине данных
    R/W — указывая, передаём — 0 (или читаем — 1)
    D/I — данные — 1 (или команду — 0)
    CS1, CS2 — какому контроллеру
    E – и проталкивая каждое действие синхроимпульсом
    Также есть:
    RST — сброс(резет)
    Vdd — питание 5В
    GND — земля
    Vo — контраст
    Vee — источник отрицательного напряжения для контраста(если экран инверсный)
    A — анод и
    K — катод светодиода подсветки

    Поиграемся с WG12864B-TML , вот его распиновка:

    Итого минимум 13 линий дуины предстоит принести в жертву красоте индикации=
    Подключается дисплей довольно просто (если, конечно, не считать количества проводков=) Как и в случае с символьным экраном кроме линий связи с мк понадобятся потенциометр регулировки контраста (обратите внимание на оригинальное подключение)
    и токоограничительный резистор для подсветки.
    Хотя некоторые его не ставят.
    Напрасно, кстати — падение на светодиодах подсветки, как гласит датащит , не более 4.6 вольт, и впихивая туда все 5, рискуем их пожечь безвозвратно.
    В ИДЕ-шку не включена библиотека для работы с графическими дисплеями, а на плейграунде лежит старая версия, поэтому берём отсюда , или у нас .
    Подключаем согласно описанию (GLCD_Documentation.pdf лежит в папке glcddoc, можно взять здесь или почитать перевод ), наш дисплей — “Panel A”(в доке ошибка, см далее, юзайте эту схему, она правильная)

    Удивляясь столь извращённому методу разбрасывания проводов по дуине, читаем чуть внимательней и узнаём, что совсем не обязательно именно так плести этот клубок

    можно поменять расположение линий поправив glcdconfigks0108_Arduino.h. То есть можем расположить эти 13 выводов в произвольном порядке, оставляя свободными именно те пины (… все 7, ни в чём себе не отказывайте, ага=), которые понадобятся нам для подключения всего остального.
    Но мы так делать не будем, а просто побыстрей закинем в arduino-xxxhardwarelibraries папку glcd из скачанного архива. Запустим ИДЕ-шку и выбрав File->Exampes->glcd>ks0108example, трясущимися руками зальём всё это дело в плату. Залилось, включилось, крутим контраст… и что-то фигово видно=

    Меряем питание и узнаём что наш экран ужасно прожорлив=) Просело аж до 4.2 В.
    Подключаем внешнее питание.

    Чтозаужоснах!
    Экран перепутался пополам= Тут самое время вспомнить, что у нас именно два контроллера и запись в них осуществляется по очереди, посредством выбора одного из них еденичкой на линии CS1 или CS2. Они-то у нас и перепутались… как-то, а точнее положение их не соответствует, предложенной автором распиновке=
    Меняем местами.

    Так гораздо лучше=)
    Симпатично, можно позаливать ещё примеры. Там есть «игра» жизнь, с ужасной скоростью прокручиваемые шрифты и бегущие таймеры, всем своим видом показывающие не высокую скорость обновления данного дисплея=) Часы мне так и не удалось скомпилировать — ИДЕ-шка непрерывно ругается на отсутствие библиотек (а при их добавлении сыплет другими ошибками). Особого внимания стоит игра Rocket, добавив потенциометр и бузер можно немного по ностальгировать=)

    Но пора уже слепить что-нибудь своё, пусть и не столь впечатляющее.
    Для этого придётся почитать объёмистое описание этой убербиблиотеки .
    А для более полного краштеста сделаем свой рисунок и свой шрифт=)

    Шрифты генерятся утилиткой GLCDFontCreator2, качать здесь , или у нас .
    Запускается жмаканьем на start.bat, вот такой френдли интерфейс.

    Кнопки Open Font/Save Font — это для внутреннего, понятного только для GLCDFontCreator2, формата шрифтов(рабочие файлы), открывать сами шрифты прога не умеет — ни сконвертированные ею самою в .h ни .ttf=(
    Так что жмём NewFont, и уже там импортируем какой-нибудь шрифт из уже установленных у вас в системе.

    Стоит сразу как-нибудь осмысленно обозвать своё творение, т.к. именно под этим именем (newFont у меня=) он, впоследствии, будет доступен нашему скетчу.
    Можно что-нибудь подрисовать.

    Давим кнопку Export, указывая желаемое имя файла и расположение (да и не забудьте к имени файла дописать «.h», программа не считает, что это нужно=)
    Всё это круто, за исключением одной мелочи — русских букв программа не знает=(
    Если указать диапазон символов помимо стандартного (Start Index и Char Count), то на месте родной кириллицы открытого шрифта видны только пустые шедевры Малевича.
    Можно попробовать вместо них намалевать чего-нибудь, но мне жутко лень=)
    К тому же товарищ SkyFort уже провёл соответствующие исследования и работы. Правда он пошёл несколько иным путём — не через GLCDFontCreator2 а используя KS0108v 4.0 For PIC (если с narod.ru что-то случится то файл можно взять у нас ).
    В результате у него получился шрифт SystemRus5x7.h его то я и использую=)

    Так, накреативили шрифты, теперь займёмся картинками.

    Для этого нам прям в архив с библиотекой засунули папку bitmaps, которая хорошо видна в виде тестового скетча из примеров glcd в Arduino IDE, но почему-то не компилится=)))
    А всё дело в том, что там лежит скетч для Processig-а, и даже готовый к запуску файлик glcd/bitmaps/utils/java/glcdMakeBitmap.jar
    Программа ещё более юзерфрендли и поддерживает втаскивание в своё окно картинок в нескольких форматах.

    Правда на этом её дружелюбность заканчивается — пихать туда надо уже чёрно-белую картинку нужного размера, приведения размеров и цветов программа не производит.
    Если картинка смогла прожеваться то в окошке нам об этом сообщат, и даже покажут что получилось, а в папке glcd/bitmaps появится файл «имя_втащеного_файла.h»

    Теперь нарисуем простенький скетч для проверки всего этого безобразия в действии.
    Шрифты и картинки в скетч включаются также как и библиотеки, и жрут немало места(особенно крупные шрифты)Например этот скетч влезет только(как минимум) в плату на базе Atmega328 .
    Скетч, шрифты и картинки одним архивом .

    Видео того, что получилось:

    Осталось разобраться с менюшками и прикрутить экран к сдвиговым регистрам для экономии ног.
    Но это уже совсем другая история=)

    Подробности про всю сигнально — битовую светотень творящуюся на линии связи МК и экрана почитать можно у ДиХальта , как обычно, всё разжёвано подробно и толково.
    Перевод описания библиотеки GLCD.
    Также, пока я собирался выложить эти статьи товарищ SinauRus перевёл мануал а SkyFort заставил wg1286 говорить по-русски=)

    Подключение графического жк-дисплея 128х64 ks0108 к at89c52

    Подключение графического LCD дисплея KS0108(WG12864B1) к LPT порту.
    Автор: MasterNeo
    01.02.2009 06:00

    Что-то давно я статей не писал: Ну пожалуй начнем. Сегодня на операционном столе у нас дисплей фирмы Wincom Tech с расширением 128*64 точки на базе контроллера KS0108(WG12864B1). Его мне любезно предоставил админ данного портала Roman , за что ему большое спасибо. Сейчас мы этот дисплей подключим к компьютеру по LPT.

    Начнем

    И так, вот что нам понадобиться:

    Переменные резисторы на 10К и 100 Ом

    постоянный резистор на 6ть Ом

    1. Для подключения принтера к lpt
    2. для подключения принтера к usb (usb A to usb B)

    С расходников и инструментов нам понадобятся:

    1. Паяльник и паяльные принадлежности
    2. Монтажный провод
    3. Кусачки (аКа Бокорезы)
    4. Отвертка
    5. Провод монтажный (любой, желательно тонкий, просто его будет удобнее паять)
    6. Мультиметр
    7. Подставка-держатель (не обязательно, но очень удобно).

    Хардваре

    И так принципиальная схема и расспиновка нашего дисплея:

    PIN NO. Symbol Level Function
    1 CS1 H Chip Selection Signal for IC1
    2 CS2 H Chip Selection Signal IC2
    3 Vss 0V Ground
    4 VDD 5.0V Power supply for logic circuit
    5 V0 Contrast adjust
    6 RS H/L Register select signal
    7 R/W H/L H : Data Read(LCD to MPU) L : Data Write(MPU to LCM)
    8 E H/L Enable signal
    9 DB0 H/L Data Bus Line
    10 DB1 H/L Data Bus Line
    11 DB2 H/L Data Bus Line
    12 DB3 H/L Data Bus Line
    13 DB4 H/L Data Bus Line
    14 DB5 H/L Data Bus Line
    15 DB6 H/L Data Bus Line
    16 DB7 H/L Data Bus Line
    17 RST H/L Reset (Active » Low»)
    18 Vout -10V Output for LCD driver circuit
    19 A (+) Power supply for BL LED(+5.0v)
    20 K (-) Power supply for BL LED(-)

    Берем наш принтерный лпт-провод и разбираем крышку. Они легко снимаются с помощью отвертки , достаточно отогнуть 4 защелки по 2 с каждой стороны.

    Оставляем только разъем который идет в компьютер, другой отрезаем, он нам не нужен.

    Займемся вторым коннектором.

    Отрезаем все ненужные провода (не забудьте оставить один провод для питания) У вас должно остаться 15 проводов. Вот что должно у вас получиться

    Теперь берем второй кабель (USB) и отрезаем кусок кабеля вместе с разъемом usb A (плоский) такой длинны что бы он дотянулся от Лпт до свободного порта USB.

    Зачищаем и видим 4 провода

    Нас интересует только питание, скорей всего это красный и черный провод, на всякий случай советую прозвонить. Мы нашли Питание, теперь припаиваем землю к земле на нашем разъеме DB-25 (lpt) а Положительный контакт (5v) к проводу который мы оставили и изолируем его термоусадочной трубкой или изолентой

    Следующим шагом припаиваем вот эту кучу проводов к дисплею (следите за расспиновкой)

    Должно получиться нечто похожее

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

    И вот так это выглядит (Ах да куда ж в нашем деле без чая)

    Теперь собираем Разъемы воедино.

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

    Это Хорошо , значит все собрано правильно на 35-40 процентов. Если дисплей не загорелся или нету точек, то покрутите резисторы:

    Так с Хардваре все: Едем дальше!

    SoftWare

    Теперь настроем программную реализацию

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

    Установка драйверов.

    После того как вы скачали архив DLPortIO и распаковали его, переходите в каталог install и запустите файл Install.exe . После завершения инсталляции перезагрузите компьютер.

    Непосредственно lcdmonitor

    Программа уже установлена и ее достаточно просто распаковать. После чего запускаем файл LCDMonitor3

    Переходим в Опции Модули и включаем модуль KS0108

    Теперь нажимаем свойства , выбираем адрес порта и время задержки

    Во время процесса должно появляться нечто подобное

    Теперь точно так же как мы включили Модуль KS0108 включаем остальные, ну например:

    Нажимаем Галочку вверху окна: Видим теперь справа появились выбранные модули. Нажимаем на поле посреди окна , оно должно стать зеленым, а потом кликаем на модуль 2 раза для открытия его структуры. В модуле 4-х строчные часы видим четыре строчки. Кликаем 2 раза на первую и нажимаем Ок! После чего выбираем следующие поле, выделяем его что бы стало зеленым и кликаем на 2-ю строчку часов 2 раза и снова нажимаем Ок! Думаю суть ясна.

    В поле посредине экрана можно писать не только Модули а и просто текст.

    Теперь все готово. Нажимаем предварительный просмотр и на дисплеи появляется:

    Все работает? Тогда нажмем на Стрелочку вверху окна и программа свернется, а дисплей начнет отображать информацию.

    Теперь осталось только выбрать корпус для дисплея. Но поскольку как известно на вкус и цвет все фломастеры разные, то оставлю этот этап для вас. Могу лишь посоветовать: если вы будете встраивать его в корпус компьютера, например в 5.25 панель, то питание можно взять с Molexа

    Достаточно подключить черный и красный провод вместо юсб:

    P.S. Так же мне понравилась программа LcdStudio совету попробовать и ее.Скачать можно здесь

    На этом Все. С вами был MasterNeo.

    Подключение графического жк-дисплея 128х64 ks0108 к at89c52

    _________________
    Мечтатель — не тот, кто сидит на диване и думает о несбыточном, а тот, кто всеми силами стремится воплотить несбыточное в реальность.

    У меня точно такой же дисплей недавно появился.
    С подсветкой там очень здорово сделано — вся обвязка у них уже собрана на плате, потому она управляется чисто логикой.
    Управляется так: 19-ю ножку сажаешь на +5 и забываешь. 20, 21 и 22 пины — это R, G и B. Подаёшь на ножку 0 и подсветка зажигается. Например, для жёлтого цвета подаешь на 19 +5; на 20 и 21 — 0; 22 — NC или +5.
    Ну или можно наоборот управлять, хозяин — барин)
    Пины 1-18 должны быть как в даташите.

    Только работать я его пока не заставил((
    Кто-нибудь пробовал его согласовывать с 3.3-вольтовой логикой?
    Я уже дошёл то такого изврата (см. вложение), но он молчит.
    Да, знаю, что есть специальные микросхемы, но у меня вся кухня на белой макетке, а они все smd.
    Вроде ещё есть схема с диодом и резитором на каждую ногу, но я так ничего не понял.

    Да, кстати, ещё один вопрос: в даташите на сайте Winstar указано, что высокий уровень — это 0, а низкий — это +5, однако в этой статье логические уровни используются стандартные и всё там работает. Кому верить?)

    JLCPCB, всего $2 за прототип печатной платы! Цвет — любой!

    Зарегистрируйтесь и получите два купона по 5$ каждый:https://jlcpcb.com/cwc

    Уважаемый lexmulya подскажите как мне вывести графику(выделено цветом), как не пробовал рисует 8 полос, по полосе на страницу! WG12864A .

    register unsigned char i;

    void WriteCom(byte Com, byte CS)
    <
    SetBit(LCD_COM,CS);
    ClrBit(LCD_COM,LCD_RS);
    ClrBit(LCD_COM,LCD_RW);
    #asm;
    nop
    nop
    nop
    #endasm;
    LCD_DB=Com;
    SetBit(LCD_COM,LCD_E);
    #asm;
    nop
    nop
    nop
    #endasm;
    ClrBit(LCD_COM,LCD_E);
    delay_ms(1);
    ClrBit(LCD_COM,(LCD_CS1+LCD_CS2));
    SetBit(LCD_COM,LCD_E);
    delay_ms(1);
    >

    void WriteData(byte data, byte CS)
    <
    SetBit(LCD_COM,CS);
    SetBit(LCD_COM,LCD_RS);
    ClrBit(LCD_COM,LCD_RW);
    #asm;
    nop
    nop
    nop
    #endasm;
    LCD_DB=data;
    SetBit(LCD_COM,LCD_E);
    #asm;
    nop
    nop
    nop
    #endasm;
    ClrBit(LCD_COM,LCD_E);
    delay_ms(1);
    ClrBit(LCD_COM,(LCD_CS1+LCD_CS2));
    SetBit(LCD_COM,LCD_E);
    delay_ms(1);
    >

    /*Координаты LCD*/
    void WriteXY(byte x,byte y, byte CS)
    <
    WriteCom(0xb8+y,CS);
    WriteCom(0x40+x,CS);
    >
    void wpixXY(byte x, byte y, byte CS)
    <

    WriteCom(0xb8 | y,CS);
    WriteCom(0x40 | x,CS);

    >
    /*Иницилизация LCD*/
    void init_lcd(void)
    <
    WriteXY(0,0,(LCD_CS1+LCD_CS2));
    WriteCom(0xb8,(LCD_CS1+LCD_CS2));
    WriteCom(0x40,(LCD_CS1+LCD_CS2));
    WriteCom(0xc0,(LCD_CS1+LCD_CS2));
    WriteCom(0x3f,(LCD_CS1+LCD_CS2));
    >
    /*Очистить LCD*/
    void clear(void)
    <
    unsigned char x,y;
    for(x = 0;x /*Функция которая ресует на экране 1 пиксел*/
    void LCD_PUT_PIXEL(byte x, byte y) <
    //Обьявляем переменные
    byte bite;
    byte page;
    byte data, data2;
    //Выход если точка лежит вне экрана
    if((x>127)|(y>63)) return;
    //Выбираем кристалл
    if(x>=64) <
    ClrBit(LCD_COM, LCD_CS1);
    SetBit(LCD_COM, LCD_CS2);
    x=x-64;
    page = 0b00010000;
    >
    else <
    ClrBit(LCD_COM, LCD_CS2);
    SetBit(LCD_COM, LCD_CS1);
    page = 0b00100000;
    >
    y/8;
    x%8;
    wpixXY(x, y, page);

    >
    /*Функция вывода прямой по алгоритму Брезенхома.
    Подробно ее описывать не буду т.к. по ней лучше почитать в интернете*/
    void LCD_LINE(byte x1, byte y1, byte x2, byte y2) <
    int dx,
    .
    .
    .
    и так рисуем линию:

    void prog(void)
    <
    byte korX = 0;
    byte korY = 0;
    clear();
    while(1)
    <
    if(PINA.7 == 0)<
    if(korX == 127)else
    if(korY == 63)
    //delay_ms(100);
    //clearz();
    LCD_PUT_PIXEL(korX, korY);
    //
    //LCD_CIRCLE(63, 63, 63);

    Сборка печатных плат от $30 + БЕСПЛАТНАЯ доставка по всему миру + трафарет

    Графическая библиотека для МК на С++. Драйвер KS0108.

    Продолжая работать над своей библиотекой для микроконтроллеров, я начал реализовывать графическую подсистему. Для начала дисплей был выбран на популярном контроллере KS0108 — в первую очередь по тому, что он относительно стандартный, доступный и многим хорошо знаком. В сети довольно много материала по работе с этим контроллером, много и готовых библиотек, но почему-то почти везде вывод текста и картинок должен быть выровнен по границам страниц дисплея. Это не удобно. Так-же большинство готовых библиотек реализуют рисование прямых и окружностей с толщиной линии только в один пиксель.

    Итак, реалированные фичи:

    1. Дисплей можно подключать на любые свободные ноги МК;
    2. Независимомть от целевой платформы;
    3. Возможность отладки на ПК;
    4. Высокоуровневый код для рисования не зависит от дисплея;
    5. Минимальные требования к RAM, ROM и F_CPU;
    6. Картинки могут храниться как по строкам, так и по столбцам;
    7. Поддержка нескольких шрифтов;
    8. Поддержка юникода.
    9. Рисование линий заданной толщины;
    10. Шрифты и картинки могут быть любого доступного размера.

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

    Здесь Cs1, Cs2, Reset, Rw, Di, E — отдельные пины, DataBus — целый восьми-битный порт или список из восьми произвольных пинов (PinList). Способ подключения дисплея можно определить так:

    Входы Cs1 и Cs2 имеют низкий активный уровень на моём дисплее поэтому используются инвртированные пины Pc0Inv и Pc1Inv, для которых Cs1::Set(); означает опустить в 0, а Cs1::Clear(); — поднять в 1.

    Интерфейс драйвера дисплея прост и минималистичен:

    Init, Fill и PutPixel — думаю, комментариев не требуют.
    Flush — по идее слив видео-буфера на дисплей, но в данном драйвере нет буфера, всё рисуется сразу на дисплее. Ведь не всегда есть лишний килобайт RAM для видео-буфера. Так что эта функция — задел на будущее и сейчас ничего не делает.
    SetOutputMode — режим вывода пикселей изображения. OutputMode может принимать следующие значения: WriteMode, XorMode, AndMode, AndNotMode, InvertMode. Коментариев тут тоже не требуется.
    Самое интересное это функция DrawBitmap. Она имеет шаблонный параметр BitmapT, который представляет класс реализующий картинку. Этот класс должен реализовывать 3 функции:

    Width() и Height() — это естественно ширина и высота картинки, а operator() возвращает значение пикселя в заданной позиции. Таким образом осуществляется независимость от способа представления картинки.
    Рассматрисать реализацию всех функций я не буду — они достаточно просты, рассмотрю только DrawBitmap, она самая интересная:

    Функция WritePage осуществляет вывод одного элемента сраницы и выглядит так:

    Кроме DrawBitmap WritePage (SetPage — тоже) нигде не используется. Так зачем нужно было выносить этот код в отдельную функцию? Просто DrawBitmap — шаблонная функция и при использовании разных типов битмапов компилятор любезно сгенерирует для каждого этого типа свою версию DrawBitmap. Если включить код WritePage (а он не очень маленький) непосредственно в DrawBitmap, то при этом он будет понапрасну продублирован в каждой инстанции DrawBitmap, а ведь он не зависит от шаблонного параметра BitmapT. Это явление называется «раздутие кода» (code bloat). Вынос фрагментов кода не зависящих от шаблонных параметров в отдельные функции — достаточно эффективное средство от раздутия кода, но тем не менее каждая инстанция DrawBitmap занимает порядка 400 байт (для AVR). Зачем-же делать эту функцию шаблонной и «раздувать код», если можно, например, просто передавать указатель на функцию чтения пикселя из картинки, или сделать абстрактный базовый класс Bitmap с виртуальными функциями (С++ всё-таки) и всё такое? Кто-то еще может вспомнить историю про то как чуваку не хватило одного байта, чтоб вместить прошивку. А вот зачем. При выводе картинок большое значение имеет скорость, вернее даже баланс универсальность — скорость — размер машинного кода. Вызавать функцию чтения пикселя по указателю — это дорого, с учетом того, что в шаблонной DrawBitmap вызов BitmapT.operator() всегда встраивается, в общей сложности DrawBitmap становится на 30-40% медленнее. Это иной раз имеет значение. К тому-же шаблонная DrawBitmap не отменяет возможности использования какого-нибудь абстрактного класса Bitmap с виртуальными функциями. То-есть имеется возможность выбирать между скоростью и размером машинного кода. В текущей реализации вывод картинки 128х64 из флеш памяти на весь экран занимает примерно 22 мс на AtMega16 бегающей на 16 МГц. При теоретическом минимуме 10 мс без учета чтения картинки, и организации циклов — дисплей быстрее не может. Вывод черного прямоугольника на весь экран занимает 15 мс, что очень не плохо.

    Картинки.

    Класс картинки, пригодный для вывода с помощью DrawBitmap выглядит примерно так:

    Это полный код для картинки хранящейся по строкам — как видно всё очень просто. Опять шаблон! Зачем тип указателя на данные делать шаблонным параметром? Так ведь адресные пространства бывают разные, нужно уметь читать картинки, например, из флеш памяти на тех-же AVR-ках. В этом нам помогут умные указатели на флеш память.
    Так объявляется картинка размещенная во флеш памяти:

    Также с помощью функции DrawBitmap легко реализовать рисование заполненных прямоугольников:

    Это в разы быстрее, чем рисовать закрашенный прямоугольник по-пиксельно.

    Рисовалка.

    Теперь к реализации остальных функций рисования. Большая их часть входят в класс Painter, который принимает тип дисплея в качестве шаблонного параметра:

    Большинство функций не требуют особых разъяснений. DrawBitmap, PutPixel, SetOutputMode, Clear, Width, Height являются простыми обёртками над функциями дисплея, просто для удобства.
    Прямые рисуются по вполне стандартному алгоритму Брезенхэма, окружности — по алгоритму Мичнера. Основная сложность в них была реализовать рисование с заданной толщиной линий. Это не очень тривиальная задача, как может показаться. И реализовал я это достоточно быстрыми, но не вполне корректными способами. У прямых торцы всегда парраллельны оси Х или У, хотя должны быть перпендикулярны самой прямой, а еще лучше, чтоб они были круглыми. В окружностях появляется смешанная связанность пикселей и из-за этого некоторая визуальная неравномерность толшины линии. К томе-же сейчас линии и окружности рисуются по-пиксельно и по этому работают относительно медленно. Будет время попробую сделать что-то типа построчной растеризации — будет и быстрее и аккуратнее, быстрый DrawBitmap и здесь пригодится.
    Остался только вывод текста:

    Опять шаблон. CharPtr — тип указателя на символ нужен для поддержки юникода и строк во флеш памяти. Font — тип шрифта. У класса шрифта должна быть только одна функция: GetChar — она принимает символ и возвращает его изображение. Изображением символа должно быть нечто пригодное для рисования с помощью функции DrawBitmap дисплея. Конструкция в блоке if(_charInterval) служит для заполнения интервалов между символами.
    Теперь перейдём к шрифтам. Применительно к МК распростронены два способа представления растровых шрифтов. В первом все символы имеют одинаковую ширину, для того чтоб найти смещение символа в таблице, достаточно умножить размер символа в байтах на его индекс в таблице. Этот способ хорошо подходит для маленьких размеров шрифта. Во втором случае символы имеют разную ширину и имеется дополнительная таблица, в которой хранятся ширина каждого символа и его смещение в массиве с изображениями. Для описания шрифтов используются две вспомогательные структуры:
    Это описание символа и шрифта соответственно. CharInfo хранится ширина и смещение символа. FontInfo описывает не весь шрифт, а один диапазон символов, содержит начало и конец этого диапазона, указатель на графические данные и указатель на таблицу описаний символов. Если последний указатель ноль, то значит шрифт имеет фиксированную ширину.
    Класс реализующий шрифт:

    Класс сделан шаблонным опять-же для поддержки данных размещенных во флеш памяти на AVR. Первый шаблонный параметр — тип указателя на графичечкие данные шрифта, второй — тип указателя на описатели символов. Конструктор класа принимает указатель на массив описаний диапазонов символов, его размер, ширину, высоту символов и unknownChar — символ выводимый когда для требуемого символа нет графических данных. Последний должен быть символом присутстующем в нулевой таблице. Обычно это что-то типа знака вопроса. Код функции GetChar выглядит следующим образом:

    Полное описание шрифта размером 5х8 точек с ASCII символами и русскими символами в кодировке CP-1251:

    Теперь используя этот шрифт можно что-то написать на дисплее:

    Тестирование и отладка.

    Теперь самое интересное. Тестировать и отлаживать программы работающие с графикой непосредственно на МК не очень продуктивно — много времени тратится на бесконечные перезаливки прошивки. Толи дело с десктопными приложениями, ткнул кнопку — оно скомпилилось и смотри на результат, захотел — поотлаживал пошагово. Хочется и программы работающие с графикой на МК также тестировать, ну хотя-бы частично. А ведь нет ничего невозможного, у нас для этого есть почти всё, что нужно. Вся представленная библиотека никак не завязана ни на какую целевую платформу, даже драйвер дисплея не привязан к конкретной реализации портов ввода-вывода. Есть реализация тестовых портов ввода-вывода, которая используется для модульного тестирования библиотеки работы с портами. А значит можно протестировать графическую библиотеку вместе с драйвером дисплея, подцепив его к тестовым портам. Нужно только сделать штуку, которая эти тестовые порты будет слушать и изображать из себя дисплей. Итак тестовое приложение будет на «голом» Win32 API без каких либо сторонних библиотек. Собираться будет из 2008 VisualStudio.
    Класс эмулирующий дисплей:

    В остальном ничего особенного: объявлен глобальный объект типа Glcd и в оконной процедуре по событию ON_PAINT вызывается функция Draw.
    Осталось только подключить драйвер к тестовому «дисплею»:

    Добавить комментарий