Войти
Все секреты компьютера для новичка и профессионала
  • Подробная инструкция — как пользоваться беговой дорожкой и обзор основных функций и режимов
  • Альтернативное начало (старт)
  • Как поменять язык в скайриме
  • Как поменять язык в скайриме через настройки или систему
  • Майнкрафт: дети и зомби выживание мультик про детей в майнкрафт видео игры minecraft видео для детей Что делать с ребенком в майнкрафте
  • Марине трафик на русском языке карта движения судов в реальном времени
  • Программа взаимодействия PIC16 и индикаторов ЖК. Работа с символьным ЖКИ на базе контроллера HD44780 Установка и инициализация lcd монитора

    Программа взаимодействия PIC16 и индикаторов ЖК. Работа с символьным ЖКИ на базе контроллера HD44780 Установка и инициализация lcd монитора

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

    Такие индикаторы часто используются при проектировании цифровых устройств, поэтому с ним необходимо уметь работать.
    Рассмотрим типовое внутреннее строение знакосинтезирующего ЖКИ :

    Внутренняя структура HD44780

    В основе ЖКИ лежит матрица из жидких кристаллов, подавая напряжение на элемент которой мы можем «зажечь» точку на экране. В нашем случае матрица состоит из знакомест (чаще всего 8х5 пикселей), сгруппированых в несколько рядков. Этим всем управляет встроенный контроллер HD44780 . У контроллера есть однобайтные ячейки памяти (DDRAM ), содержимое которых собственно отображается на экране согласно таблице записанной в CGRAM . Ячеек памяти обычно больше чем знакомест в ЖКИ , поэтому адресацию знакомест нужно смотреть в даташите. То есть нам необходимо только в нужную позицию записать код нужного знака, а все остальное HD44780 сделает сам.

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

    Старшая тетрада кода будет равна ряду выбранного символа, а младшая – строке. Можно создать свою таблицу символов, записав ее в CGRAM . На каждый символ требуется 5 байт, где единицы отвечают за «зажженные» пиксели. Например, цифра «8» кодируется последовательностью 0x6c,0x92,0x92,0x92,0x6c.
    Коды команд приведены в таблице.

    Таблица символов HD44780


    Значения флагов:


    Остается открытым вопрос: «как записать в нужную позицию код требуемого символа»? Для этого рассмотрим за что отвечают выводы ЖКИ . Выводы DB0-DB7 отвечают за входящие/исходящие данные. Высокий уровень на выводе RS дает индикатору понять, что сигнал на выводах DB0-DB7 является данными, а низкий – командой. Вывод W/R отвечает за направление данных, пишутся ли данные в память или читаются из нее (обычно чтение из ЖКИ не используется, можем смело на него подать низкий уровень). Импульс на выводе Е (длительностью не менее 500 нс) используется как сигнал для записи/чтения данных с выводов DB0-DB7 , RS и W/R .

    Вывод V0 используется для задания контраста изображения, вывода А,К – для питания подсветки (если она есть в вашей модели ЖКИ ). Оставшиеся 2 вывода – собственно питание ЖКИ . То есть, для управления ЖКИ потребуется 8+1+1=10 выводов. Но можно работать в режиме 4-х битного интерфейса. При этом, сперва будет передавать старшая тетрада команды/данных на выводах DB4-DB7, а после – младшая. Выводы при DB0-DB3 при этом не используются. Итого для управления требуется 6 выводов микроконтроллера.
    Теперь рассмотрим живой пример. Напишем программу для вывода текста «сайт» на имеющийся у меня в наличии WH1602А (2 строки по 16 символов).

    Для других ЖКИ следует сверить соответствие ячеек DDRAM знакоместам. Схема подключения ЖКИ к контроллеру выглядит так.

    Схема подключения к микроконтроллеру AVR


    Резистор R3 - 17 Ом ограничивает ток через подсветку, а переменный VR1 задает контраст (если все правильно подключено и запрограммировано, но индикатор молчит, покрутите VR1, чтобы изображения стало видимым). Также не в коем случае не следует путать полярность ЖКИ , питать его выше 5,5В, со своего опыта могу сказать, что горят они моментально. Назначение всех остальных деталей такое же как в
    Теперь перейдем к написанию программы. Для контроля индикатора напишем программу с несколькими ключевыми функциями работы с ЖКИ : lcd_dat(unsigned char x) – для записи данных х, lcd_com(unsigned char x) – для записи команды х, lcd_init(void) – для начальной инициализации индикатора:

      #include //библиотека ввода/вывода

    1. #define RS 2 //RS=PD2 - сигнал управления ЖКИ

      #define E 3 //E=PD3 - сигнал управления ЖКИ

    2. #define TIME 10 //Константа временной задержки для ЖКИ

      //Частота тактирование МК - 4Мгц

    3. //Программа формирвоания задержки

      void pause (unsigned int a)

      { unsigned int i;

    4. for (i= a; i> 0 ; i-- ) ;

    5. //Программа передачи команд в ЖКИ

      void lcd_com (unsigned char lcd)

      { unsigned char temp;

    6. temp= (lcd& ~(1 << RS) ) | (1 << E) ; //RS=0 – это команда

      PORTD= temp; //Выводим на portD старшую тетраду команды, сигналы RS, E

      asm("nop" ) ;

      PORTD= temp& ~(1 << E) ; //Сигнал записи команды

    7. temp= ((lcd* 16 ) & ~(1 << RS) ) | (1 << E) ; //RS=0 – это команда

      PORTD= temp; //Выводим на portD младшую тетраду команды, сигналы RS, E

      asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации

      PORTD= temp& ~(1 << E) ; //Сигнал записи команды

    8. pause (10 * TIME) ; //Пауза для выполнения команды

    9. //Программа записи данных в ЖКИ

      void lcd_dat (unsigned char lcd)

      { unsigned char temp;

    10. temp= (lcd| (1 << RS) ) | (1 << E) ; //RS=1 – это данные

      PORTD= temp; //Выводим на portD старшую тетраду данных, сигналы RS, E

      asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации

      PORTD= temp& ~(1 << E) ; //Сигнал записи данных

    11. temp= ((lcd* 16 ) | (1 << RS) ) | (1 << E) ; //RS=1 – это данные

      PORTD= temp; //Выводим на portD младшую тетраду данных, сигналы RS, E

      asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации

      PORTD= temp& ~(1 << E) ; //Сигнал записи данных

    12. pause(TIME) ; //Пауза для вывода данных

    13. //Программа иниализации ЖКИ

      void lcd_init (void )

      lcd_com(0x2c ) ; //4-проводный интерфейс, 5x8 размер символа

      pause(100 * TIME) ;

      pause(100 * TIME) ;

      pause (100 * TIME) ;

    14. //Основная программа

      int main(void )

      DDRD= 0xfc ; //Инициализация portD

      PORTD= 0x00 ;

    15. pause(1000 ) ;

      lcd_init() ; //Инициализация ЖКИ

    16. lcd_dat("w" ) ; //Вывод "www.сайт"

      lcd_dat("w" ) ;

      lcd_dat("w" ) ;

      lcd_dat("." ) ;

      lcd_dat("a" ) ;

      lcd_dat("v" ) ;

      lcd_dat("r" ) ;

      lcd_dat("l" ) ;

      lcd_dat("a" ) ;

      lcd_dat("b" ) ;

      lcd_dat("." ) ;

      lcd_dat("c" ) ;

      lcd_dat("o" ) ;

      lcd_dat("m" ) ;

    17. lcd_dat("I" ) ; //Записываем "It"s so easy"

      lcd_dat("t" ) ;

      lcd_dat(""" ) ;

      lcd_dat("s" ) ;

      lcd_dat(" " ) ;

      lcd_dat("s" ) ;

      lcd_dat("o" ) ;

      lcd_dat(" " ) ;

      lcd_dat("e" ) ;

      lcd_dat("a" ) ;

      lcd_dat("s" ) ;

      lcd_dat("y" ) ;

    18. while (1 ) //бесконечный цикл

    19. return 1 ;

    Программа очень проста, разобраться в ней не составит труда любому, кто хоть немного владеет C для AVR . Для латиницы и цифр ASCII коды совпадают с зашитыми в знакогенератор ЖКИ , поэтому позволительно использовать lcd_dat(‘A’) . Можно создать свою библиотеку для работы с ЖКИ, выделив функции lcd_dat(unsigned char x), lcd_com(unsigned char x), lcd_init(void) в отдельный модуль LCD.h и подключать его за надобностью.

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

      int main(void )

      { unsigned char data [ 14 ] = { "w" , "w" , "w" , "." , "a" , "v" , "r" , "l" , "a" , "b" , "." , "c" , "o" , "m" } ;

      unsigned char i;

      DDRD= 0xfc ; //Инициализация portD

      PORTD= 0x00 ;

    1. pause(1000 ) ; //Задержка, чтобы ЖКИ успел включиться

      lcd_init() ; //Инициализация ЖКИ

    2. for (i= 0 ; i< 14 ; i++ ) //Вывод записи побуквенно

      lcd_dat(data[ i] ) ;

    Только не стоит забывать, что нумерация массивов в С начинается с нуля. Существующую программу можно без существенных изменений использовать совместно с контроллером ATtiny2313 , подключив ЖКИ к PORTB , та как PORTD у ATtiny2313 имеет всего 7 выводов, а не 8, как у ATmega8 .

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

    есть маленький недочет в этом примере

    есть маленький недочет в этом примере, возможно по этой причине у многих не работает пример!

    вобщем пример лаконичен и прост, поэтому в глаза не бросается маленький недочет(тем кто ориентируется в языке "С"), и уж тем более тем кто только только знакомится с AVR и языком "С", возможно они даже недоумевают как так....пишут сделайте так и будет как на картинке....а не тут то было...

    вобщем вся проблема с циклами задержки, для того чтоб дисплей поспевал за контроллером, а именно в функции-

    //Программа формирвоания задержки

    void pause (unsigned int a)

    { unsigned int i;

    for (i=a;i>0;i--);

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

    по крайней мере это справедливо для atmel studio 6.1, и в этом можно убедится просмотрем папку проэкта, там есть *.lss файл содержащий асемблерный код данной программы, генерируемы при сборке проекта. никакого намека на реализацию функции void pause...

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

    а вот если сделать маленькую поправку

    void pause (unsigned int a)

    { unsigned int i;

    for (i=a;i>0;i--)
    asm("nop");

    То для компилятора это обретает смысл, это так же подтверждается явным появлением реализации функции в асемблерном коде

    0000006c
    :
    6c: 9c 01 movw r18, r24
    6e: 03 c0 rjmp .+6 ; 0x76
    70: 00 00 nop
    72: 21 50 subi r18, 0x01 ; 1
    74: 31 09 sbc r19, r1
    76: 21 15 cp r18, r1
    78: 31 05 cpc r19, r1
    7a: d1 f7 brne .-12 ; 0x70

    и скорей всего все заработает....покрайней мере у меня на atmega16 (внутренняя RC синхронизация 1Mhz) и использовании atmel studio 6.1 было именно так... возможно на др частотах придется поигратся с константой #define TIME 10 и/или значениями передаваемыми функции void pause

    вот здесь-> pause(значение) ...или pause(значение*TIME) ....

    удачи в обучении управлению AVR!

    Смотри, представь что ЖКИ -

    Смотри, представь что ЖКИ - пишущая машинка, бумага в машинке - память ЖКИ, каретка - указатель курсора. Кроме того ЖКИ на экран выводит не все содержимое памяти, а лишь часть. Вроде как некоторое окно, которое мы налаживаем на нашу бумагу с текстом.

    Вот I/D задает как мы будем печатать, справа-налево или слева-направо.
    S определяет, будем ли мы сдвигать окно экрана вслед за тем, как печатаем или нет.
    S/C - просто смещает видимое окно экрана или каретку машинки.
    R/L - уточняет куда (влево или вправо) мы будем сдвигать экран или курсов с помощью флага S/C.

    чего-то помоему не хватает!

    Содрал вашу прогу и протэусе и на меги8 не стартует. Экран молчит, стал копать по даташитам и вот что нарыл:
    не хватает в инициализации первых трех!

    0011 - ждем 5 мс
    0011 - ждем 100 мкс
    0011 - ждем 2 мс
    0010 - ждем 41 мкс
    0000 - -и-
    0010 - -и-
    1000
    0000
    1000
    0000
    0001
    0000
    0100

    если я не прав поправте!

    Не работает!

    Попробовал поменять частоты тактирования, задержки при инициализации и выводе символов(команд), пока что безуспешно. По поводу фьюзов, если вы имеете ввиду сконфигурировать выводы порта D c помощью регистров DDRB, PORTD как выходы с низким лог. уровнем, то это я сделал.
    От делать нечего скомпилировал простую прогу вывода символов с помощью средств CodeVisionAVR, загнал в PROTEUS - работает!...а с реальным LCD отказывается..

    Нет я говорю о том, что

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

    Не работает!

    Собрал и подключил всё как по схеме, только МК использовал ATmega16 и LCD WH1602M, соответственно откомпилировал в WinAVR для него прошивку. Однако, выводить что либо LCD отказался, также собирал в протеусе(на ATmega 8 и LM016L), данные с МК выводятся но на LCD ничего не видно. В чем может быть проблема? (Если это важно, использовал внутренний RC генератор для тактирования на 1 мГц)

    1. Для Atmega16 необходимо

    1. Для Atmega16 необходимо через фьюзы включить сперва что бы порт D работал.
    2. Попробуй изменить частоту тактирования на 4МГц и на 8МГц. Вся проблема ЖКИ в том, что не выдержаны все паузы при инициализации или при подаче команды. А контроллер ЖКИ очень чувствительный к этому.

    Есть вопрос:
    Собрал схемку хронометра на меге 8 с готовым хексом, - показания выводятся на WH0802,
    показание- число из трех цифр, которые выводятся на весь экран, одна цифра состоит из 4-х знакомест. Экран типа псевдографический. Каким образом могла писаться прошивка??
    Автор категорически отказывается давать исходники и не комментирует работу- наверное из соображения "интеллектуальной собственности".
    По-свободе хочу попробовать написать свою прошивку в учебных целях.

    Столкнулся с такой

    Столкнулся с такой ситуацией.
    Есть два LCD 16х2:
    1 - MTC-S16204XFGHSAY
    2 - WH1602A-YGH-CTK

    1-ый использую в проекте с GPS.
    2-ой решил использовать в проекте с клавиатурой. Но по каким то причинам lcd не работает.
    Контраст регулируется и появляются квадратики. И все.
    Возможно там другой порядок инициализации.
    Помогите разобраться
    Вот даташиты
    filebox.od.ua/?file=24a31fc50d62bfcd658bdadac84088ab

    Дисплеи ничем не отличаются.

    Дисплеи ничем не отличаются. Распиновка одинакова. Тайминги немного разнятся. Попробуй увеличить задержки при отсылке команд на ЖКИ или понизь частоту МК.

    Все ЖКИ на HD44780 имеют идентичную систему команд. Ты какой интерфейс юзаеш, 4-х битный, или 8-ми битный? Еще попробуй увеличить задержку между включением ЖКИ и его инициализацией, примерно до 0,1с. Полярность питания для ЖКИ не путалась, чтобы сгореть им немного надо? То я сдуру как-то спалил, а потом пытался подключить. Тоже выводились черные квадратики, через раз выводились данные, т.е. работал крайне нестабильно.

    Использую программы из статей

    Использую программы из статей о GPS.
    интерфейс 4-ех битный

    попробовал прогу отсюда
    chipenable.ru/index.php/programming-c/75-chasy-na-mikrokontrollere.html

    заработало

    А что изменить в вашей проге?

    Обрати внимание на задержки

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

    Аналоги HD44780

    Столкнулся с проблемой - не могу найти ЖКИ WH1602A по разумной цене. Например
    в чипдипе такие стоят chipdip.ru/product/wh1602a-ygh-ct-k.aspx
    700 деревянных. Что такое YGH в названии "WH1602A-YGH-CT(K), ЖКИ 16х2, англо-русский"
    Какие есть аналоги ЖКИ на базе HD44780? Вот нашёл страничку micronika.ru/order.phtml?vid=64 - там в названии FDCC1602A-FSBFBW-51SR содержится 1602A,
    просто обратил внимание. Может и FDCC1602A-FSBFBW-51S сойдёт без особого изменения кода?
    Какие проблемы могут возникнуть при использовани
    не собственно HD44780 от Хитачи, а его аналогов?
    ЗЫ Не плохо бы почитать про использование различных ЖКИ, аналогов хд44780, чем МЭЛТ"овские
    ЖКИ плохи

    В данной статье я приведу пример одного из вариантов программы инициализации жидкокристаллического алфавитно-цифрового индикатора на платформе контроллера HD44780 или KS0066 для начинающих программистов на языке ассемблер применительно к микроконтроллерам PIC16.

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

    После директив замены текста идут макросы – маленькие программки, к которым можно обращаться из основной программы сколько угодно и когда угодно. Первый макрос — impuls_E, обеспечивает на линии Е, линии стробирования и синхронизации, получение стробирующего импульса. Строка 14 – устанавливает на линии логическую единицу, через две псевдокоманды NOP, строка17 – устанавливает логический ноль. Таким образом мы получаем на линии Е положительный импульс длительностью 2 мксек при частоте кварцевого генератора 4 мГц. Следующий макрос Load_Znak, Позволяет нам загрузить код символа в регистр DR, для вывода его на индикатор. Можно заметить, что в этом макросе есть обращение к другому макросу, написанному ниже. Рассмотрим макрос send_LCD. Строка 26 – читаем содержимое регистра Write_data, т.е. код символа, который должен в нем находиться. Строка – 27, меняем местами старший и младший полубайты регистра. Строка – 28, выделяем старший полубайт кода символа, который уже находится в младшем полубайте и выдаем эти данные в порт В. Дело в том, что запись данных при 4-х разрядном режиме работы контроллера индикатора, происходит последовательно, сперва старший полубайт регистра, потом младший – строка 31… 33. После передачи полубайт, обязательно должен быть сформирован стробирующий импульс. Что мы и видим, строка 30 и 34. Для того, что бы контроллер дисплея успел обработать информацию, в макрос введена временная задержка, равная 200 микросекунд. После созданных нами макросов идет стандартная процедура инициализации микроконтроллера. В статье « » я рассказал об основных свойствах LCD дисплеев и коснулся темы создания своих символов. Как я уже говорил, в моих индикаторах нет символа градуса. Вот его и загрузим в знакогенератор индикатора. Для этого напишем небольшую подпрограмму, которая должна находится за процедурой инициализации микроконтроллера и впереди основной программы.Начинается подпрограмма с 69 строки, где мы заносим код адреса в области CGRAM, 40h — под этим адресом будет храниться первый пользовательский адрес. Смотрим скриншот 2.

    Так как каждый символ занимает восемь регистров памяти, то следующий созданный нами символ будет начинаться с адреса 40h + 08h = 48h. Следующий – 48h + 08h = 50h. Не забудьте, что сложение происходит в шестнадцатеричной системе счисления. И так, строки 69 и 70 – загрузка начального адреса символа. Далее идет поочередная запись восьми байт кода символа. Код символа градуса мы возьмем из программы LCDCC.

    Придется немного повторить то, что было в статье «Жидкокристаллические алфавитно-цифровые индикаторы». Смотрим скриншот этой программы. Нажатием на ячейки матрицы, мы рисуем нужный символ, в данном случае это символьный значок градуса. Внизу нам программа сразу пишет коды выбранных точек матрицы. Теперь нам необходимо эти коды записать в контроллер индикатора. Что мы и сделали. Теперь мы дошли до инициализации самого индикатора. Смотрим скриншот 3.

    Перед инициализацией для примера запишем данные в регистры вывода значений на индикатор. Введем, например, значение температуры 21,7 градусов. Потом мы создадим проект в протеусе и посмотрим, что у нас получилось. И так. Скриншот 3, строки 88… 93 – запись чисел в регистры. Инициализация начинается с метки InitLCD, как и положено ждем не менее 15 ms. После паузы, строки 98… 100, записываем в регистр Reg_3 число три – это будет количество раз передачи команды 30h = b’0011 0000’ (30h). И три записываем в регистр порта В, для последующей записи в контроллер индикатора, это число три находится в старшем полубайте команды. Формируем стробирующий импульс, строка 102, выдерживаем паузу 5 ms. Возвращаемся на метку Setloop. Посылаем команду пока не обнулится регистр Reg_3, т.е. три раза. После передачи этой команды, контроллер индикатора будет готов к работе, но в 8-ми разрядном режиме. Теперь переведем его в 4-х разрядный режим. Для этого перешлем команду 20h. Имейте в виду, что команды записываются в контроллер индикатора в 4-х разрядном режиме. Значит так, имеем команду 20h или 0010 0000. Так как в 4-х разрядном режиме команды передаются в два этапа, сперва данные старшего полубайта регистра, то мы заносим двойку в регистр порта В и записываем в контроллер индикатора, а так как младший полубайт пустой, то мы ничего и не передаем.

    После записи 2 в порт В, стробируем линию Е и делаем паузу в 200 us. Теперь индикатор будет работать в 4-х разрядном режиме. Следующая команда, это команда установки режима работы – две строки, шрифт — 5×7. Код команды 28h. Далее идет команда 0С на включение индикатора. Ну, а дальше, я думаю, разберетесь. Да, еще немного. В протеусе, созданный нами символ значка градуса выводится не корректно, выводит две точки, хотя в реальности все работает нормально. Смотрим фото. Успехов.

    Сегодня все чаще для отображения простой символьной информации используют символьные жидкокристаллические индикаторы ЖКИ. О том, как с ними работать мы и поговорим. В этой части статьи, мы детально рассмотрим символьные ЖКИ на базе контроллера HITACHI HD44780 (или совместимым с ним SAMSUNG KS0066). Статья - попытка систематизировать найденную мной информацию при работе с этими ЖКИ.

    Символьный ЖКИ с контроллером HD44780 (KS0066). Интерфейс

    Символьный ЖКИ есть ничем другим, как матрицей из точек, разделенной на строки и поля символов:

    Для управления этой матрицей и вывода собственно символов используется специальный контроллер.

    HD44780 (и совместимый с ним KS0066) – есть де-факто стандартом на контроллеры монохромных жидкокристаллических знакосинтезирующих дисплеев с параллельным 4-х или 8-битным интерфейсом. На базе этого контроллера выпускается огромное количество моделей с различным конструктивном и разрешением, начиная с 8x1 (восемь символов в одной строке), и заканчивая 40x4 (содержащих два независимых управляющих чипа). Типичная частота работы контроллера – 270 кГц.

    Контролер ЖКИ оперирует 3-мя блоками памяти:

    1. Для вывода символа контроллер использует память DDRAM (Display Data RAM), где хранятся ASCII-коды символов, которые мы хотим видеть на ЖКИ. Под нее отведено 80 ячеек памяти. Понятно, что на ЖКИ мы увидим лишь часть символов, которые находятся в DDRAM - если наш ЖКИ 1 или 2-строчный и отображает 8 символов в строке, то так:

    Рабочую область дисплея, как видно, можно смещать по ячейкам DDRAM (получается эффект бегущей строки).

    2. Шаблоны самих символов контроллер берет из CGROM (Character Generator ROM) – памяти знакогенератора. Таблицу символов можно посмотреть в спецификации на HD44780.

    3. Для хранения пользовательских символов (их шаблонов) предусмотрена память CGRAM (Character Generator RAM).

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

    Типичный 14-пиновый интерфейс контроллеров HD44780 :

    Земля, общий провод, GND

    Напряжение питания, Vcc (+5V)

    Настройка контрастности (Vo)

    Выбор регистра (R/S для HD44780, A0 для KS0066)

    Чтение/запись (R/W)

    Строб по спаду Е (Enable)

    Bit 0 (младший для 8мибитного интерфейса)

    Линия данных

    DB 4 (младший для 4х битного интерфейса)

    DB 7 (старший для 8-х (4х) битного интерфейса)

    Для дисплея с подсветкой

    Питание подсветки для дисплеев с подсветкой (анод)

    Питание подсветки для дисплеев с подсветкой (катод)

    Нумерацию пинов на конкретном ЖКИ смотрим в datasheet.

    Контрастность изображения на ЖКИ можно изменять, подключив дополнительно построечный резистор на 10 кОм по схеме:

    Но, следует смотреть в спецификацию на свой контроллер (например у ЖКИ Klsn10294v-0 на чипе KS0066 1-Vcc, а 2-GND). Подача питания подсветки может различаться от модели к модели в зависимости от её типа. Обычно подсветка питается от 5 вольт, токоограничительный резистор (50-100 Ом) обычно не обязателен.

    Назначение выводов R/S, R/W, E:

    При переходе Е с высокого лог. уровня на низкий данные, которые уже «висят» на выводах DB0..DB7, записываются в память контроллера ЖКИ для последующей обработки.

    При высоком лог. уровне на R/S(Register Select) контроллер ЖКИ воспринимает этот набор битов как данные(код символа), а при низком – как инструкцию и направляет их в соответствующий регистр.

    R/W определяет направление работы выводов DB0..DB7 – если на R/W «0», то мы можем только писать в порт DB, а если R/W = «1», то можем прочитать с него (например узнать занят контроллер или свободен для приема новых данных). Если мы не будем читать данные из ЖКИ, то можно «посадить» R/W на землю.

    Набор команд HD44780

    Для того чтобы начать выводить информацию на ЖКИ, его контроллер надо проинициализировать (сообщить ему об интерфейсе, шрифте, смещениях и т.д.). Контроллер может воспринимать всего 11 команд:

    Название инструкции

    Состояние выводов

    Время исполнения

    f раб. =270 кГц

    Очистка Всего ЖКИ установка адреса DDRAM в 0

    Установка текущего адреса DDRAM в 0 (курсор – домой) Данные DDRAM не меняются

    Установка направления движения курсора (I/D) и смещения дисплея (S) при выводе данных

    Display on/off control

    Вкл/выкл. дисплей(D), курсор(C) и его мерцание(B)

    Cursor or display shift

    Двигает курсор и смещает дисплей по DDRAM

    Установка интерфейса(DL), число строк(N) и шрифт символов(F)

    Set CGRAM address

    Установка счетчика адреса CGRAM. После этого можно записывать данные в CGRAM

    Set DDRAM address

    Установка счетчика адреса DDRAM

    Read busy flag & address

    Если BF = 1 то контроллер ЖКИ выполняет внутреннюю операцию (занят). АC6-АC0 – текущее значение адреса DDRAM

    Write data to RAM

    Запись данных в RAM

    Read data from RAM

    Чтение данных из RAM

    I/D = 1: адрес DDRAM увеличивается I/D = 0: уменьшается
    S = 1: сдвиг рабочей области дисплея по DDRAM разрешен
    D = 1: дисплей (изображение) включен
    C = 1: курсор включен
    В = 1: мерцание курсора включено

    S/C = 1: сдвинуть дисплей S/C = 0: переместить курсор
    R/L = 1: вправо R/L = 0: влево

    DL = 1: 8 bit DL = 0: 4 bits
    N = 1: 2 lines N = 0: 1 line
    F = 1: 5х10 F = 0: 5х8

    ACG: CGRAM address
    ADD: DDRAM address (адрес курсора)
    AC: Address counter DD и CGRAM адресов

    Инициализация ЖКИ

    Есть 2 способа инициализации контроллера ЖКИ:

    1. Через внутреннюю схему сброса.

    2. В ручном режиме (через посылку в него ряда команд, которыми мы задаем режим работы ЖКИ)

    Внутренняя схема сброса контроллера начинает работать сразу после включения питания. В этом есть один минус – если питание у нас «ползет» до рабочего уровня медленно (медленнее, чем за 10 мс), то самоинициализация контроллера может пройти некорректно. При этом способе инициализации контроллер сам исполняет следующие команды:

    1. Display clear

    2. Function set:
    DL = 1; 8-bit interface data
    N = 0; 1-line display
    F = 0; 5х8 dot character font

    3. Display on/off control:
    D = 0; Display off
    C = 0; Cursor off
    B = 0; Blinking off

    4. Entry mode set:
    I/D = 1; Increment by 1
    S = 0; No shift

    Второй способ исключает зависимость схемы от источника питания. Для инициализации контроллера ЖКИ в ручном режиме необходимо исполнить следующий алгоритм:

    Как видно, здесь нет ничего сложного: посылаем в ЖКИ команду за командой, учитывая время их исполнения (около 40 мкс) или проверяя флаг занятости контроллера ЖКИ (тогда надо посадить пин RW на лапку микроконтроллера и выставлять его в «1», когда хотим узнать, занят ЖКИ или нет).

    Вот, собственно, все, что касается теории работы с символьными ЖКИ. Если что-то пропустил или ошибся, читаем спецификацию на контроллер или .

    Во второй части рассмотрим аппаратную и программную реализацию связи PIC-микроконтроллера с ЖКИ.

    Некоторое время лежал без дела вот такой дисплей.


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

    Итак, начнём.
    Первое что надо сделать - это найти распиновку, то есть какой контакт за что отвечает, второе - найти название контроллера, который управляет дисплеем, для этого скачиваем даташит на данный LCD и открываем его на первой странице.


    Контакты считаются слева направо, первый отмечен красной стрелочкой. Напряжение питание равно 5 вольтам, управляющий контроллер S6A0069 или аналогичный, например, ks0066U .

    Для чего мы искали название управляющего контроллера? Дело в том, что в даташите на дисплей есть временные задержки(timing diagram), описана система команд, но нет банальной инициализации, а без неё никуда.
    Далее, открываем вторую страницу и видим таблицу, в которой написано какой контакт за, что отвечает.


    DB7…DB0 – шина данных/адреса.

    R/W - определяет что будем делать, считывать(R/W=1) или записывать(R/W=0)

    R/S – определяет, что будем слать команду(RS=0) или данные(RS=1)

    E – стробирующий вход, изменяя сигнал на этом входе мы разрешаем дисплею считывать/записывать данные.

    LED± – управление подсветкой.

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

    Скачиваем даташит на управляющий контроллер и находим инструкцию по инициализации. Картинки можно увеличить, кликнув по ним.



    Оказывается, таких инструкций целых две, для 8-битного и 4-битного режима. Что ж это за режимы такие? Данные режимы определяют по скольки проводкам будут передаваться данные: по четырём, либо по восьми. Давайте рассмотрим передачу по 4 проводам , в таком случае дисплей будет работать медленнее, но зато мы сэкономим 4 вывода микроконтроллера, да и реализация восьмибитного режима не намного отличается.

    Схема подключения информационных выглядит следующим образом.


    Контрастность можно регулировать включив потенциометр между выводами питания.

    Хотелось бы обратить внимание, что во время инициализации R/S и R/W всегда равны нулю, то есть мы будем слать команды .

    При инициализации можно настроить:

    • N - количество отображаемых строк
    • C - включить или выключить курсор
    • B - сделать курсор мигающим
    • I/D - увеличивать или уменьшать значение счётчика адреса
    • SH - двигать окошко дисплея
    Два последние пункта рассмотрим подробнее.
    На картинке ниже показано по какому адресу надо писать данные чтобы они отобразились в определённой позиции, например, если мы хотим вывести символ на первой позиции второй строки , то мы должны писать по адресу 0х40.


    После этого значение счётчика автоматически изменится, либо увеличится, либо уменьшится, а вместе с ним изменится и положение курсора.

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


    Эту таблицу нельзя изменить, но из неё можно брать уже готовые символы. Ещё один вид памяти это CGRAM , она то же представляет собой таблицу знакогенератора, но символы в этой таблице мы рисуем сами.


    Теперь пару слов о движении экрана, дело в том что обычно на дисплее мы видим не всю DDRAM, а лишь определённую часть, как показано на картинке ниже.


    В невидимую часть мы также можем писать, но то что мы запишем видно не будет, до тех пор, пока мы не подвинем на это место окошко экрана.

    С теорией закончили переходим к практике.
    Картина общения с LCD дисплеем в 4-битном режиме выглядит следующим образом.


    Данные шлются байтами, но так, как у нас 4-битный режим, то для того чтобы отправить байт надо сделать 2 посылки, старшим битом вперёд. На картинке первая посылка обозначена D7(старшая тетрада), вторая D3(младшая тетрада). Перед следующей посылкой мы должны проверить флаг занятости и если он не установлен снова можно слать, если установлен ждём, пока контроллер, управляющий LCD закончит свои дела.

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


    Для отправки надо по 8-битной шине:
    • R/W установить в 0
    • выдаём код команды/данные в шину
    • задержка 2us
    • опускаем строб Е

    Операция чтения реализуется аналогично:

    • убедиться, что управляющий контроллер свободен
    • R/W установить в 1
    • поднимаем строб E(в этот момент LCD выдаст данные в шину)
    • задержка 2us
    • читаем то что выдал LCD
    • опускаем строб Е
    Откуда взялась задержка 2us?

    Выше таймингов есть таблица в которой написано чему равны задержки изображённые на графике, так вот длительность стробирующего импульса - tw должна быть равна 230nS или 450nS в зависимости от напряжения питания, мы взяли чуть с запасом. Почему мы учли только эту задержку? Потому что значение остальных задержек очень мало.

    Для отправки по 4-битной шине:

    • убедиться, что управляющий контроллер свободен
    • установить RS в 0(команда) или 1(данные), в зависимости оттого что будем слать
    • R/W установить в 0
    • поднимаем строб E(устанавливаем в 1)
    • выдаём старшую тетраду в шину
    • задержка 2us
    • опускаем строб Е
    • задержка 1us
    • поднимаем строб E(устанавливаем в 1)
    • выдаём младшую тетраду в шину
    • задержка 2us
    • опускаем строб Е

    Для чтения по 4-битной шине:

    • убедиться, что управляющий контроллер свободен
    • порт данных на вход с подтяжкой
    • установить RS в 0(команда) или 1(данные), в зависимости оттого что будем читать
    • R/W установить в 1
    • поднимаем строб E(устанавливаем в 1)
    • задержка 2us
    • читаем старшую тетраду
    • опускаем строб Е
    • задержка 1us
    • поднимаем строб E(устанавливаем в 1)
    • задержка 2us
    • читаем младшую тетраду
    • опускаем строб Е

    Поднятие строба и вывод команды/данных в шину, можно поменять местами. Теперь не составит труда инициализировать дисплей. Для упрощения инициализации, мы заменим чтение флага занятости задержкой, а работу с флагом рассмотрим позже.
    Надо отметить, что при инициализации в 4-битном режиме используются 4-битные команды, а после инициализации 8-битная система команд, поэтому для инициализации мы реализуем отдельную функцию отправки команд void Write_Init_Command(uint8_t data) .
    //Код инициализации для Atmega16 #define F_CPU 8000000UL #define LCD_PORT PORTA #define LCD_DDR DDRA #define LCD_PIN PINA #define DATA_BUS 0XF0 #define RS 0 #define RW 1 #define E 2 #include #include void Write_Init_Command(uint8_t data) { //ножки по которым передаются команды/данные на выход LCD_DDR |= DATA_BUS; //будем слать команду LCD_PORT &= ~(1<Весело мигающий курсор, свидетельствует о том, что инициализация прошла успешно. В