За все время увлечения электроникой мне довелось пользоваться ЖКД от нескольких производителей - DataVision, WINSTAR, Uniworld Technology Corp. Они отличались типом контроллера, количеством выводов и длинною строк, но при этом все имели одинаковую схему подключения, систему команд и обслуживались одной и той же программой со стороны микроконтроллера. Поэтому, хотя речь сейчас пойдет о дисплее WH0802A фирмы WINSTAR, все ниже сказанное применимо к символьным ЖК-дисплеям и других фирм.
Учебный курс. Подключение lcd к микроконтроллеру. Получение первых результатов.
29/10/2009 - 21:00
Pavel Bobkov
Итак, подключаем дисплей WH0802A-YGH-CT к микроконтроллеру
WH0802A – двухстрочный символьный дисплей на 8 знакомест со встроенным управляющим контроллером KS0066.Разбираем назначение выводов дисплея.
У некоторых дисплеев есть два дополнительных вывода – выводы подсветки +LED и –LED. Причем если выводы есть – это еще не означает что есть и подсветка. Как и наоборот. У моего дисплея подсветка есть, а выводов управления нет.
По умолчанию подсветка у дисплея WH0802A-YGH-CT отключена. Чтобы ее включить, нужно проделать парочку нехитрых манипуляций, а именно – установить две перемычки и впаять токоограничительный резистор (смотри на фотке RK, JF и RA соответственно).
Схема подключения дисплея
Это типовая схема включения символьных LCD. Схему управления подсветкой дисплея мы задействовать не будем, но я ее на всякий случай нарисовал. Начальный код
Начальный код
Подав питание на схему, нужно покрутить регулятор контраста (резистор R1). Если на экранчике появилась верхняя строка, значит, он живой и самое время приступать к написанию кода. На начальном этапе мы будем использовать 8-ми разрядную шину. Чтобы получить первые результаты, нам понадобится написать две функции – функцию записи данных и функцию записи команд. Отличаются они всего одной строчкой – когда записываются данные, сигнал RS должен быть 1, когда записывается команда, RS должен быть 0. Функции чтения мы пока использовать не будем, поэтому сигнал R/W будет всегда 0.
Цикл записи для 8-ми разрядной шины выглядит следующим образом:
1. Установить RS (0 - команда, 1 – данные)
2. Вывести значение байта данных на шину DB7…DB0
3. Установить E=1
4. Программная задержка 1
5. Установить E=0
6. Программная задержка 2
Контроллер символьного ЖК-дисплея, не обладает бесконечным быстродействием, поэтому между некоторыми операциями используются программные задержки. Первая нужна для удержания на некоторое время строб сигнала, вторая, для того чтобы контроллер успел записать данные или выполнить команду. Величины задержек всегда приводятся в описании на контроллер дисплея и нужно всегда выдерживать хотя бы их минимальное значение, в противном случае неизбежны сбои в работе контроллера.
Вообще у контроллера дисплея есть так называемый флаг занятости – BF. Если флаг в 1 – контроллер занят, если в 0 – свободен. Вместо второй программной задержки можно читать флаг занятости и проверять, когда контроллер дисплея освободится. Но поскольку мы хотим быстро получить первые результаты, с флагом занятости будем разбираться потом.
//подключаем символьный ЖК-дисплей к AVR
#include <ioavr.h>
#include <intrinsics.h>
//порт к которому подключена шина данных ЖКД
#define PORT_DATA PORTD
#define PIN_DATA PIND
#define DDRX_DATA DDRD
//порт к которому подключены управляющие выводы
#define PORT_SIG PORTB
#define PIN_SIG PINB
#define DDRX_SIG DDRB
//номера выводов микроконтроллера
//к которым подключены управляющие выводы ЖКД
#define RS 5
#define RW 6
#define EN 7
//макросы для работы с битами
#define ClearBit(reg, bit) reg &= (~(1<<(bit)))
#define SetBit(reg, bit) reg |= (1<<(bit))
#define F_CPU 8000000
#define _delay_us(us) __delay_cycles((F_CPU / 1000000) * (us));
#define _delay_ms(ms) __delay_cycles((F_CPU / 1000) * (ms));
//функция записи команды
void LcdWriteCom(unsigned char data)
{
ClearBit(PORT_SIG, RS); // устанавливаем RS в 0
PORT_DATA = data; // выводим данные на шину
SetBit(PORT_SIG, EN); // устанавливаем Е в 1
_delay_us(2);
ClearBit(PORT_SIG, EN); // устанавливаем Е в 0
_delay_us(40);
void LcdWriteCom(unsigned char data)
{
ClearBit(PORT_SIG, RS); // устанавливаем RS в 0
PORT_DATA = data; // выводим данные на шину
SetBit(PORT_SIG, EN); // устанавливаем Е в 1
_delay_us(2);
ClearBit(PORT_SIG, EN); // устанавливаем Е в 0
_delay_us(40);
}
//функция записи данных
void LcdWriteData(unsigned char data){
SetBit(PORT_SIG, RS); //устанавливаем RS в 1
PORT_DATA = data; //выводим данные на шину
SetBit(PORT_SIG, EN); //устанавливаем Е в 1
_delay_us(2);
ClearBit(PORT_SIG, EN); // устанавливаем Е в 0
_delay_us(40);
}
}
int main( void )
{
while(1);
return 0;
}
Здесь нет сложных мест, все должно быть понятно. Идем дальше.
Любой ЖК-дисплей перед использованием нужно инициализировать. Процесс инициализации обычно описан в datasheet`е на контроллер дисплея. Но даже если там и нет информации, последовательность, скорее всего, будет такая.
2. Ждем >40 мс
3. Подаем команду Function set
DL – бит установки разрядности шины
0 – 4 разрядная шина, 1 – 8 разрядная шина
N – бит установки количества строк дисплея
0 – однострочный режим, 1 – двухстрочный режим
F – бит установки шрифта
0 – формат 5*8, 1 – формат 5*11
* - не важно что будет в этих битах
4. Подаем команду Display ON/OFF
D – бит включения/выключения дисплея
0 – дисплей выключен, 1 – дисплей включен
C – бит включения/выключения курсора
0 – курсор выключен, 1 – курсор включен
B – бит включения мерцания
0 – мерцающий курсор включен, 1 – мерцающий курсор выключен
5. Подаем команду Clear Display
6. Ждем > 1,5 ms
7. Подаем команду Entry Mode Set
I/D – порядок увеличения/уменьшения адреса DDRAM(ОЗУ данных дисплея)
0 – курсор движется влево, адрес уменьшается на 1, 1 – курсор движется вправо, адрес увеличивается на 1
SH – порядок сдвига всего дисплея
0 – сдвига нет, 1 – сдвиг происходит согласно сигналу I/D – если он 0 – дисплей сдвигается вправо, 1 – дисплей сдвигается влево
Для нашего примера функция инициализации будет выглядеть так
//функция инициализации
void InitLcd(void)
{
//настраиваем порты ввода/вывода
DDRX_DATA = 0xff;
PORT_DATA = 0xff;
DDRX_SIG = 0xff;
PORT_SIG |= (1<<RW)|(1<<RS)|(1<<EN);
ClearBit(PORT_SIG, RW);
_delay_ms(40);
LcdWriteCom(0x38); //0b00111000 - 8 разрядная шина, 2 строки
LcdWriteCom(0x0f); //0b00001111 - дисплей, курсор, мерцание включены
LcdWriteCom(0x01); //0b00000001 - очистка дисплея
_delay_ms(2);
LcdWriteCom(0x06); //0b00000110 - курсор движется вправо, сдвига нет
}
Теперь у нас есть необходимый минимум, чтобы начать работу с дисплеем. Выведем на него слово "Test."
//собственно наша программа
int main( void )
{
InitLcd();
LcdWriteData('T');
LcdWriteData('e');
LcdWriteData('s');
LcdWriteData('t');
LcdWriteData('.');
while(1);
return 0;
}
Первые результаты мы получили. Доводить программу до ума будем в следующих статьях.
Файлы
Tagged under
Comments
KS0066 на HD44780 .
Т.е. применимо ли выше сказанное для
HD44780 .
Если по делу, то в файле исходника для IAR для соответствия прогаммы и схемы неибходимо заменить соответствующую часть на:
#define RS 4
#define RW 5
#define EN 6
Проверенно во Proteus
"//номера выводов микроконтроллер а
//к которым подключены управляющие выводы ЖКД"
Как в комментарии указано "номера выводов", так и определено: RS прицеплен к выводу 5 (корпус DIP), вот и определено
#define RS 5
был бы использован корпус TQFP, было бы
#define RS 44
___
По-моему если бы комментарий был:
"//номера битов порта микроконтроллер а
//к которым подключены управляющие выводы ЖКД", то и было бы
#define RS 4
или
#define RS PB4
___
Это кстати не только для IAR, а во всех примерах эта ошибка, и в html (2010-10-20)
___
С уважением Александр.
За статьи спасибо.
Вс' так красиво и доступно расписано.
Только вот здеся ошибочка есть:
"3. Установить E=0
4. Программная задержка 1
5. Установить E=1
6. Программная задержка 2"
наоборот же надо ведь, во всяком случае у вас в коде наоборот написано, сначала установить, потом обнулить
MTC-16201x (mega16, кварц 11.0592). Были проблемы с отображением,
терялись символы, нарушалась последовательно сть, но после установки флага BF, все пришло в норму (подобрать задержку не получилось).
Подскажите, как русифицировать текст?
Спасибо за статьи.
Исправь здесь пожалуйста
1.Установить RS (0 - данные, 1 – команда)
#define PORT_DATA PORTC
#define PIN_DATA PINC
#define DDRX_DATA DDRC
"С" если на схеме четко показано что двунаправленная шина подключена к порту "D"?
пробывал юзать HDM08216L - он вроде на HD44780 ... результат дальше появления второй строчки не ушел. Уже даже сам написал весь код используя даташит. И не получилось ничего с WH1602L-DYK-CTT , получил на экране появление кирилицы в место S - З, t-г, f-Л... если слать более трех символов курсор начинает бегать по полю... Наверно мне дохлые стекляшки попались :(
//номера выводов микроконтроллер а
//к которым подключены управляющие выводы ЖКД
#define RS 5
#define RW 6
#define EN 7
Не номера выводов микроконтроллер а , а номера порта!!!
Правильно так:
#define RS 4
#define RW 5
#define EN 6
Иначе не работает. Проверено!
Нельзя код сделать для 4х портов дата?!
Можно ли использовать тактовую частоту контроллера от внутреннего генератора 1МГц?
Пробовал подключить индикатор к тем же портам контоллера ATmega8 - не работает. В тексте кода (из примера для CodeVision) поменял первую строку на #include . Нужно ли еще что нибудь менять?
совместно с этим статя будет понятна всем
http://www.geocities.com/dinceraydin/djlcdsim/djlcdsim.html
Code:
/*позиционирование курсора*/
#define LCD_Goto(x,y) LCD_WriteCom(((((y)& 1)*0x40)+((x)& 7))|128)
RSS feed for comments to this post