Heute möchte ich eine LCD-Ansteuerung über I2C vorstellen.
Die LCD-Anzeige ist dabei über ein bei Pollin erhältliches LCD-I2C Adaptermodul mit PCF8574P angeschlossen.
Es sind zwei neue Forth (A) Worte hinzugekommen.
swapnibble (b1b2 --- b2b1) tauscht unteres gegen oberes Halbbyte b1 b2
_zero (a1a2a3 --- a1a2a3) entfernt führende Nullen (a3,a2) durch Ersatz mit Leerzeichen (ASCII 32) a1,a2,a3 --> ASCII Zeichen
Forth Programm:
Forth-Wörter:
: lcdsend i2cstart 78 i2cwrite drop i2cwrite drop i2cstop ;
: lcdenable dup 64 or lcdsend 191 and lcdsend ;
: lcdcommand dup swapnibble 15 and dup lcdsend lcdenable 15 and dup lcdsend lcdenable ;
: lcddata dup swapnibble 15 and 16 or dup lcdsend lcdenable 15 and 16 or dup lcdsend lcdenable ;
: lcdinit 1 wait 3 1 do 3 dup lcdsend lcdenable loop 2 dup lcdsend lcdenable 40 lcdcommand 12 lcdcommand 6 lcdcommand ;
: lcdclear 1 lcdcommand ;
: lcdhome 2 lcdcommand ;
: blein 127 lcdsend ;
: blaus 128 lcdsend ;
: Ausgabe 3 1 do lcddata loop ;
: lcdnum 3 1 do 10 / 48 + swap loop drop _zero ;
: .S stackcount 40 lcddata 48 + lcddata 41 lcddata ;
: Locate 128 + swap 64 * 65 - + lcdcommand ;
Hauptprogramm:
: main blein lcdinit lcdclear lcdhome 255 0 do 1 5 locate i lcdnum ausgabe 2 14 locate .S loop 10 wait blaus end ;
Erlauterung der Befehle:
lcdsend (B -- ) sendet ein Byte zur LCD-Anzeige über I2C (78 ist in diesem Fall die Adresse des Adaptermoduls) kann geändert werden,
lcdenable (B -- ) sendet den Enableimpuls für die LCD-Anzeige über I2C (B - Byte vom vorherigem lcdsend),
lcdcommand (C -- ) splittet das Kommandobyte C in oberes und unteres Nipple auf und sendet es über I2C zur Anzeige (Kommandobyte siehe Datenblatt
der LCD-Anzeige R/S=0),
lcddata (D -- ) splittet das Datenbyte D in oberes und unteres Nipple auf und sendet es über I2C zur Anzeige (R/S=1),
lcdinit ( -- ) initialisiert die LCD Anzeige (in diesem Fall 4-Bitmodus, 2-zeilig, Curser-aus, Blinken-aus) aus Datenblatt der LCD ersichtlich,
lcdclear ( -- ) löscht die LCD-Anzeige,
lcdhome ( -- ) setz den Curser auf Zeile 1 Spalte 1,
blein ( -- ) schaltet die Hintergrundbeleuchtung ein,
blaus ( -- ) schaltet die Hintergrundbeleuchtung aus,
Ausgabe (abc -- ) gibt die obersten drei Byte vom Stack aus,
lcdnum (z -- A1A10A100) wandelt eine Zahl z (Byte) in 3 ASCII-Zeichen (3 Byte) um,
.S ( -- ) gibt die Stacktiefe in Form von (Z) aus,
locate (zs -- ) setzt den Curser auf Zeile,Spalte,
Hauptprogramm (main):
1. Hintergrundbeleuchtung einschalten
2: LCD initialisieren
3: LCD löschen
4. Curser auf Zeile 1, Spalte1 setzen
5. eine Schleife von 0 bis 255 beginnen
6. Curser auf Zeile 1 Spalte 5 setzen
7. Schleifenindex i holen
8. Schleifenindex in ASCII umwandeln, führende Nullen ausblenden
9. auf LCD ausgeben
10. Curser auf Zeile 2 Spalte 14 setzen
11. Stacktiefe ausgeben
12. Schleife wiederholen bis 255
13. 10 Sekunden warten
14. Hintergrundbeleuchtung ausschalten
15. Ende
Die Initialisierung der LCD-Anzeige funktioniert mit einem 2-zeiligen LCD sowie einem 1-zeiligen LCD (16 Zeichen).
Bei manchem 1-zeiligen LCD's müssen die Stellen 9 bis 16 mit 2 1 locate bis 2 8 locate addressiert werden.
Leider weiss ich nicht wie und ob ich hier eine Datei anhängen kann, dann könnte ich die entsprechende forthvok.vok anhängen.
Momentan kann ich sie per E-Mail versenden. Bitte bei mir melden. (dieterhaeussler@freenet.de)
MikroForth LCD mit I2C
Re: MikroForth LCD mit I2C
In meinem Beitrag "I2C-LCD von YwRobot" habe ich schon darauf hingewiesen, dass es (mindestens) zwei verschiedene Module gibt, bei denen ein Hitachi-kompatibles LCD (2 x 16) über einen PCF8574-Baustein angesteuert werden. Sie ähneln sich sehr stark. Vermutlich sind sich die Händler dieses Umstandes gar nicht bewusst, denn immer wieder finde ich im Internet Angebote, bei denen nebeneinander Bilder von beiden Typen auftauchen. So ist bei der Bestellung häufig nicht klar, welchen Typ man erwirbt.
Das wäre auch gar nicht so tragisch, wenn die beiden Module kompatibel wären. Beide besitzen zwar den gleichen PCF-Baustein; dessen 8 Ausgänge sind aber unterschiedlich mit den Steuerleitungen des LCDs verbunden; auch die Steuerung der Hintergrundbeleuchtung ist anders organisiert.
Typ 1:
P0 -> D4
P1 -> D5
P2 -> D6
P3 -> D7
P4 -> RS
P5 -> RW (not used, set to 0 to ground for write)
P6 -> E2 (on 1 or 2 line display nc)
P7 -> E1(=E)
Typ 2 (YwRobot):
P0 -> RS
P1 -> RW
P2 -> E
P3 -> BT (Backlight)
P4 -> D4
P5 -> D5
P6 -> D6
P7 -> D7
Didis I2C-LCD-Forth-Vokabular bezieht sich offensichtlich auf den Typ 1. Aus dem Programm wird nämlich deutlich, dass die Daten-Nibbles über P0 bis P3 ausgegeben werden. Ich habe für den Typ 2 (YwRobot) Didis Programm umgeschrieben:
Die Wörter haben die gleiche Funktion wie bei Didi. Der HEX-Code für das erforderliche Assemblerwort swapnibble befindet sich in der Anlage.
.
Das wäre auch gar nicht so tragisch, wenn die beiden Module kompatibel wären. Beide besitzen zwar den gleichen PCF-Baustein; dessen 8 Ausgänge sind aber unterschiedlich mit den Steuerleitungen des LCDs verbunden; auch die Steuerung der Hintergrundbeleuchtung ist anders organisiert.
Typ 1:
P0 -> D4
P1 -> D5
P2 -> D6
P3 -> D7
P4 -> RS
P5 -> RW (not used, set to 0 to ground for write)
P6 -> E2 (on 1 or 2 line display nc)
P7 -> E1(=E)
Typ 2 (YwRobot):
P0 -> RS
P1 -> RW
P2 -> E
P3 -> BT (Backlight)
P4 -> D4
P5 -> D5
P6 -> D6
P7 -> D7
Didis I2C-LCD-Forth-Vokabular bezieht sich offensichtlich auf den Typ 1. Aus dem Programm wird nämlich deutlich, dass die Daten-Nibbles über P0 bis P3 ausgegeben werden. Ich habe für den Typ 2 (YwRobot) Didis Programm umgeschrieben:
Code: Alles auswählen
( Vokabular für I2C-Display "YwRobot Arduino LCM1602 IIC V1" mit PCF8574T )
( I2C-Adresse ist 78 )
( Bytes und Nibbles übertragen: )
: Yw_lcd_send i2cstop i2cstart 78 i2cwrite drop 8 or i2cwrite drop i2cstop ;
: Yw_lcd_enable dup 4 or Yw_lcd_send 251 and Yw_lcd_send ;
: Yw_lcd_command dup $F0 and dup Yw_lcd_send Yw_lcd_enable swapnibble $F0 and dup Yw_lcd_send Yw_lcd_enable ;
: Yw_lcd_data dup $F0 and 1 or dup Yw_lcd_send Yw_lcd_enable swapnibble $F0 and 1 or dup Yw_lcd_send Yw_lcd_enable ;
: Yw_lcd_nibble swapnibble $F0 and dup Yw_lcd_send Yw_lcd_enable ;
( Zahlendarstellung: )
: Yw_lcd_digit 48 + Yw_lcd_data ;
: Yw_lcd_num 100 / swap Yw_lcd_digit 10 / swap Yw_lcd_digit Yw_lcd_digit ;
( Initialisierung und LCD-Steuerbefehle: )
: Yw_lcd_init1 20 waitms 3 Yw_lcd_nibble 5 waitms 3 Yw_lcd_nibble wait1ms 3 Yw_lcd_nibble wait1ms 2 Yw_lcd_nibble wait1ms ;
: Yw_lcd_init2 $28 Yw_lcd_command wait1ms $0C Yw_lcd_command wait1ms $01 Yw_lcd_command wait1ms $06 Yw_lcd_command wait1ms ;
: Yw_lcd_init Yw_lcd_init1 Yw_lcd_init2 ;
: Yw_lcd_clear 1 Yw_lcd_command ;
: Yw_lcd_home 2 Yw_lcd_command ;
: Yw_lcd_locate 64 * + 128 + 16 / swap Yw_lcd_nibble Yw_lcd_nibble wait1ms ;
( Tests: )
: ausgabe1 200 100 do Yw_lcd_home I Yw_lcd_num 250 waitms loop ;
: ausgabe2 5 1 Yw_lcd_locate 33 111 108 108 97 72 6 1 do Yw_lcd_data loop ;
( : ausgabe0 65 Yw_lcd_data ; )
: main Yw_lcd_init Yw_lcd_clear Yw_lcd_home ausgabe2 1 wait ausgabe1 ;
.
- Dateianhänge
-
- swapnibble.zip
- swapnibble.hex (gepackt)
- (194 Bytes) 2270-mal heruntergeladen