Печать

Подключение LCD(HD44780) к микроконтроллерам AVR

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 23
ПлохоОтлично 
 

В этой статье приведен пример подключения LCD индикатора к микроконтроллеру AVR, а именно ATmega8. При выборе LCD cледует различать обычные многопозиционные LCD серии ИЖКЦ, модули на их основе с микросхемой HT1611 и алфавитно-символьные LCD с встроенным контроллером. Именно последние и относят к наиболее перспективным изделиям. В подтверждение тому множество фирм в мире, специализирующихся на выпуске подобной продукции. Крупнейшие из них находятся в Тайване, Китае, Японии, США.

Среди параметров, отличающих одни LCD от других, выделяется марка внутреннего контроллера. В дальнейшем будут рассматриваться только модели, совместимые с контроллером HD44780 (фирма Hitachi) и его аналогами, например, KS0066 (фирма Samsung), SED1278
(фирма Epson), ST7066 (фирма Sitronix). Таких изделий на отечественном рынке подавляющее большинство, да и в любительских конструкциях они стали стандартом "де-факто".

При покупке LCD надо поинтересоваться следующими моментами:

поддерживается ли система команд HD44780 ("Да");
имеется ли русификация знакогенератора с выводом больших и малых букв ("Да");
однополярное или двухполярное требуется питание ("Однополярное +5 В");
имеется ли подсветка (если "Да", то нужна светодиодная, а не электролюминесцентная);
сколько символов и строк отображается на экране LCD ("8x1",
"8x2", "16x1", "16x2", "20x2", "20x4" и т.д.).

Внутреннее устройство LCD

Рисунок 1. Подключение LCDДостоинством символьных многострочных LCD является то, что заботу о подаче требуемых напряжений на массив "ЖК-конденсаторов" берет на себя встроенный управляющий контроллер. На рис.1 показана структурная схема типового LCD с организацией 16х2, которая идентична для всех моделей независимо от фирмы-изготовителя. Основу составляет специализированный контроллер, обычно выполненный в виде одной или двух микросхем-"капелек", реже - в виде фирменной SMD-микросхемы. По назначению выводов и системе команд он совпадает с родоначальником серии - HD44780. Общепринятое название таких микросхем "Dot Matrix Liquid Crystal Display Controller/Driver", из чего следует их двойная функция - контроллер управляет интерфейсом, а драйвер "зажигает" сегменты.

Контроллер синхронизируется внутренним RC-генератором G1, имеющим частоту 250 ±50 кГц. Напряжение подсветки подается через выводы А и К на светодиоды, которые освещают ЖК-панель с торца или обратной стороны корпуса. Светодиоды включены матрицей и соединены параллельно-последовательно. В связи с этим напряжение подсветки довольно высокое 4,0...4,2 В.

Назначение и нумерация всех внешних выводов LCD унифицированы (рис.2). Это не зависит от количества строк и символов, будь то "8x1" или "16x2". Даже контакты светодиодной подсветки 15, 16 имеются на всех LCD, хотя при ее физическом отсутствии они будут просто "висеть в воздухе".

Небольшой нюанс. На печатной плате LCD порядок нумерации контактных площадок отличается от модели к модели. Например, встречаются следующие варианты: слева направо 1-16, справа налево 16-1, вперемежку 15, 16, 1-14. Подсказку следует искать визуально по отмаркированным цифрам на печатной плате. Контакты 15, 16 обычно дублируются еще одной парой контактов с маркировкой А и К соответственно. Электрически они соединены параллельно.

Конструктивно выводы могут располагаться сверху, снизу или на боковой стороне платы LCD. Это не суть важно, ведь соединяться с изделием они будут жгутом проводов длиной до 10 см. Крепление LCD производится винтами через 4 угловых отверстия.

Электрический интерфейс состоит из трех шин:

DB0-DB7 шина данных;
RS, R/W, E шина управления;
VCC, GND, Vo, A, K шина питания.

Рисунок 2. Назначение выводов LCD

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

Типовая схема подключения LCD к МК показана на рис.3. Именно она и будет использоваться для первой тестовой проверки LCD с выведением на экран знаменитой фразы "Hello, world!" ("Здравствуй, мир!"). Кнопка SB1 осуществляет начальный сброс. Переменным резистором R2 регулируют контрастность изображения. Его сопротивление непринципиально и может меняться от 5 до 20 кОм.

Рисунок 3. Схема подключения LCD

Рис. 3

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

Отрегулировать R2 следует на перегибе характеристики, как правило, с потенциалом ближе к общему проводу, когда слабо видны все точки знакомест на LCD. Неправильная установка контрастности может привести к ложному выводу о дефекте индикатора, хотя все, что надо сделать, это покрутить движок резистора.

Управляющая программа хранится в МК DD1. Чтобы облегчить ее составление, здесь и в дальнейшем приняты некоторые упрощения.

Во-первых, LCD будет работать только на прием информации по всем 11 соединительным линиям шины данных и управления.

Во-вторых, экран LCD считается жестко привязанным к начальной позиции с фиксированными адресами знакомест.

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

Программное управление LCD

Поскольку внутри LCD находится свой собственный контроллер со своей разветвленной системой команд, то задача упрощается. Две такие мощные и интеллектуальные микросхемы, как HD44780 и ATmega8, смогут быстро между собой "договориться" на машинном языке. Труд программиста заключается в том, чтобы "объяснить" контроллерам правила общения и установить протокол соединения.

Таблица 3

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

Рисунок 4. Распределение адресов на верхней и нижней строках экрана

Рисунок 4

Различают команды прямого и косвенного действия. Первые из них занимают адреса 0x01-0x3F и не требуют передачи данных. За вторыми (диапазон выше 0x3F) обязательно следует передача одного или нескольких байтов информации. Для примера на рис.5 показаны временные диаграммы выполнения команды 0x80 "Установка курсора в первое знакоместо верхней строки экрана" и индикация в нем цифры "4" пересылкой кода данных 0x34.

Рисунок 5. Временные диаграммы выполнения команды

Рисунок 5

Формировать диаграммы, показанные на рис.5, должен МК с учетом задержек из табл.3, необходимых контроллеру LCD на выполнение команд. Для повышения устойчивости работы экономить на задержках не надо. По крайней мере, при отладке программы они должны быть достаточно большими.

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

Далее показана Си-программа для тестовой проверки LCD по схеме, собранной на рис.3.

// Тестовая программа для LCD, шина 8 бит
#include <avr/io.h>
#include <util/delay.h>
 
#define RS PC0 // RS подключаем к PC0 микроконтроллера
#define EN PC2 // EN подключаем к PC2 микроконтроллера
 
// Функция записи команды в LCD
void lcd_com(unsigned char p)
{
PORTC &= ~(1 << RS); // RS = 0
PORTC |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD = p; // Вывод команды на шину DB0-7 LCD
_delay_us(100); // Длительность сигнала EN
PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100); // Пауза для выполнения команды
}
 
// Функция записи данных в LCD
void lcd_dat(unsigned char p)
{
PORTC |= (1 << RS)|(1 << EN); // RS = 1, EN = 1 (начало записи команды в LCD)
PORTD = p; // Вывод команды на шину DB0-7 LCD
_delay_us(100); // Длительность сигнала EN
PORTC &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100); // Пауза для выполнения команды
}
 
// Функция инициализации LCD
void lcd_init(void)
{
DDRC |= (1 << PC2)|(1 << PC1)|(1 << PC0); // PC2-0 выходы
PORTC = 0x00; // Лог. нули на выходе 
DDRD = 0xFF; // PD7-0 выходы
PORTD = 0x00; // Лог. нули на выходе
lcd_com(0x08); // Полное выключение дисплея
lcd_com(0x38); // 8 бит 2 строки
_delay_us(100);
lcd_com(0x38); // 8 бит 2 строки
_delay_us(100);
lcd_com(0x38); // 8 бит 2 строки
lcd_com(0x01); // Очистка дисплея
_delay_us(100);
lcd_com(0x06); // Сдвиг курсора вправо
_delay_ms(10);
lcd_com(0x0C); // Курсор невидим
}
 
// Основная программа
int main (void)
{
lcd_init(); // Инициализация дисплея
lcd_dat('H'); // Выводим символы на экран
lcd_dat('e');
lcd_dat('l');
lcd_dat('l');
lcd_dat('o');
lcd_dat(' ');
lcd_dat('w');
lcd_dat('o');
lcd_dat('r');
lcd_dat('l');
lcd_dat('d');
lcd_dat('!');
while(1)
{
// Больше ничего не делаем
}
}

Функции "lcd_com" и "lcd_dat" формируют соответственно левую и правую половину временных диаграмм, показанных на рис.5.

Без процедуры инициализации ни один LCD работать не будет. Это самая важная часть листинга. Именно на процессе инициализации часто "спотыкаются" начинающие программисты. Дело в том, что в разных источниках приводятся разные варианты последовательностей команд инициализации и не все из них гарантированно будут работать с конкретным LCD.

Наиболее общая процедура инициализации приведена в DATASHEET на HD44780. Функция "lcd_init" в целом повторяет ее с тем отличием, что команда полного выключения дисплея 0х08 поставлена первой, чтобы при включении питания на экране не появлялся "мусор". Здесь нет ограничений против экспериментов, главный критерий - практика.

После выполнения инициализации курсор устанавливается в крайнее слева положение в верхней строчке экрана. Следовательно, первая буква "H" будет выведена именно в это знакоместо. Далее курсор автоматически переходит на одну позицию вправо и следующая команда выведет сюда букву "e" и т.д.

Комментарии  

0 #21 Артурио 21.06.2014 21:06
Здравствуйте, объясните пожалуйста почему не надо подключать библиотеку в заголовке?
Сообщить модератору
0 #22 AntonChip 22.06.2014 09:44
Цитирую Артурио:
Здравствуйте, объясните пожалуйста почему не надо подключать библиотеку в заголовке?

Функций для работы с LCD не очень много, поэтому имеет смысл записать все в одном файле
Сообщить модератору
+1 #23 loki amorf 27.08.2014 19:47
Здравствуйте.
В Протеусе схема не работает.
Требуется указать частоту задающего генератора для верной работы фунции delay.
При компиляции по этому поводу возникает Warning.
Например как-то так - #define F_CPU 1000000UL.

Из-за этого собранная в Протеусе схема не заработала - пишет о том что контроллер ЛСД принял данные во время своей занятости, наверняка неправильно отрабатываются задержки.
Под какую частоту разрабатывался пример?
Сообщить модератору
-1 #24 Roman-1-1 17.03.2015 20:56
Скиньте бібліотеки будласка
Сообщить модератору
0 #25 AntonChip 17.03.2015 22:19
Цитирую Roman-1-1:
Скиньте бібліотеки будласка

Все что есть в статье
Сообщить модератору
-1 #26 Roman-1-1 18.03.2015 10:01
Я закинув цю програму у Atmel Studio 6.0 все нормально. Но коли запрограмував по ній Lsd 1602A нічого не вивелося. У чому проблема???
Сообщить модератору
0 #27 Roman-1-1 18.03.2015 16:09
Я закинув цю програму у Atmel Studio 6.0 все нормально. Но коли запрограмував по ній Lsd 1602A нічого не вивелося. У чому проблема???
Сообщить модератору
0 #28 Jk 30.05.2015 20:14
Скажите, есть ли блок-схема для данной программы? Если есть, скиньте пожалуйста
Сообщить модератору
0 #29 Вилен 17.06.2015 22:59
Скомпилировал код для Atmega16A и опробовал на дисплее HY-1602F-801
Программа не работает, то есть не выводятся на дисплей символы
В чем может быть проблема?
Сообщить модератору
0 #30 AntonChip 18.06.2015 08:53
Скорее всего нужно изменить функцию инициализации
Сообщить модератору
+3 #31 NIK123 30.07.2015 21:14
1 добавьте значение Код:DDRC |= (1 << PC2) | (1<<PC1) | (1 << PC0);
пропустили (1
Сообщить модератору
0 #32 NIK123 30.07.2015 21:15
35 строка yна PORTD исправить
Сообщить модератору
0 #33 Egor 10.08.2015 12:23
У меня возникла такая проблема. Можете подсказать?
Символы по адресам xxxx xx00 — xxxx xx11 воспринимаются как xxxx xx01
Что это может быть?

Мой дисплей WEH001602AGPP5N00001
Плата stm32f103
Сообщить модератору
0 #34 Иван123 11.09.2015 23:07
а как бы выглядела табличка "распределения адресов" (рис.4) только для 4х(4на20) строчного дисплея. В даташитах даже на двухстрочный дисплей, найти такую табличку не могу(для двухстрочного пользуюсь вашей). Вы сами ее составили?
Сообщить модератору
0 #35 Иван123 11.09.2015 23:25
нашел вот здесь web.alfredstate.edu/.../... описание адресов но они не сходятся с вашей таблицей?
Сообщить модератору
0 #36 AntonChip 12.09.2015 17:14
Цитирую Иван123:
а как бы выглядела табличка "распределения адресов" (рис.4) только для 4х(4на20) строчного дисплея.
На этом рисунке показаны команды, т.е если адрес знакоместа 0x00, то для перехода на этот адрес команда будет 0x00+0x80 = 0x80, если адрес 0x40, то команда будет 0x40+0x80=0xC0
Сообщить модератору
0 #37 ivanovevgenij02 13.12.2015 03:55
как сделать бегущую строку к примеру из 15-20 букв и при этом добавить несколько условий (если на ножке такой-то 1, то на мониторе один текст, если на ножке такой-то 1, то другой текст)? если можно с примером, заранее спасибо.
Сообщить модератору
0 #38 bigrat911 07.10.2016 20:45
Антон, исправьте пожалуйста ошибку в Вашем коде. Строка 32 у Вас:
Код:DDRC |= (1 << PC2)|(1 << PC0); // PC3-0 выходы
А должно быть:
Код:DDRC |= (1 << PC2)|(1 << PC1)|(1 << PC0); // PC3-0 выходы
Без установки РС1 в единицу экран не оживает. Новичку очень трудно понять, где ошибка. Спасибо!
Сообщить модератору
0 #39 AntonChip 08.10.2016 10:39
Ошибку исправил, спасибо
Сообщить модератору

Рекомендуем посмотреть