Based on the sample code kindly posted in this thread, here is a fully debugged example of an AvrCo AtMega128 working with an I2C 20x4 LCD display shown above.
program TWIDisplay;
{$NOSHADOW}
{ $WG} {global Warnings off}
Device = mega128, VCC = 5.0;
{ $BOOTRST $0F000} {Reset Jump to $0F000}
Define_Fuses
// Override_Fuses;
NoteBook = A;
Supply = 5.0, 100;
LockBits0 = [];
FuseBits0 = [];
FuseBits1 = [SPIEN, JTAGEN, OCDEN];
FuseBits2 = [];
import SysTick, SerPort, TWImaster, LCDport;
from System import;
define
ProcClock = 16000000; {Hertz}
SysTick = 10; {msec}
StackSize = $0100, iData;
FrameSize = $0100, iData;
LCDport = LcdUserPort;
LCDtype = 44780; {66712}
LCDrows = 4; {4 rows}
LCDcolumns = 20; {20 chars per line}
TWIpresc = TWI_BR400;
SerPort = 19200, Stop2; {Baud, StopBits|Parity}
RxBuffer = 32, iData;
TxBuffer = 60, iData;
implementation
{$IDATA}
{--------------------------------------------------------------}
{ Type Declarations }
type
{--------------------------------------------------------------}
{ Const Declarations }
const
// this example uses the PCF8574 as an 8bit I/O port to the display
// the display is operated in 4bit mode
// the display control lines are connected to PCF8574 0..3
// the display data lines are connected to PCF8574 4..7
// Belegung des PCF8574(a)
// Achtung: es gibt wohl auch Displays die anders belegt sind !!
// HiNibble = Daten
// LowNibble = Steuerleitungen
En : byte = %0100;// Enable bit
Rw : byte = %0010;// Read/Write bit : 0= write
Rs : byte = %0001;// Register select bit : 0=Instruction Register
BL : byte = %1000;// Backlight on
// PCF8574 I2C address alle Address-Leitungen offen
LcdAdr : byte = $27;
// PCF8574A I2C address alle Address-Leitungen offen
// LcdAdr : byte = $3F;
{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
led[@portB, 5] : bit;
Backlight : byte;
t1000ms : Systimer;
cnt : byte;
{--------------------------------------------------------------}
{ functions }
procedure InitPorts;
begin
portB := %00000000; //nc,nc,led,nc,nc,nc,nc,nc
ddrB := %00100000;
portC := %00110000;
ddrc := %00110000;
end;
// pulse En mit Verzögerungen
procedure pulseEn(data : byte);
begin
TWIout(LcdAdr, data or En);
udelay(1);
TWIout(LcdAdr, data and not (En));
udelay(50);
end;
// schreibe 4 Bit
// Daten und Steuerleitungen stehen in data
procedure write4bits(data : byte);
begin
data := data or Backlight;
TWIout(LcdAdr, data);
pulseEn(data);
end;
// lese 4 Bit
// Daten und Steuerleitungen stehen in data
// gelesene Daten stehen im hiNibble
function read4bits(data : byte) : byte;
var
ip : byte;
begin
data := $F0 or data or Backlight;
TWIout(LcdAdr, data); //
TWIout(LcdAdr, data or En); // En auf 1
udelay(5);
TWIinp(LcdAdr, ip); // HighNibble einlesen
TWIout(LcdAdr, data); // En zurückauf 0
udelay(20);
return(ip); // die Daten stehen im HiNibble
end;
// initialiseire LCD
procedure init_lcd;
begin
mdelay(50);
write4bits($30);
mdelay(5);
write4bits($30);
mdelay(5);
write4bits($30);
udelay(10);
write4bits($20);
udelay(10);
lcdctrl(%00001100); // Display on, Cursor aus
lcdctrl(%00010100); // shift Cursor nach rechts
lcdctrl(%00000110); // autoincrement
lcdclr;
Backlight := BL; // Backlight ein
end;
userdevice LCDIOS(cmd, data : byte) : byte;
var
mode : byte;
loN, hiN : byte;
begin
(* commands passed to user defined function "LCDIOS" *)
(* 0 init data = none result = none init user's hardware *)
(* 1 select display data = 0/1 result = none select display 1 or 2 *)
(* 2 write dataport data = byte result = none character output *)
(* 3 read dataport data = none result = byte character input *)
(* 4 write controlport data = byte resul = none command to display *)
(* 5 read controlport data = none result = byte get display state *)
// Writeln(Serout, bytetostr(cmd) + ', ' + bytetobin(data));
// if TWIstat(LcdAdr) then
case cmd of
0 : // hardware init
TWIout(LcdAdr, $F8); // all LCD control lines inactive
// Backlight on
cmd := 0;
|
1 : // select display
cmd := 0;
|
2 : // write to data port : Rs = true, Rw := false
mode := Rs;
hiN := data and $F0;
loN := (data and $0F) shl 4;
write4bits(hiN or mode);
write4bits(loN or mode);
|
3 : // read from data port : Rs,Rw = true
mode := Rw or Rs;
hiN := read4bits(mode);
hiN := (hiN and $F0);
loN := read4bits(mode);
loN := (loN shr 4) and $0F;
cmd := hiN or loN;
|
4 : // write to control port : Rs = false, Rw := false
mode := 0;
hiN := data and $F0;
loN := (data and $0F) shl 4;
write4bits(hiN or mode);
write4bits(loN or mode);
|
5 : // read from control port : Rs = false, Rw = true;
mode := Rw;
hiN := read4bits(mode);
hiN := (hiN and $F0);
loN := read4bits(mode);
loN := (loN shr 4) and $0F;
cmd := hiN or loN;
|
endcase;
// endif;
return(cmd);
end;
{--------------------------------------------------------------}
{ Main Program }
{$IDATA}
begin
InitPorts;
// InitADC;
EnableInts;
Writeln(Serout, 'LCDPort via PCF8574');
init_lcd;
// spalte, zeile
LCDclr;
Write(LCDout, 'LCDPort via PCF8574');
LCDxy(7, 1);
Write(LCDout, 'line 1');
LCDxy(7, 2); // spalte, zeile
Write(LCDout, 'line 2');
loop
if isSysTimerZero(t1000ms) then
SetSysTimer(t1000ms, 1000 div SysTick);
toggle(led);
Inc(cnt);
// LCDclrLine(3);
LCDxy(7, 3); // spalte, zeile
Write(LCDout, bytetostr(cnt : 6));
endif;
endloop;
end TWIDisplay.