OK, Hier komtie dan. Ik zal de code afwisselen met commentaar. Dat moet een idee geven van de code. De code is oorspronkelijk bedoeld voor een KS0108-controller voor een Grafische LCD.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
| const dataport=$0378;
const controlport=$037A;
const
LCD_Enable=1;
LCD_CS2=0;
LCD_CS1=6;
LCD_Inst=8;
const
DISPLAY_ON=$3f;
DISPLAY_OFF=$3e;
DISPLAY_STARTLINE=$c0;
DISPLAY_PAGE_SET=$b8;
DISPLAY_COLUMN_SET=$40; |
Dit zijn de hex-codes van een aantal signalen en commando's. Deze kun je uit je eigen datasheet halen. De DISPLAY_* commando's worden uiteindelijk allemaal naar de data-poort gestuurd. De LCD_* constanten worden gecombineerd naar de controlpoort gestuurd. Een aantal van de lijnen op de controlport zijn geinverteerd. Dat is in deze constanten reeds meegenomen.
Delphi:
1
2
3
4
5
6
7
8
9
| procedure delay;
var start,finish,req:int64;
begin
Queryperformancecounter(start);
req:=start+delaycounts;
repeat
Queryperformancecounter(finish);
until finish>req;
end; |
Met het gebruik van de API-functie QueryPerformanceCounter kun je een delay krijgen die beter instelbaar is dan de standaard sleep. sleep heeft een minimum van 1ms, terwijl in de specs veel kortere tijden besproken worden. Een delay van 1 microseconde is vaak al voldoende.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
| procedure SendLCDCommand(value,CS:byte);
begin
if ProcLoaded then
begin
writeIO(controlport,(LCD_ENABLE or CS or LCD_Inst));
writeIO(dataport,value);
writeIO(controlport,(CS or LCD_inst));
writeIO(controlport,(LCD_ENABLE or CS OR LCD_inst));
writeIO(dataport,0);
end;
end; |
Bovenstaande procedure stuurt een commando naar de LCD. De procedure writeIO die aangeroepen wordt, is de procedure uit DLPORTIO.
Let op de waarde die meegegeven wordt. CS is bij mijn LCD een select tussen twee controllers en zul jij dus waarschijnlijk niet hoeven te gebruiken.
In regel 5 wordt de enable-flag hoog gezet, samen met het instructie-bit en de controller-selectie. Daarna wordt de instructie naar de datapoort gestuurd.
regel 7 en 8 doen niets anders dan de enable-flag laag en weer hoog maken, terwijl de rest van de bits gelijk blijft.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| procedure SendLCDData(values:array of byte);
var i:integer;
CS:byte;
begin
if ProcLoaded then
begin
for i:=low(values) to high(values) do
begin
if CurrentColumn>63 then CS:=LCD_CS2 else CS:=LCD_CS1;
writeIO(controlport,(LCD_ENABLE or CS));
delay;
writeIO(dataport,values[i]);
delay;
writeIO(controlport,CS);
delay;
writeIO(controlport,(LCD_ENABLE or CS));
inc(currentColumn);
end;
end;
end; |
Bovenstaande procedure is vergelijkbaar met de SendLCDCommand-procedure, behalve dan dat deze de data stuurt. Let weer op regel 10,12,14,16. Enable hoog, data sturen, enable laag, enable hoog.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| procedure SetColumn(y:byte);
begin
CurrentColumn:=y;
if y<64 then
begin
SendLCDCommand(DISPLAY_COLUMN_SET or (y and 63),LCD_CS1);
SendLCDCommand(DISPLAY_COLUMN_SET or 0,LCD_CS2);
end
else
begin
SendLCDCommand(DiSPLAY_COLUMN_SET or 63,LCD_CS1);
SendLCDCommand(DISPLAY_COLUMN_SET or ((y-64) and 63),LCD_CS2);
end;
end;
procedure setpage(x:byte);
begin
SendLCDCommand (DISPLAY_PAGE_SET or x,LCD_CS1);
SendLCDCommand (DISPLAY_PAGE_SET or x,LCD_CS2);
end;
procedure setStartLine(line:byte);
begin
SendLCDCommand (DISPLAY_STARTLINE or (line and 63),LCD_CS1);
SendLCDCommand (DISPLAY_STARTLINE or (line and 63),LCD_CS2);
end; |
Bovenstaande procedures zijn in feite niets meer dan wrappers om LCD-instructies heen. Alle LCD-instructies kan je uit je datasheet halen.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
| procedure TForm1.FormCreate(Sender: TObject);
var Q:int64;
begin
MyHandle:=LoadLibrary('DLPortio.dll');
If MyHandle<>0 then
begin
@WriteIO:=GetProcAddress(MyHandle,'DlPortWritePortUchar');
ProcLoaded:=(@writeIO<>nil);
end;
QueryPerformanceFrequency(Q);
delaycounts:=Q div 1000000;
end; |
Als laatste een stukje uit mn Create-procedure. Als eerste wordt hier gepoogd om de juiste DLL te laden en de procedure writeIO te koppelen aan de DLL-functie DLPortWriteUChar. Als dat niet lukt is procloaded false, zodat er in dat geval nooit een writeIO wordt aangeroepen, hetgeen tot ongewenste resultaten zal leiden.
Als laatste wordt via QueryPerformanceFrequency de delay bepaald. Die Frequency is in mijn geval ongeveer 3.5 miljoen. Door te delen door 1 miljoen zal dit uiteindelijk een delay van ongeveer 1 microseconde opleveren. In eerste instantie had ik geen enkele delay ingebouwd, wat tot gevolg had dat enkele pixels niet getoond werden. Mocht zoiets dus het geval zijn, dan moetde delay iets langer.
Delphi:
1
2
3
4
| procedure TForm1.FormDestroy(Sender: TObject);
begin
If Myhandle<>0 then FreeLibrary(MyHandle);
end; |
Bijna vergeten, achteraf de DLL natuurlijk weer vrijgeven