AVR. Учебный курс

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


И вот появилось желание прикрутить его к одному из проектов, можно, конечно, постараться найти библиотеку с готовыми функциями, но в таком случае картина, о том как работает дисплей, будет неполная, а нас это не устраивает. Один раз, разобравшись с принципом работы 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<Весело мигающий курсор, свидетельствует о том, что инициализация прошла успешно. В

Для активизации четырехбитового режима надо программно сформировать сигналы управления согласно временным диаграммам на рис.1. По структуре они совпадают с диаграммой 8-ми разрядной шины за исключением удвоенного числа импульсов "Е". Линии связи проходят через старшие разряды шины данных DB4-DB7, младшие DB0-DB3 остаются не задействованными.

Рис.1

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

Принцип работы 4-х разрядной шины рассмотрим на примере тестовой программы для нашего LCD. На дисплей будут с секундными паузами выводиться цифры десятичного адреса знакоместа 0-255 и графические образы содержащихся в них символов.

Рис. 2

Как известно, каждый LCD имеет встроенный знакогенератор, представляющий собой область ПЗУ объемом более 8 Кб, которая прошивается на заводе-изготовителе. Традиционно первая половина ПЗУ с адресами 00-7Fh содержит начертания цифр, знаков препинания, а также заглавных и строчных букв латинского алфавита. Все как в IBM PC. Вторая половина "отдана на откуп" национальным алфавитам. В связи с этим HD44780 имеет модификации исполнения с тремя основными вариантами зашивки знакогенератора:

латиница и европейские языки (European standard font или Euro)
латиница и японские иероглифы (Japanese standard font или Japan)
латиница и кириллица (Custom font или Russian, рис.2)

Не все из ячеек знакогенератора заполнены. При обращении к "пустым" ячейкам на экране будет выведена произвольная информация, чаще всего состоящая из засвеченных точек. Первые 8 символов с адресами 0х00-0х07 отмечены "звездочкой". При желании они могут быть самостоятельно запрограммированы пользователем.

Какой знакогенератор имеется в конкретном LCD, должно быть указано в его условном обозначении или в технических параметрах, хотя на практике приходится верить честному слову продавца. Другой подход воочию увидеть на экране LCD все возможные начертания символов. Напишем, откомпилируем программу и запрограммируем контроллер, после чего в верхней строке экрана LCD будут с секундными паузами будут выводиться цифры десятичного адреса знакоместа 0-255 и графические образы содержащихся в них символов. Если графика и очередность появления символов соответствует рис.2, значит, LCD в порядке.

class="eliadunit">

Далее собираем схему согласно рис.3, ее отличие только в том что шина данных подключена по 4-х проводной линии, т.е. DB4-DB7 подключены, а DB0-DB3 остаются не задействованными. Вывод R/W дисплея подключен на минус, т.к. дисплей у нас является приемником данных.

Код программы проверки знакогенератора LCD приведен ниже.

// Программа проверки знакогенератора LCD #include #include #define RS PC0 #define EN PC2 // Функция записи команды в ЖКИ void lcd_com(unsigned char p) { PORTC &= ~(1 << RS); // RS = 0 (запись команд) PORTC |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p & 0xF0); // Выделяем старший нибл _delay_us(100); PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); PORTC |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p << 4); // Выделяем младший нибл _delay_us(100); PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); } // Функция записи данных в ЖКИ void lcd_dat(unsigned char p) { PORTC |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p & 0xF0); // Выделяем старший нибл _delay_us(100); PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); PORTC |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p << 4); // Выделяем младший нибл _delay_us(100); PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); } // Функция инициализации ЖКИ void lcd_init(void) { DDRC |= (1 << PC2)|(1 << PC0); // PC1, PC0 - выходы PORTC = 0x00; DDRD = 0xFF; // порт D - выход PORTD = 0x00; _delay_ms(50); // Ожидание готовности ЖК-модуля // Конфигурирование четырехразрядного режима PORTD |= (1 << PD5); PORTD &= ~(1 << PD4); // Активизация четырехразрядного режима PORTC |= (1 << EN); PORTC &= ~(1 << EN); _delay_ms(5); lcd_com(0x28); // Шина 4 бит, LCD - 2 строки lcd_com(0x08); // Полное выключение дисплея lcd_com(0x01); // Очистка дисплея _delay_us(100); lcd_com(0x06); // Сдвиг курсора вправо _delay_ms(10); lcd_com(0x0C); // Включение дисплея, курсор не видим } // Основная программа int main (void) { unsigned char znak = 0; // определяем переменную lcd_init(); // Инициализация дисплея while (1) { lcd_com(0x80); // Вывод в верхнюю левую позицию 1 строки lcd_dat(znak/100 + "0"); // Выделяем сотни lcd_dat((znak/10)%10 + "0"); // Выделяем десятки lcd_dat(znak%10 + "0"); // Выделяем единицы lcd_dat("="); // Выводим знак равенства lcd_dat(znak); // Выводим содержимое знакогенератора _delay_ms(100); // Тут можно поменять задержку вывода символов znak++; // Следующий символ знакогенератора } }

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

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

Внутренняя структура 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, чем МЭЛТ"овские
ЖКИ плохи

Так случилось, что прикупил я тут себе поприколу LCD дисплейчик две строки по восемь символов. Валялся он в ящике валялся, да чегото поперло меня и решил я его заюзать, попутно вкурив в его работу. О том как подключить к AVR LCD дисплей я вам сейчас и поведаю.

Для начала оговорюсь сразу, что речь тут пойдет о LCD индикаторах на контроллере HD44780, который стал промышленным стандартом де-факто на рынке цифро-буквенных дисплеев. Продается везде где только можно, стоит недорого (8х2 мне обошелся порядка 150 рублей), а также под него написана куча кода. Я же, как обычно, решил изобрести велосипед и сварганить свою собственную тру-библиотеку для работы с этим типом индикаторов. Разумеется на ассемблере, а на чем же еще? ;)

Подключение.
LCD на базе HD44780 подключается к AVR микроконтроллеру напрямую к портам. Есть два способа подключения — на 8 бит и на 4 бита. В восьмибитном режиме немножко проще закидывать байты — не нужно сдвигать байт, зато в четырех битном резко нужно тратить на целых четыре ножки контроллера меньше. Есть еще одна особенность работы в 8-битном режиме — к некоторым контроллерам можно подрубить этот дисплей как внешнее ОЗУ и засылать данные простыми командами пересылки. Лично я подключил его в режиме полного порта у меня один фиг выводы уже девать некуда было, так что не жалко.

  • Выводы DB7…DB0 это шина данных/адреса.
  • E — стробирующий вход. Дрыгом напряжения на этой линии мы даем понять дисплею что нужно забирать/отдавать данные с/на шину данных.
  • RW — определяет в каком направлении у нас движутся данные. Если 1 — то на чтение из дисплея, если 0 то на запись в дисплей.
  • RS — определяет что у нас передается, команда (RS=0) или данные (RS=1). Данные будут записаны в память по текущему адресу, а команда исполнена контроллером.

Со стороны питания все еще проще:

  • GND — минус, он же общий.
  • Vcc — плюс питания, обычно 5V
  • V0 — вход контрастности. Сюда нужно подавать напряжение от нуля до напряжения питания, тем самым задается контрастность изображения. Можно поставить переменный резистор, включенный потенциометром и крутить в свое удовольствие. Главное поймать значение максимального контраста, но чтобы не было видно знакомест (серый ореол из квадратов вокруг символа). Если же выставить слишком малый контраст, то символы будут переключаться лениво и задумчиво. Примерно как в калькуляторе у которого сели батарейки.
  • А — это вход Анода светодиодной подсветки. Короче плюс.
  • К — соответственно Катод, он же минус. Подсветка хавает примерно 100мА и поэтому нужно выставить туда токоограничительный резистор на 100 Ом. Кстати, многие ЖК дисплеи имеют на плате пятачки для припайки резисторов. Если прозвонить, то можно убедиться в том, что эти линии ведут на входы питания LCD, поэтому, впаяв резисторы, можно не заморачиваться на запитку подстветки, она будет подключена к питанию контроллера.
Логическая структура LCD контроллера HD44780

Контроллер имеет свой блок управления, который обрабатывает команды и память. Она делится на три вида:

DDRAM — память дисплея. Все что запишется в DDRAM будет выведено на экран. То есть, например, записали мы туда код 0x31 — на экране выскочит символ «1» т.к. 0х31 это ASCII код цифры 1. Но есть тут одна особенность — DDRAM память гораздо больше чем видимая область экрана. Как правило, DDRAM содержит 80 ячеек — 40 в первой строке и 40 во второй, а на дисплей может двигаться по этой линейке как окошко на логарифмической линейке, высвечивая видимую область. То есть, например, можно засунуть в DDRAM сразу пять пунктов меню, а потом просто гонять дисплей туда сюда, показывая по одному пункту. Для перемещения дисплея есть спец команда. Также есть понятие курсора — это место в которое будет записан следующий символ, т.е. текущее значение счетчика адреса. Курсор не обязательно может быть на экране, он может располагаться и за экраном или быть отключен вовсе.

CGROM — таблица символов. Когда мы записываем в ячейку DDRAM байт, то из таблицы берется символ и рисуется на экране. CGROM нельзя изменить, поэтому важно, чтобы она имела на борту русские буквы. Если, конечно, планируется русскоязычный интерфейс.

CGRAM — тоже таблица символов, но ее мы можем менять, создавая свои символы. Адресуется она линейно, то есть вначале идет 8 байт одного символа, построчно, снизу вверх — один бит равен одной точке на экране. Потом второй символ тем же макаром. Поскольку знакоместо у нас 5 на 8 точек, то старшие три бита роли не играют . Всего в CGRAM может быть 8 символов, соответственно CGRAM имеет 64 байта памяти. Эти программируемые символы имеют коды от 0х00 до 0х07. Так что, закинув, например, в первые 8 байт CGRAM (первый символ с кодом 00) какую нибудь фигню, и записав в DDRAM нуль (код первого символа в CGRAM ) мы увидим на экране нашу хрень.

Доступ к памяти.
Тут все просто. Мы командой выбираем в какую именно память и начиная с какого адреса будем писать. А потом просто шлем байты. Если указано, что записываем в DDRAM то на экран (или в скрытую область) полезут символы, если в CGRAM то байты полезут уже в память знакогенератора. Главное потом не забыть переключится обратно на область DDRAM

Система команд.
Система команд проста как мычание. О том, что передается команда контроллеру дисплея сообщит нога RS =0. Сама команда состоит из старшего бита, определяющего за что отвечает данная команда и битов параметров, указывающих контроллеру HD44780 как дальше жить.

Таблица команд:

DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 Значение
0 0 0 0 0 0 0 1 Очистка экрана. Счетчик адреса на 0 позицию DDRAM
0 0 0 0 0 0 1 Адресация на DDRAM сброс сдвигов, Счетчик адреса на 0
0 0 0 0 0 1 I/D S Настройка сдвига экрана и курсора
0 0 0 0 1 D C B Настройка режима отображения
0 0 0 1 S/C R/L Сдвиг курсора или экрана, в зависимости от битов
0 0 1 DL N F Выбор числа линий, ширины шины и размера символа
0 1 AG AG AG AG AG AG Переключить адресацию на SGRAM и задать адрес в SGRAM
1 AD AD AD AD AD AD AD Переключить адресацию на DDRAM и задать адрес в DDRAM

Теперь поясню что значат отдельные биты:
  • I/D — инкремент или декремент счетчика адреса. По дефолту стоит 0 — Декремент. Т.е. каждый следующий байт будет записан в n-1 ячейку. Если поставить 1 — будет Инкремент.
  • S — сдвиг экрана, если поставить 1 то с каждым новым символом будет сдвигаться окно экрана, пока не достигнет конца DDRAM, наверное удобно будет когда выводишь на экран здоровенную строку, на все 40 символов, чтобы не убегала за экран.
  • D — включить дисплей. Если поставить туда 0 то изображение исчезнет, а мы в это время можем в видеопамяти творить всякие непотребства и они не будут мозолить глаза. А чтобы картинка появилась в эту позицию надо записать 1.
  • С — включить курсор в виде прочерка. Все просто, записали сюда 1 — включился курсор.
  • B — сделать курсор в виде мигающего черного квадрата.
  • S/C сдвиг курсора или экрана. Если стоит 0, то сдвигается курсор. Если 1, то экран. По одному разу за команду
  • R/L — определяет направление сдвига курсора и экрана. 0 — влево, 1 — вправо.
  • D/L — бит определяющий ширину шины данных. 1-8 бит, 0-4 бита
  • N — число строк. 0 — одна строка, 1 — две строки.
  • F — размер символа 0 — 5х8 точек. 1 — 5х10 точек (встречается крайне редко)
  • AG — адрес в памяти CGRAM
  • АD — адрес в памяти DDRAM

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

Задача:

  1. Включить дисплей.
  2. Очистить содержимое.
  3. Сдвинуть курсор на одну позицию.
  4. И записать туда «1».
Решение (последовательность команд):

Первым делом Инициализация дисплея без которой большая часть дисплеев на HD44780 просто откажется работать. Некоторые виды имеют дефолтные состояние (шина 8 бит, курсор в 0) и им только дисплей включить. Но все же ее лучше сделать, мало ли что там намудрил разработчик. Лишней не будет.

  1. 001 11000 Шина 8 бит, 2 строки
  2. 00000001 Очистка экрана
  3. 000001 10 Инкремент адреса. Экран не движется
  1. 00001 100 Включили дисплей (D=1)
  2. 00000001 Очистили дисплей. Указатель встал на DDRAM
  3. 0001 0100 Сдвинули курсор (S/C=0) вправо (R/L=1)
  4. 00110001 — это мы уже записали данные (ножка RS=1) код «1» 0х31

Жирным шрифтом выделен идентификатор команды, ну а остальное по таблице увидите.

Задача: создать свой символ. С кодом 01 и вывести его на экран.
Считаем, что дисплей у нас уже инициализирован и готов к приему данных.

Решение:

  1. 01 001000 Выбираем в CGRAM адрес 0х08 — как раз начало второго символа (напомню, что на один символ уходит 8 байт)
  2. 00000001 Это пошли 8 байт данных. (RS=1 )
  3. 0000001 0 Рисуем значок молнии, ну или
  4. 000001 00 ССовскую Зиг руну, кому как
  5. 00001 000 больше нравится.
  6. 00011111 Старшие три бита не действуют
  7. 0000001 0 Туда можно писать что угодно, на
  8. 000001 00 результат влиять не будет.
  9. 00001 000 Последний байт данных
  10. 1 0000000 А это уже команда — переключение адреса на DDRAM и указатель на адрес 0000000 — первый символ в первой строке.
  11. 00000001 И снова данные (RS=1 ), код 01 — именно в него мы засунули нашу молнию.
Опа и он на экране!

Так, с логикой разобрались, пора вкуривать в физику протокола общения. Код я приведу несколько позже, когда вылижу свою библиотеку и заоптимизирую до состояния идеала. Пока же дам алгоритм, а его уж на любом языке программирования реализовать можно. Хоть на ассемблере, хоть на Сях, да хоть на Васике:)

Алгоритм чтения/записи в LCD контроллер HD44780
Направление, а также команда/данные определяются ножками, а чтение и запись осуществляется по переходу строба (вывод Е) из 1 в 0

Инициализация портов

  1. RS, RW, E — в режим выхода.
  2. DB7..DB0 в режим входа. Впрочем, можно их не трогать, дальше переопределим.

Ожидание готовности, чтение флага занятости.
  1. RS=0 (команда)
  2. RW=1 (чтение)
  3. E=1 (Готовьсь!!!)
  4. Пауза (14 тактов процессора на 8МГЦ хватало)
  5. Е=0 (Пли!)
  6. Читаем из порта. Если бит 7 (Busy flag) установлен, то повторяем все заново, пока не сбросится.

Запись команды
  1. Ожидание готовности
  2. RS=0 (команда)
  3. RW=0 (запись)
  4. Е=1 (Готовьсь!!!)
  5. Порт на выход
  6. Вывести в порт код команды
  7. Пауза
  8. Е=0 (Пли!)
  9. Орудие на плечо Порт на вход, на всякий случай.

Запись Данных
  1. Ожидание готовности
  2. RS=1 (Данные)
  3. RW=0 (запись)
  4. Е=1 (Готовьсь!!!)
  5. Порт на выход
  6. Вывести в порт код команды
  7. Пауза
  8. Е=0 (Пли!)
  9. Порт на вход, на всякий случай.

Чтение команды
  1. Ожидание готовности
  2. Порт данных на вход с подтяжкой (DDR=0, PORT=1)
  3. RS=0 (команда)
  4. RW=1 (чтение)
  5. Пауза
  6. Считываем данные с порта
  7. E=0 (Ать!)

Чтение Данных
  1. Ожидание готовности
  2. Порт данных на вход с подтяжкой (DDR=0, PORT=1)
  3. RS=1 (Данные)
  4. RW=1 (чтение)
  5. Е = 1 (Готовьсь! В этот момент данные из LCD вылазят на шину)
  6. Пауза
  7. Считываем данные с порта
  8. E=0 (Ать!)

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

Запись:

  1. Пауза
  2. Выставили в порт старшую тетраду
  3. Пауза
  4. Пауза
  5. Выставили в порт младшую тетраду

Чтение
  1. Пауза
  2. Читаем из порта старшую тетраду
  3. Пауза
  4. Пауза
  5. Читаем из порта младшую тетраду

Ждите код:) Скоро будет:)
UPD:

Для работы с символьными графическими дисплеями предлагаем воспользоваться библиотекой LiquidCrystal которая входит в стандартный набор Arduino IDE и предназначена для работы по 8-битному (4-битному) параллельному интерфейсу. Если Ваш дисплей подключается к Arduino по шине I2, то Вам нужно установить библиотеку LiquidCrystal_I2C (большинство функций которой повторяют функции первой библиотеки).

Поддерживаемые дисплеи:

Дисплей Подключение и инициализация
LCD1602 - символьный дисплей (16x02 символов),


#include
[ , 8 , 9 , 10 , 11 ]);
void setup(){ lcd.begin(16 , 2); }

// Пояснение:

void setup(){ ОБЪЕКТ.begin(КОЛ_СТОЛБЦОВ, КОЛ_СТРОК); }


LiquidCrystal ОБЪЕКТ (RS , E , D0 , D1 , D2 , D3 , D4 , D5 , D6 , D7);


с интерфейсом I2C (синий)

#include
#include
LiquidCrystal_I2C lcd(0x27 или 0x3F , 16 , 2);
void setup(){ lcd.init(); }

// Пояснение:



LCD1602 I2C - символьный дисплей (16x02 символов),
с интерфейсом I2C (зелёный)

#include
#include
LiquidCrystal_I2C lcd(0x27 или 0x3F , 16 , 2);
void setup(){ lcd.init(); }

// Пояснение:
LiquidCrystal_I2C ОБЪЕКТ (АДРЕС_I2C , КОЛ_СТОЛБЦОВ, КОЛ_СТРОК);
// АДРЕС_I2C может быть либо 0x27, либо 0x3F

LCD2004 - символьный дисплей (20x04 символов),
с параллельным интерфейсом (синий)

#include
LiquidCrystal lcd(2 , 3 , 4 , 5 , 6 , 7 [ , 8 , 9 , 10 , 11 ]);
void setup(){ lcd.begin(20 , 4); }

// Пояснение:
LiquidCrystal ОБЪЕКТ (RS , E , D4 , D5 , D6 , D7);
void setup(){ ОБЪЕКТ.begin(КОЛ_СТОЛБЦОВ, КОЛ_СТРОК); }

// Если используется 8 проводов шины данных, то указываем их все
LiquidCrystal ОБЪЕКТ (RS , E , D0 , D1 , D2 , D3 , D4 , D5 , D6 , D7);

LCD2004 I2C - символьный дисплей (20x04 символов),
с интерфейсом I2C (синий)
#include
#include
LiquidCrystal_I2C lcd(0x27 или 0x3F , 20 , 4);
void setup(){ lcd.init(); }

// Пояснение:
LiquidCrystal_I2C ОБЪЕКТ (АДРЕС_I2C , КОЛ_СТОЛБЦОВ, КОЛ_СТРОК);
// АДРЕС_I2C может быть либо 0x27, либо 0x3F

#1 Пример

Выводим надпись на дисплей LCD1602 подключённый по шине I2C. Для работы с дисплеем LCD2004 нужно изменить 3 строку на LiquidCrystal_I2C lcd(0x27,20,4);

#include // Подключаем библиотеку для работы с LCD дисплеем по шине I2C LiquidCrystal_I2C lcd(0x27,16,2); // Объявляем объект библиотеки, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2) // Если надпись не появилась, замените адрес 0x27 на 0x3F void setup(){ // lcd.init(); // Инициируем работу с LCD дисплеем lcd.backlight(); // Включаем подсветку LCD дисплея lcd.setCursor(0, 0); // Устанавливаем курсор в позицию (0 столбец, 0 строка) lcd.print("LCD"); // Выводим текст "LCD", начиная с установленной позиции курсора lcd.setCursor(0, 1); // Устанавливаем курсор в позицию (0 столбец, 1 строка) lcd.print("www.iarduino.ru"); // Выводим текст "www.iarduino.ru", начиная с установленной позиции курсора } // // void loop(){} // Код внутри функции loop выполняется постоянно. Но так как мы выводим статичный текст, нам достаточно его вывести 1 раз при старте, без использования кода loop

#2 Пример

Выводим надпись на дисплей LCD1602 подключённый по 4-битной параллельной шине. Для работы с дисплеем LCD2004 нужно изменить 5 строку на lcd.begin(20, 4);

#include // Подключаем библиотеку LiquidCrystal для работы с LCD дисплеем LiquidCrystal lcd(2,3,4,5,6,7); // Объявляем объект библиотеки, указывая выводы дисплея (RS,E,D4,D5,D6,D7) // Если используется 8 проводов шины данных, то указываем (RS,E,D0,D1,D2,D3,D4,D5,D6,D7) void setup(){ // lcd.begin(16, 2); // Инициируем работу с LCD дисплеем, указывая количество (столбцов, строк) lcd.setCursor(0, 0); // Устанавливаем курсор в позицию (0 столбец, 0 строка) lcd.print("LCD2004"); // Выводим текст "LDC1602", начиная с установленной позиции курсора lcd.setCursor(0, 1); // Устанавливаем курсор в позицию (0 столбец, 1 строка) lcd.print("www.iarduino.ru"); // Выводим текст "www.iarduino.ru", начиная с установленной позиции курсора } // // void loop(){} // Код внутри функции loop выполняется постоянно. Но так как мы выводим статичный текст, нам достаточно его вывести 1 раз при старте, без использования кода loop

#3 Пример

Выводим надпись «Русский язык» на дисплей LCD1602 подключённый по шине I2C:

#include // Подключаем библиотеку для работы с шиной I2C #include // Подключаем библиотеку для работы с LCD дисплеем по шине I2C LiquidCrystal_I2C lcd(0x27,16,2); // Объявляем объект библиотеки, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2) // uint8_t symbol = { // Объявляем массив из 6 собственных символов (к и й я з ы), каждый символ состоит из 8 байт { 0, 0,18,20,24,20,18, 0 }, // к { 0, 0,17,19,21,25,17, 0 }, // и {10, 4,17,19,21,25,17, 0 }, // й { 0, 0,15,17,15, 5, 9, 0 }, // я { 0, 0,14,17, 6,17,14, 0 }, // з { 0, 0,17,17,29,19,29, 0 }}; // ы // void setup(){ // lcd.init(); // Инициируем работу с LCD дисплеем lcd.backlight(); // Включаем подсветку LCD дисплея lcd.createChar(1, symbol); // Загружаем 1 символ "к" в ОЗУ дисплея lcd.createChar(2, symbol); // Загружаем 2 символ "и" в ОЗУ дисплея lcd.createChar(3, symbol); // Загружаем 3 символ "й" в ОЗУ дисплея lcd.createChar(4, symbol); // Загружаем 4 символ "я" в ОЗУ дисплея lcd.createChar(5, symbol); // Загружаем 5 символ "з" в ОЗУ дисплея lcd.createChar(6, symbol); // Загружаем 6 символ "ы" в ОЗУ дисплея lcd.setCursor(0, 0); // Устанавливаем курсор в позицию (0 столбец, 0 строка) lcd.print("Pycc\1\2\3 \4\5\6\1"); // Выводим текст "Pycckий языk", где "Pycc" написано латиницей, а "kий языk" - символами из ОЗУ дисплея } // Если нужно вывести символ из ОЗУ дисплея, то пишем \ и номер символа // void loop(){} // Код внутри функции loop выполняется постоянно. Но так как мы выводим статичный текст, нам достаточно его вывести 1 раз при старте, без использования кода loop

Функции, общие для библиотек LiquidCrystal и LiquidCrystal_I2C:

  • begin(cols,rows,); – Инициализация дисплея с указанием количества столбцов, строк и размера символа.
  • clear(); – Очистка дисплея с установкой курсора в положение 0,0 (Занимает много времени!).
  • home(); – Установка курсора в положение 0,0 (Занимает много времени!).
  • display(); – Быстрое включение дисплея (без изменения данных в ОЗУ).
  • noDisplay(); – Быстрое выключение дисплея (без изменения данных в ОЗУ).
  • blink(); – Включение мигающего курсора (с частотой около 1 Гц).
  • noBlink(); – Выключение мигающего курсора.
  • cursor(); – Включение подчеркивания курсора.
  • noCursor(); – Выключение подчеркивания курсора.
  • scrollDisplayLeft(); – Прокрутка дисплея влево. Сдвиг координат дисплея на один столбец влево (без изменения ОЗУ).
  • scrollDisplayRight(); – Прокрутка дисплея вправо. Сдвиг координат дисплея на один столбец вправо (без изменения ОЗУ).
  • leftToRight(); – Указывает в дальнейшем сдвигать положение курсора, после вывода очередного символа, на один столбец вправо.
  • rightToLeft(); – Указывает в дальнейшем сдвигать положение курсора, после вывода очередного символа, на один столбец влево.
  • noAutoscroll(); – Указывает в дальнейшем выравнивать текст по левому краю от позиции курсора (как обычно).
  • autoscroll(); – Указывает в дальнейшем выравнивать текст по правому краю от позиции курсора.
  • createChar(num,array); – Запись пользовательского символа в CGRAM дисплея под указанным номером.
  • setCursor(col,row); – Установка курсора в позицию указанную номером колонки и строки.
  • print(text); – Вывод текста, символов или цифр на экран дисплея. Синтаксис схож с одноимённой функцией класса Serial.

Функции, реализованные только в библиотеке LiquidCrystal_I2C:

  • init(); – Инициализация дисплея. Должна быть первой командой библиотеки LiquidCrystal_I2C после создания объекта. На самом деле данная функция есть и в библиотеке LiquidCrystal, но в той библиотеке она вызывается автоматически (по умолчанию) при создании объекта.
  • backlight(); – Включение подсветки дисплея.
  • noBacklight(); – Выключение подсветки дисплея.
  • setBacklight(flag); – Управление подсветкой (true - включить / false - выключить), используется вместо функций noBacklight и backlight.

Подключение:

// Для шины I2C:
#include
#include
LiquidCrystal_I2C lcd(address , col , row );
void setup(){
lcd.init();
}

Параметр:
  • address: Адрес дисплея на шине I2C - 0x27 или 0x3F
  • col:
  • row:
// Для параллельной шины из 4 проводов:
#include
LiquidCrystal lcd( RS , E , D4 , D5 , D6 , D7 );
void setup(){
lcd.begin( col , row );
}
Параметр:
  • RS: № вывода Arduino к которому подключён вывод RS
  • E: № вывода Arduino к которому подключён вывод E
  • D0...D3: № выводов Arduino к которым подключены выводы D0-D3
  • D4...D7: № выводов Arduino к которым подключены выводы D4-D7
  • col: количество столбцов реализованное у дисплея
  • row: количество строк реализованное у дисплея
// Для параллельной шины из 8 проводов:
#include
LiquidCrystal lcd( RS , E , D0 , D1 , D2 , D3 , D4 , D5 , D6 , D7 );
void setup(){
lcd.begin( col , row );
}
begin(col , row , );
Инициализация дисплея с указанием размеров экрана и символов.
Параметр:
  • col: количество столбцов реализованное у дисплея
  • row: количество строк реализованное у дисплея
  • size: размер символов, указывается константой:
    LCD_5x8DOTS (по умолчанию), или LCD_5x10DOTS
/* Для шины I2C: */ #include // Подключаем библиотеку для работы с шиной I2C #include // Подключаем библиотеку для работы с LCD дисплеем по шине I2C LiquidCrystal_I2C lcd(0x3F,20,4); // Объявляем объект библиотеки, указывая параметры дисплея (адрес I2C = 0x3F, количество столбцов = 20, количество строк = 4) // void setup(){ // lcd.init(); // Инициируем работу с LCD дисплеем lcd.backlight(); // Включаем подсветку LCD дисплея... // Выводим информацию, которая должна отображаться при старте } // // void loop(){} // ... // Выводим информацию которая должна меняться по алгоритму Вашего кода } // /* Для 4 проводной параллельной шины: */ #include // Подключаем библиотеку LiquidCrystal для работы с LCD дисплеем LiquidCrystal lcd(2,3,4,5,6,7); // Объявляем объект библиотеки, указывая выводы дисплея (RS,E,D4,D5,D6,D7) // Если используется 8 проводов шины данных, то указываем (RS,E,D0,D1,D2,D3,D4,D5,D6,D7) void setup(){ // lcd.begin(16, 2); // Инициируем работу с LCD дисплеем, указывая количество (столбцов, строк) ... // Выводим информацию, которая должна отображаться при старте } // // void loop(){} // ... // Выводим информацию которая должна меняться по алгоритму Вашего кода } //

Функции управления дисплеем:

display();
Включает дисплей после того как он был выключен функцией noDisplay.
Примечание: Функция выполняется быстро и без изменений в ОЗУ дисплея.
noDisplay();
Выключает дисплей.
Данные на дисплее не будут отображаться до вызова функции display, но и не сотрутся из памяти ОЗУ, а после вызова функции display, опять будут отображаться.
Примечание: Функция выполняется быстро и без изменений в ОЗУ дисплея.
scrollDisplayLeft();
Сдвигает координаты дисплея на один столбец влево.



scrollDisplayRight();
Сдвигает координаты дисплея на один столбец вправо.
Постоянный вызов данной функции создаст эффект бегущей строки.
Координаты сдвигаются как для имеющейся на дисплее информации, так и для той, которая будет выведена после.
Примечание: Функция выполняется без изменений ОЗУ дисплея.
Если вызвать функцию 40 раз подряд, то координата вернётся в изначальную точку
clear();
Очистка дисплея с установкой курсора в положение 0,0.
Информация имеющаяся на дисплее безвозвратно сотрётся.
Примечание: Занимает много времени.
backlight();
Включение подсветки дисплея.
noBacklight();
Выключение подсветки дисплея.
Примечание: Функция реализована только в библиотеке LiquidCrystal_I2C.
setBacklight(flag );
Управление подсветкой (вместо функций noBacklight и backlight).
Параметр:
  • flag: значение true - включает, а false - выключает подсветку.
Примечание: Функция реализована только в библиотеке LiquidCrystal_I2C.
/* Выводим надпись для наблюдения за функциями управления дисплеем: */ lcd.cursor(0,0); // Устанавливаем курсор в крайний верхний угол дисплея (0 столбец, 0 строка) lcd.print("iarduino.ru"); // Выводим текст "iarduino.ru" (первая буква "i" будет находиться в позиции "0,0", а последняя "u" в позиции "10,0", невидимый курсор в позиции "11,0") // lcd.noDisplay(); // Выключаем дисплей (надпись исчезнет с дисплея) lcd.display(); // Включаем дисплей (надпись появится на дисплее в том же месте) lcd.scrollDisplayLeft(); // Сдвигаем координаты столбцов влево (на дисплее будет отображаться "arduino.ru" без первой буквы "i", которая выйдет за пределы дисплея, но останется в его ОЗУ) lcd.scrollDisplayRight(); // Сдвигаем координаты столбцов вправо (на дисплее будет отображаться "iarduino.ru" на том же месте, где и была выведена изначально) lcd.clear(); // Чистим дисплей (надпись безвозвратно исчезнет с дисплея) lcd.noBacklight(); // Отключаем подсветку дисплея lcd.backlight(); // Включаем подсветку дисплея lcd.setBacklight(0); // Отключаем подсветку дисплея lcd.setBacklight(1); // Включаем подсветку дисплея

Функции управления курсором:

setCursor(col , row );
Установка курсора в указанную позицию.
Параметр:
  • col: номер столбца (начиная с 0).
  • row: номер строки (начиная с 0)
home();
Установка курсора в позицию 0,0. Работает как функция setCursor(0,0);
Примечание: Занимает много времени.
blink();
Включение мигающего курсора.
Примечание: Курсор занимает всё поле символа и мигает с частотой около 1 Гц, в той позиции где он был установлен ранее.
noBlink();
Выключение мигающего курсора.
Примечание: Курсор становится невидим, но его позиция сохраняется.
cursor();
Включение подчеркивания курсора.
Примечание: Курсор принимает вид символа подчёркивания и находится в той позиции, где он был установлен ранее.
noCursor();
Выключение подчеркивания курсора.
Примечание: Курсор становится невидим, но его позиция сохраняется.
lcd.setCursor(0, 1); // Устанавливаем курсор на первый символ второй строки (нумерация строк и столбцов начинается с 0) lcd.home(); // Устанавливаем курсор на первый символ первой строки (как при вызове lcd.setCursor(0,0);) lcd.blink(); // Делаем курсор видимым (на месте курсора будет мигать прямоугольник) lcd.noBlink(); // Делаем курсор невидимым (убираем мигающий прямоугольник) lcd.cursor(); // Делаем курсор видимым (на месте курсора появится знак подчёркивания) lcd.noCursor(); // Делаем курсор невидимым (убираем знак подчёркивания) // Если курсор попадает на место где есть символ, то этот символ не исчезает

Функции указывающие направление и выравнивание:

leftToRight();
Указывает, что после каждого нового символа, положение курсора должно сдвигаться на один столбец вправо.
Примечание: Если вывести текст "abc" на дисплее отобразится "abc" и текст будет находиться правее от изначального положения курсора.
(Как обычно)
rightToLeft();
Указывает, что после каждого нового символа, положение курсора должно сдвигаться на один столбец влево.
Примечание: Если вывести текст "abc" на дисплее отобразится "cba" и текст будет находиться левее от изначального положения курсора.
(Письменность справа налево)
noAutoscroll();
Указывает, что в дальнейшем, текст нужно выравнивать по левому краю от изначальной позиции курсора.
Примечание: если установить курсор в позицию 10,0 и вывести текст, то в данной позиции будет находиться первый символ выведенного текста.
(Как обычно)
autoscroll();
Указывает, что в дальнейшем, текст нужно выравнивать по правому краю от изначальной позиции курсора.
Примечание: если установить курсор в позицию 10,0 и вывести текст, то в данной позиции будет находиться курсор.
(Координаты дисплея будут сдвинуты влево, как будто Вы вызвали функцию scrollDisplayLeft столько раз, сколько букв в выведенном тексте)
lcd.leftToRight(); // Указываем курсору сдвигаться вправо (Как обычно в европейской письменности) lcd.clear(); lcd.setCursor(5,0); lcd.print("ABC"); // На дисплее увидим: " ABC " (После "A" курсор сдвинулся вправо и вывелась "B", далее курсор сдвинулся вправо и вывелась "C") lcd.rightToLeft(); // Указываем курсору сдвигаться влево (Как в письменности справа налево) lcd.clear(); lcd.setCursor(5,0); lcd.print("ABC"); // На дисплее увидим: " CBA " (После "A" курсор сдвинулся влево и вывелась "B", далее курсор сдвинулся влево и вывелась "C") lcd.noAutoscroll(); // Устанавливаем выравнивание по левому краю (Как обычно) lcd.clear(); lcd.setCursor(5,0); lcd.print("ABC"); // На дисплее увидим: " ABC " (Как обычно) lcd.autoscroll(); // Устанавливаем выравнивание по правому краю (Координаты дисплея будут сдвинуты влево на количество выведенных символов) lcd.clear(); lcd.setCursor(5,0); lcd.print("ABC"); // На дисплее увидим: " ABC " (Координаты дисплея будут сдвинуты на 3 символа влево, так как после каждого символа совершается вызов функции scrollDisplayLeft)

Функции ввода текста и символов:

createChar(num,array);
Запись пользовательского символа в CGRAM дисплея под указанным номером.
Если Вы хотите вывести текст (функцией print) в котором должен находиться установленный Вами символ, укажите слэш и номер под которым был записан этот символ: print("C\1MBO\2").
Параметр:
  • num: номер под которым будет записан символ.
  • array: массив представляющий записываемый символ.
Примечание: Массив состоит из нескольких байт, количество которых равно количеству строк в символе. Каждый установленный бит байта соответствует установленному (отображаемому) пикселю символа.
print(text);
Вывод текста, символов или цифр на экран дисплея.
Параметр:
  • text: символ, число или строка для вывода на дисплей.
Примечание: Синтаксис схож с одноимённой функцией класса Serial.
#include // Подключаем библиотеку для работы с шиной I2C #include // Подключаем библиотеку для работы с LCD дисплеем по шине I2C LiquidCrystal_I2C lcd(0x27,16,2); // Объявляем объект библиотеки, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2) // uint8_t symbol_d = {0b00000, // 1 строка символа "д" 0b00000, // 2 строка символа "д" 0b00110, // 3 строка символа "д" 0b01010, // 4 строка символа "д" 0b01010, // 5 строка символа "д" 0b01010, // 6 строка символа "д" 0b11111, // 7 строка символа "д" 0b10001}; // 8 строка символа "д" Весь массив можно записать одной строкой: uint8_t symbol_d={0,0,6,10,10,10,31,17}; // uint8_t symbol_i = {0b00000, // 1 строка символа "и" 0b00000, // 2 строка символа "и" 0b10001, // 3 строка символа "и" 0b10011, // 4 строка символа "и" 0b10101, // 5 строка символа "и" 0b11001, // 6 строка символа "и" 0b10001, // 7 строка символа "и" 0b00000}; // 8 строка символа "и" Весь массив можно записать одной строкой: uint8_t symbol_i={0,0,17,19,21,25,17,0}; void setup(){ // lcd.init(); // Инициируем работу с LCD дисплеем lcd.backlight(); // Включаем подсветку LCD дисплея lcd.createChar(1,symbol_d); // Загружаем в память дисплея первый символ lcd.createChar(2,symbol_i); // Загружаем в память дисплея второй символ lcd.clear(); // Чистим экран lcd.setCursor(0,0); // Устанавливаем курсор в крайний верхний угол lcd.print("Pa\1\2o"); // Выводим текст "Paдиo" при этом символы "P", "a" , "o" пишем латиницей, } // а символы "д", "и" выводим из памяти дисплея, указывая их номера // void loop(){ // lcd.setCursor(0,1); lcd.print(" "); // стираем всю нижнюю строку lcd.setCursor(0,1); lcd.print("i"); lcd.print("arduino"); lcd.print(".ru"); // выводим текст "i" "arduino" ".ru" в нижней строке delay(2000); // ждём 2 секунды lcd.setCursor(0,1); lcd.print(" "); // стираем всю нижнюю строку lcd.setCursor(0,1); lcd.print(12.345); // выводим число 12.34 (выводится 2 знака после запятой) delay(2000); // ждём 2 секунды lcd.setCursor(0,1); lcd.print(" "); // стираем всю нижнюю строку lcd.setCursor(0,1); lcd.print(12, HEX); // выводим число 12 в виде шестнадцатиричного числа delay(2000); // ждём 2 секунды lcd.setCursor(0,1); lcd.print(" "); // стираем всю нижнюю строку lcd.setCursor(0,1); lcd.print(1); // выводим число 1 delay(2000); // ждём 2 секунды }
Loading...Loading...