Option Explicit
'LCD-Ansteuerung von Christof Rueß, www.hobby-elektronik.de.vu
'Die Verwendung dieses Moduls ist kostenfrei, solange diese Zeilen erhalten bleiben.
'Fragen, Kritik und Anregungen an: hobbyelektronik@gmx.net
'Deklaration für die Portansteuerung (auch für Win2k & WinXP)
Public Declare Sub PortOut32 Lib "inpout32.dll" Alias "Out32" (ByVal PortAddress As Integer, ByVal Value As Integer)
Public Declare Function PortIn32 Lib "inpout32.dll" Alias "Inp32" (ByVal PortAddress As Integer) As Integer
'Hier können die Werte für die verschiedenen Zustände der Ausgänge eingetragen werden.
'Falls das Display direkt, also ohne die invertierende Treiberstufe betrieben wird,
'müssen SCLlo mit SCLhi und SDAlo mit SDAhi getauscht werden.
Const SCLlo = 1 'Ausgabe am Port für SCL wenn low
Const SCLhi = 0 'Ausgabe am Port für SCL wenn high
Const SDAlo = 2 'Ausgabe am Port für SDA wenn low
Const SDAhi = 0 'Ausgabe am Port für SDA wenn high
Const StaticOut = 0 'Statische Ausgabe am Port (evtl. für die Stromversorgung des LCDs oder Steuerung LEDs - _
kann durch eine Variable ersetzt werden.)
Private LcdPort As Long 'Variable für den Parallelport
'Enums für die Sonderzeichen am oberen Displayrand
Enum EnSpecialCharA
scL2 = 1 'zweiter Strich hinter "FM"
scRDS = 2 'RDS-Zeichen
scL3 = 4 ' dritter Strich hinter "FM"
stDP = 16 'Punkt hinter dem 6. Zeichen unten
stTP = 32 'TP-Zeichen (Traffic Program)
stTA = 64 'TA-Zeichen (Traffic Announcement)
scST = 128 'Stereo-Zeichen
End Enum
Enum EnSpecialCharB
sc1 = 1 '1 oben links
sc3 = 2 '3 oben links
sc2 = 4 '2 oben links
sc4 = 8 '4 oben links
scL1 = 16 'erster Strich hinter "FM"
sc6 = 32 '1 oben links
scFM = 64 'FM-Zeichen
sc5 = 128 '5 oben links
End Enum
'Type für die Blinkfrequenz
Enum EnBlinkFrequ
bOff = 0 'kein blinken
b2Hz = 1 '2 Hz
b1Hz = 2 '1 Hz
bhHz = 3 '0.5 Hz
End Enum
'Hiermit wird der Port, an dem das LCD angschlossen ist festgelegt
Property Let Port(ByVal NewPort As Long)
LcdPort = NewPort
End Property
'Damit der Port auch gelesen werden kann, ist dies hier notwendig:
Property Get Port() As Long
Port = LcdPort
End Property
'binären String in dezimalen Long umwandeln
Function BintoDez(ByVal Bin As String) As Long
Dim X&, y&
Bin = Bin & String$(8 - Len(Bin), "0")
For X = 1 To Len(Bin)
If Mid$(Bin, X, 1) = "1" Then
y = y + 2 ^ (8 - X)
End If
Next X
BintoDez = y
End Function
'dezimal -> binär
Function DeztoBin(ByVal Dez As Long) As String
Dim X%
If Dez >= 2 ^ 32 Then
Call MsgBox("Zahl ist größer als 32 Bit")
Exit Function
End If
Do
If (Dez And 2 ^ X) Then
DeztoBin = "1" & DeztoBin
Else
DeztoBin = "0" & DeztoBin
End If
X = X + 1
Loop Until 2 ^ X > Dez
DeztoBin = Format(DeztoBin, "00000000")
End Function
'Startbit senden
Private Function I2C_Startbit()
PortOut32 LcdPort, SCLhi + SDAhi + StaticOut
PortOut32 LcdPort, SCLhi + SDAlo + StaticOut
PortOut32 LcdPort, SCLlo + SDAlo + StaticOut
End Function
'Stoppbit senden
Private Function I2C_Stoppbit()
PortOut32 LcdPort, SCLhi + SDAlo + StaticOut
PortOut32 LcdPort, SCLhi + SDAlo + StaticOut
PortOut32 LcdPort, SCLhi + SDAhi + StaticOut
End Function
'Ein Byte an das Display senden
Function I2C_WriteByte(ByVal I2C_Data As Long)
Dim BinData As String
Dim X
BinData = DeztoBin(I2C_Data) 'dezimale Daten in binäre umwandeln
For X = 1 To 8
If Mid(BinData, X, 1) = "1" Then 'Jedes Bit abfragen
PortOut32 LcdPort, SCLlo + SDAhi + StaticOut
PortOut32 LcdPort, SCLhi + SDAhi + StaticOut
PortOut32 LcdPort, SCLlo + SDAhi + StaticOut
Else
PortOut32 LcdPort, SCLlo + SDAlo + StaticOut
PortOut32 LcdPort, SCLhi + SDAlo + StaticOut
PortOut32 LcdPort, SCLlo + SDAlo + StaticOut
End If
Next
'Byte abschließen
PortOut32 LcdPort, SCLlo + SDAlo + StaticOut
PortOut32 LcdPort, SCLhi + SDAlo + StaticOut
PortOut32 LcdPort, SCLlo + SDAlo + StaticOut
'Noch ein ACK rausjagen
PortOut32 LcdPort, SCLlo + SDAlo + StaticOut
End Function
'Display initialisieren
Function Init(Optional ByVal HighContrast As Boolean = False)
Dim X
I2C_Startbit 'Startbit ausgeben
I2C_WriteByte 112 ' Adresse des LCDs
I2C_WriteByte 224 '11100000
'Device select (weitere Befehle folgen, Device 0)
I2C_WriteByte 200 + IIf(HighContrast = True, 4, 0) '11001000
'Mode set (weitere Befehle folgen, Normaler Modus, Lcd Enabled, 1/3 bias, 1:4 MUX)
I2C_WriteByte 240 '11110000 'blinken abstellen
I2C_WriteByte 0 'Cursor auf Null setzen
'gesamten Displayinhalt löschen
For X = 0 To 18
I2C_WriteByte 0
Next
I2C_Stoppbit 'Stoppbit ausgeben
End Function
'Sonderzeichen in der oberen Zeile des Displays an- und abschalten
Function SpecialChars(Optional ByVal SPchar1 As EnSpecialCharA, Optional ByVal SPchar2 As EnSpecialCharB)
I2C_Startbit 'Startbit ausgeben
I2C_WriteByte 112 ' Adresse des LCDs
I2C_WriteByte 224 '11100000
'Device select (weitere Befehle folgen, Device 0)
I2C_WriteByte 32 'Cursor auf "obere Zeile" setzen - Position * 4
I2C_WriteByte SPchar1 'ersten Teil schreiben
I2C_WriteByte SPchar2 'zweiten Teil schreiben
I2C_Stoppbit
End Function
'Display blinken lassen
Function Blink(ByVal BlinkFrequ As EnBlinkFrequ)
I2C_Startbit 'Startbit ausgeben
I2C_WriteByte 112 ' Adresse des LCDs
I2C_WriteByte 224 '11100000
'Device select (weitere Befehle folgen, Device 0)
I2C_WriteByte 240 + BlinkFrequ 'blinken einstellen
I2C_Stoppbit
End Function
'Text an das Display ausgeben
Function WriteText(ByVal Text As String)
Dim X
Dim ByteA As Long
Dim ByteB As Long
I2C_Startbit
I2C_WriteByte 112 ' Adresse des LCDs
I2C_WriteByte 224
'Device select (weitere Befehle folgen, Device 0)
I2C_WriteByte 0 'Cursor auf erstes Zeichen setzen
Text = Left(Text, 8) 'Murx!
Text = Text & Space(8 - Len(Text))
For X = 1 To 8 'Text parsen
Select Case UCase(Mid(Text, X, 1))
'die Zusammensetzung der Zeichen ist etwas eigenartig:
'Der linke Teil des Zeichens wird in ByteA gespeichert, der rechte in ByteB.
'Mehr Informationen dazu auf der oben genannten Homepage.
Case " ": ByteA = 0: ByteB = 0
Case "A": ByteA = 184: ByteB = 141
Case "B": ByteA = 13: ByteB = 189
Case "C": ByteA = 153: ByteB = 144
Case "D": ByteA = 13: ByteB = 185
Case "E": ByteA = 185: ByteB = 144
Case "F": ByteA = 184: ByteB = 128
Case "G": ByteA = 153: ByteB = 149
Case "H": ByteA = 176: ByteB = 13
Case "I": ByteA = 13: ByteB = 176
Case "J": ByteA = 17: ByteB = 25
Case "K": ByteA = 176: ByteB = 7
Case "L": ByteA = 145: ByteB = 16
Case "M": ByteA = 146: ByteB = 11
Case "N": ByteA = 146: ByteB = 73
Case "O": ByteA = 153: ByteB = 153
Case "P": ByteA = 184: ByteB = 140
Case "Q": ByteA = 153: ByteB = 217
Case "R": ByteA = 184: ByteB = 204
Case "S": ByteA = 169: ByteB = 149
Case "T": ByteA = 12: ByteB = 160
Case "U": ByteA = 145: ByteB = 25
Case "V": ByteA = 208: ByteB = 2
Case "W": ByteA = 208: ByteB = 73
Case "X": ByteA = 66: ByteB = 66
Case "Y": ByteA = 164: ByteB = 12
Case "Z": ByteA = 73: ByteB = 146
Case "0": ByteA = 217: ByteB = 155
Case "1": ByteA = 0: ByteB = 11
Case "2": ByteA = 57: ByteB = 156
Case "3": ByteA = 9: ByteB = 157
Case "4": ByteA = 160: ByteB = 13
Case "5": ByteA = 169: ByteB = 208
Case "6": ByteA = 185: ByteB = 149
Case "7": ByteA = 8: ByteB = 137
Case "8": ByteA = 185: ByteB = 157
Case "9": ByteA = 169: ByteB = 157
Case "°": ByteA = 168: ByteB = 140
Case "!": ByteA = 11: ByteB = 146
Case """": ByteA = 128: ByteB = 32
Case "$": ByteA = 173: ByteB = 181
Case "%": ByteA = 192: ByteB = 3
Case "&": ByteA = 185: ByteB = 212
Case "/": ByteA = 64: ByteB = 2
Case "\": ByteA = 2: ByteB = 64
Case "(": ByteA = 153: ByteB = 0
Case ")": ByteA = 0: ByteB = 153
Case "=": ByteA = 33: ByteB = 20
Case "?": ByteA = 72: ByteB = 156
Case "@": ByteA = 57: ByteB = 157
Case "Ü": ByteA = 25: ByteB = 145
Case "Ö": ByteA = 57: ByteB = 149
Case "Ä": ByteA = 56: ByteB = 133
Case "*": ByteA = 102: ByteB = 102
Case "+": ByteA = 36: ByteB = 36
Case "-": ByteA = 32: ByteB = 4
Case "~": ByteA = 136: ByteB = 44
Case "_": ByteA = 1: ByteB = 16
Case ".": ByteA = 1: ByteB = 0
Case ",": ByteA = 96: ByteB = 0
Case "µ": ByteA = 176: ByteB = 12
Case "<": ByteA = 0: ByteB = 66
Case ">": ByteA = 66: ByteB = 0
Case "|": ByteA = 4: ByteB = 32
Case "^": ByteA = 130: ByteB = 0
Case "}": ByteA = 13: ByteB = 36
Case "{": ByteA = 36: ByteB = 176
Case ":": ByteA = 33: ByteB = 0
Case ";": ByteA = 104: ByteB = 0
Case "§": ByteA = 255: ByteB = 255
'Für den Paragraph gibt es kein sinnvolles Zeichen, deshalb wird er als Testzeichen missbraucht.
Case Else: ByteA = 0: ByteB = 0
End Select
I2C_WriteByte ByteA 'erstes Byte ausgeben
I2C_WriteByte ByteB 'zweites Byte ausgeben
Next
I2C_Stoppbit
End Function