Для активизации четырехбитового режима надо программно сформировать сигналы управления согласно временным диаграммам на рис.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 в порядке.
Далее собираем схему согласно рис.3, ее отличие только в том что шина данных подключена по 4-х проводной линии, т.е. DB4-DB7 подключены, а DB0-DB3 остаются не задействованными. Вывод R/W дисплея подключен на минус, т.к. дисплей у нас является приемником данных.
Код программы проверки знакогенератора LCD приведен ниже.
// Программа проверки знакогенератора LCD #include <avr/io.h> #include <util/delay.h> #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++; // Следующий символ знакогенератора } }