Версия для печати


Программирование LCD - дисплея, на основе микросхемы HD44780
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=1195

Андрей Шишкин
дата публикации 24-01-2006 04:56

Программирование LCD - дисплея, на основе микросхемы HD44780

Микросхема HD44780 - жидкокристаллический дисплейный модуль, который отображает две строки символов. Каждый символ может использовать 5х10 точек матрицы, из которых 5х7 разрешается выбирать программно. Дисплей имеет набор инструкций по выполнению различных функций.

В данном случае для ввода/вывода применяется восьмиразрядная двунаправленная шина данных. Кроме того, для работы дисплея, помимо шины данных, будем использовать - Выбор регистра (RS), Разрешение (Enable), вывод R/W - подключим на минус питания (будем использовать режим только записи в LCD).

Все выводы LPT (их нумерация) даны со стороны компьютера. Можно использовать LPT - кабель, отрезав разъем который подключается непосредственно к принтеру, и припаяв все по схеме. Питание +5V можно взять прямо из компьютера, или подать с внешнего блока питания.

Теперь непосредственно о программировании LPT - порта.

Для того чтобы можно было писать в LPT из под различных операционных систем семейства Windows, будем использовать драйвер LPTWDMIO.sys, предварительно скопировав его в папку Windows\System32\drivers, после чего устанавливаем LPTWDMIO.inf файл (Нажав на нем правой кнопкой мыши, и выбрав пункт меню Установить). Все что было нужно нам для работы, у нас есть. Теперь переходим непосредственно к программированию. Для работы с LPT и HD44780 был создан класс содержащий в себе все необходимое.

type
   THD44780 = class
  private
    CRValue,DRValue:byte;  // Хранят значения регистров LPT
    Lpt: TLptPortConnection; // Указатель на объект LPT для работы
    procedure D0(Data:byte);  //Установка битов порта LPT
    procedure D1(Data:byte);
    procedure D2(Data:byte);
    procedure D3(Data:byte);
    procedure D4(Data:byte);
    procedure D5(Data:byte);
    procedure D6(Data:byte);
    procedure D7(Data:byte);
    procedure Strobe(Data:byte);
    procedure Init(Data:byte);
    procedure AutoLF(Data:byte);
    procedure SelectIn(Data:byte);
    procedure OutData(Data:byte); //Вывод данных в LPT
    procedure ResetLPT(PortNum: integer); //Сброс LPT  в начальное состояние
  public
    BlinkCursor:boolean; //Признак мерцания курсора
    VisibleCursor:boolean; //Признак видимости курсора
    procedure InitializationLPT;  //Инициализация порта
    procedure _Control(Command:byte);  //Вывод управляющего слова для LCD
    procedure _Clear;  //Очистка LCD
    procedure _Home; //Установка курсора на первую позицию, первой строки
    procedure _Line1;  //Выбор строки 1
    procedure _Line2;  //Выбор строки 2
    procedure _Data(Ch:char); //Вывод символа
    procedure _Initialization;  //Инициализация LCD
    procedure _Test;               //Тест LCD
    procedure _MoveCursor(Position:byte); //Переместить курсор в опред. позицию
  end;

В секции USES не забываем подключить LPTIO. В нем содержится реализация обращения к драйверу.

Реализация класса:

{ THD44780 }

procedure THD44780.ResetLPT(PortNum: integer);
begin
 DRValue:=00;  // Сбрасываем регистр DR
 CRValue:=203; // Сбрасываем регистр CR
 if PortNum = 01 then
 begin
  Lpt.WritePort(LPT2,LPT_DATA_REG,DRValue);
  Lpt.WritePort(LPT2,LPT_CONTROL_REG,CRValue);
 end else
 begin
  Lpt.WritePort(LPT3,LPT_DATA_REG,DRValue);
  Lpt.WritePort(LPT3,LPT_CONTROL_REG,CRValue);
 end;
{ В модуле LPTIO под LPT1 понимается параллельный
  порт с базой $3BC, под LPT2 - с базой $378, под
  LPT3 - порт с базой $278. }
end;

procedure THD44780._Clear;
begin
  _Control(1);
end;

procedure THD44780._Control(Command: byte);
begin
  OutData(Command);
  Strobe(1); Init(1);
  Strobe(0); Init(1);
  Strobe(1); Init(1);
end;

procedure THD44780._Data(Ch: char);
begin
 OutData(Ord(ch));
 Strobe(1); Init(0);
 Strobe(0); Init(0);
 Strobe(1); Init(0);
end;

procedure THD44780._Home;
begin
 _Control(2);
end;

procedure THD44780._Initialization;
var ILCD:byte;
begin
 _Control(16+32); //8 бит данных, 2 строки, 5*7 точек
 _Control(16+32);
 _Control(16+32);
 _Control(16+32+8+4);
 ILCD:=8+4;
 if BlinkCursor then ILCD:=ILCD+1;  //1 - курсор мигает
 if VisibleCursor then ILCD:=ILCD+2; //2 - включение курсора
 _Control(ILCD);

 _Clear;
 _Control(4+2+0);
end;

procedure THD44780._Line1;
begin
  _Control(128);
end;

procedure THD44780._Line2;
begin
 _Control(128+64);
end;

procedure THD44780._Test;
var s,s1:string;
    i:byte;
begin
  s:='Stroka 1';
  s1:='Stroka 2';
  _Line1;
  for i:=1 to length(s) do
     _Data(s[i]);
  _Line2;
  for i:=1 to length(s1) do
     _Data(s1[i]);
end;

procedure THD44780._MoveCursor(Position: byte);
begin
  _Control(128+Position);
end;

{ THD44780 }

procedure THD44780.AutoLF(Data: byte);
begin
CRValue:=Lpt.ReadPort(LPT2,LPT_CONTROL_REG);
  if Data=1 then
   begin
     CRValue:=CRValue and (255-2);
   end
    else
     CRValue:=CRValue or 2;
  Lpt.WritePort(Lpt2,LPT_CONTROL_REG,CRValue);
end;

procedure THD44780.D0(Data: byte);
begin
 DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-1);
   end
    else
     DRValue:=DRValue or 1;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D1(Data: byte);
begin
   DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-2);
   end
    else
     DRValue:=DRValue or 2;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D2(Data: byte);
begin
   DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-4);
   end
    else
     DRValue:=DRValue or 4;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D3(Data: byte);
begin
  DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-8);
   end
    else
     DRValue:=DRValue or 8;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D4(Data: byte);
begin
   DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-16);
   end
    else
     DRValue:=DRValue or 16;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D5(Data: byte);
begin
  DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-32);
   end
    else
     DRValue:=DRValue or 32;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D6(Data: byte);
begin
   DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-64);
   end
    else
     DRValue:=DRValue or 64;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.D7(Data: byte);
begin
  DRValue:=Lpt.ReadPort(LPT2,LPT_DATA_REG);
  if Data=0 then
   begin
     DRValue:=DRValue and (255-128);
   end
    else
     DRValue:=DRValue or 128;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.Init(Data: byte);
begin
 CRValue:=Lpt.ReadPort(LPT2,LPT_CONTROL_REG);
  if Data=1 then
   begin
     CRValue:=CRValue and (255-4);
   end
    else
     CRValue:=CRValue or 4;
  Lpt.WritePort(Lpt2,LPT_CONTROL_REG,CRValue);
end;

procedure THD44780.OutData(Data: byte);
begin
  DRValue:=Data;
  Lpt.WritePort(Lpt2,LPT_DATA_REG,DRValue);
end;

procedure THD44780.SelectIn(Data: byte);
begin
 CRValue:=Lpt.ReadPort(LPT2,LPT_CONTROL_REG);
  if Data=1 then
   begin
     CRValue:=CRValue and (255-8);
   end
    else
     CRValue:=CRValue or 8;
  Lpt.WritePort(Lpt2,LPT_CONTROL_REG,CRValue);
end;

procedure THD44780.Strobe(Data: byte);
begin
 CRValue:=Lpt.ReadPort(LPT2,LPT_CONTROL_REG);
  if Data=1 then
   begin
     CRValue:=CRValue and (255-1);
   end
    else
     CRValue:=CRValue or 1;
  Lpt.WritePort(Lpt2,LPT_CONTROL_REG,CRValue);
end;

procedure THD44780.InitializationLPT;
var msg: AnsiString;
begin
 Lpt:=TLptPortConnection.Create; // Создаем объект связи с портом
 if not Lpt.Ready then           // Если объект не готов, покажем
 begin                           // код ошибки и закроем программу
  msg:='Ошибка при создании объекта Lpt, код = ' + IntToStr(GetLastError());
  Application.MessageBox(PChar(msg),'ERROR',MB_OK);
  Application.Terminate;
 end;
 ResetLPT(1); //LPT 1
end;

Запись данных в LCD производится по отрицательному фронту на входе Enable.

Данный перепад описывается следующим образом:
Strobe(1);  Strobe(0);  Strobe(1);  

Для указания вида операции над LCD используется вход RS. По документации: при логической 1, вывод данных (текст), при 0 - управляющее слово.

Команды LCD дисплея приведены в таблице:

Данный пример был испытан на LCD: LE-1602T.

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

Наиболее полная документация: HD44780.

К материалу прилагаются файлы: