Forum: Mikrocontroller und Digitale Elektronik PCF 8574P + LCD


von Gerald *. (pyromane)


Lesenswert?

Hi, ich hab hier ein LCD von Pollin(Bestellnr 120 420) welches ich per 
PCF 8574P steuere. Das LCD ist wie folgt an den PCF 8574P angebunden:

DB4 - P0
DB5 - P1
DB6 - P2
DB7 - P3
RS  - P4
RW  - P5
E   - P7

Die Initialisierung, Löschen, Kursorsteuerungen funktionieren ohne 
Probleme, jedoch werden einige Buchstaben nicht richtig dargestellt.

Ich möchte ein L auf den LCD anzeigen und übermittle dazu:
94h
1ms Pause
00h
1ms Pause
9Ch
1ms Pause
00h

Auf den LCD bekomme ich allerdings ein D angezeigt, obwohl hierfür eig 
folgendes übermittelt werden müsste:
94h
1ms Pause
00h
1ms Pause
94h
1ms Pause
00h

Dieser Fehler findet sich auch bei einigen anderen Zeichen, jedoch nicht 
bei allen.

Über Hinweise oder auch Lösungsvorschläge würde ich mich freuen.
Pyromane

von Ago (Gast)


Lesenswert?

Du toggelst neben dem EN auch das Command/Data usw.
Versuch einfach mal, bei der Datenübertragung nur Bit 7 (EN)zu toggeln, 
also:

94h
1ms Pause
14h
1ms Pause
9Ch
1ms Pause
1Ch

Wenn ich  mich recht erinnere, werden die Daten mit fallender Flanke 
übernommen. Habe gerade mal in meinen I2C Routinen (PIC) nachgesehen. Da 
mache es ich so ähnlich:

; lcd_config:
; Bit D0 to D3 are directly written to PCF8574(A) after being IORed with 
nibble data D4-D7
;       D0 = EN, default to H
;       D1 = RW, default to L (write to LCD)
;       D2 = RS, default to L (will be modified in LCD_Command/LCD_Data)
;       D3 = Display-Backlight, set to L (on)
...
                iorwf   lcd_temp, W
                call    IIC_Put
                andlw   0xfe            ; clear enable bit
                call    IIC_Put

von Oliver J. (skriptkiddy)


Lesenswert?

Wahrscheinlich ist eine der Datenleitungen von PCF8574 zum Display nicht 
richtig angeschlosen.

tippe mal auf DB7.

Schau dir mal die binäre Codierung der Zeichen 'L' und 'D' an.

von Klaus 2. (klaus2m5)


Lesenswert?

Die Pausen kannst Du Dir normalerweise sparen. I2C ist langsam genug 
(außer bei Clear/Home).

von Gerald *. (pyromane)


Lesenswert?

Danke für die Antworten

Ago schrieb:
> 94h
> 1ms Pause
> 14h
> 1ms Pause
> 9Ch
> 1ms Pause
> 1Ch
Es erscheint auf dem LCD leider wieder ein D

Skript Kiddy schrieb:
> Wahrscheinlich ist eine der Datenleitungen von PCF8574 zum Display nicht
> richtig angeschlosen.
Alle Pins wurden durchgemessen.

Skript Kiddy schrieb:
> Schau dir mal die binäre Codierung der Zeichen 'L' und 'D' an.
L = 0100 9
D = 0100 0100
(Leerstellen wurden zu besseren Übersicht hinzugefügt)

Klaus 2m5 schrieb:
> Die Pausen kannst Du Dir normalerweise sparen. I2C ist langsam genug
> (außer bei Clear/Home).
Danke für die Info.

von Oliver J. (skriptkiddy)


Lesenswert?

L = 0100 1100
D = 0100 0100

Die beiden unterscheiden sich nur in einem Bit. Das würde ich als 
Grundlage für die Fehlersuche ansetzen.

Schreib mal  1100 1100 = 0xCC  als Zeichen auf das Display.

Wenn mit dem DB7 was nicht stimmt müsste dabei ein 'D' auf dem Display 
erscheinen. Denn Bit 3 und Bit 7 des Zeichens werden ja über DB7 
übertragen.

Gruß

Das Skriptende Kind

von Gerald *. (pyromane)


Angehängte Dateien:

Lesenswert?

Ich hab folgendes übertragen
9Ch
00h
9Ch
00h
und das Zeichen im Anhang erhalten.

Anmerkung:
"Display aus" benötigt den DB7 und dieser Befehl wird problemlos 
ausgeführt.

von Oliver J. (skriptkiddy)


Lesenswert?

Gerald O. schrieb:
> Ich hab folgendes übertragen
> 9Ch
> 00h
> 9Ch
> 00h
> und das Zeichen im Anhang erhalten.

OK. Dann scheint es ein Software-Problem zu sein.

Kannste du mal deine Sourcen Posten?

von Gerald *. (pyromane)


Lesenswert?

Ich verwende die AVR-NET-IO mit Ethersex Firmware. Die I2C Befehle 
werden von einem AutoIT Skript per TCP an die AVR-NET-IO übermittelt. 
Der Debug Modus in der Ehtersex Firmware ist aktitviert und somit kann 
ich sicher sein das die I2C Befehler richtig übertragen werden.
Keine elegante Lösung aber ich habe leider gerade keinen Zugriff auf 
einen Brenner. :/

AutoIT Skript dennoch posten?

von Oliver J. (skriptkiddy)


Lesenswert?

ja.

von Gerald *. (pyromane)


Lesenswert?

$tab0data ist ein Input Feld
$cm* listet die übermittelten und empfangenen Befehle/Nachrichten auf
_BinaryToHexString ist eine Funktion um Binärwerte in hexadezimale 
Zahlen zu wandeln, die Funktion wurde schon mehrfach mit Diversen Tool 
gegengeprüft.
1
$laenge = stringlen(GUICtrlRead($tab0data))
2
if $laenge > 0 Then
3
  if $laenge > 20 Then
4
    $data = StringLeft(GUICtrlRead($tab0data), 20)
5
  Else
6
    $data = GUICtrlRead($tab0data)
7
  EndIf
8
9
  $data2 =""
10
  for $t=1 to $laenge  ;jeden Buchstaben im String
11
    $asciicode=asc(stringmid($data,$t,1))  ;in asciicode umwandeln
12
    for $i=7 to 0 step -1   ;asciicode in bits
13
      if bitand($asciicode,2^$i) then
14
        $data2&="1"
15
      else
16
        $data2&="0"
17
      endif
18
    next
19
  next
20
21
  For $i = 1 To (($laenge * 2) - 1) +1
22
    $zw1 = StringLeft($data2, (4*$i))
23
    $zw1 = StringRight($zw1, 4)
24
    $zw2 = "1001" & $zw1
25
    $zw3 = _BinaryToHexString($zw2)
26
  
27
    ;Enable ein + Befehl übermitteln
28
    $bef = "pcf8574x set 1 0 " & $zw3
29
    TCPSend($socket, $bef  & @CRLF)
30
    sleep(1)
31
    $recv = TCPRecv( $socket, 2048)
32
    If $recv <> "" Then
33
      GUICtrlSetData($cmd, " < " & $bef & @CRLF & " > " & $recv & @CRLF, true)
34
    endif
35
          
36
    ;Enable aus
37
    $bef = "pcf8574x set 1 0 00"
38
    TCPSend($socket, $bef  & @CRLF)
39
    sleep(1)
40
    $recv = TCPRecv( $socket, 2048)
41
    If $recv <> "" Then
42
      GUICtrlSetData($cmd, " < " & $bef & @CRLF & " > " & $recv & @CRLF, true)
43
    endif
44
    sleep(20)
45
  Next
46
EndIf

von Oliver J. (skriptkiddy)


Lesenswert?

Super kommentiert.

Na mal schauen, ob es Jemanden gibt, der sich das bei der Hitze antut.

von Ago (Gast)


Lesenswert?

Boah... :-)

Also wenn ich das richtig überblicke, enthält $data2 den kompletten 
String data, und zwar jeweils 8 "Bit" als String aus 0 und/oder 1...

  For $i = 1 To (($laenge * 2) - 1) +1
    $zw1 = StringLeft($data2, (4*$i))
    $zw1 = StringRight($zw1, 4)
    $zw2 = "1001" & $zw1
    $zw3 = _BinaryToHexString($zw2)

...

  For $i = 1 To (($laenge * 2) - 1) +1
    $zw1 = StringMid($data2, (4*$i)-3, 4)
    $zw2 = _BinaryToHexString($zw1)

    ;Enable ein + Befehl übermitteln
    $bef = "pcf8574x set 1 0 9" & $zw2
...

    ;Enable aus
    $bef = "pcf8574x set 1 0 1" & $zw2
...

von Ago (Gast)


Lesenswert?

Oder gleich so (ohne Garantie natürlich, habe aber die internen 
Funktionen genutzt (lt. http://www.autoitscript.com/autoit3/docs/ ).

$data = GUICtrlRead($tab0data)
$laenge = StringLen($data)
if $laenge > 0 Then
  if $laenge > 20 Then
    $laenge = 20
    $data = StringLeft($data, 20)
  EndIf

  $data2 ="" ; Das wird unser Hex-String
  for $t=1 to $laenge  ;jeden Buchstaben im String
    $asciicode=asc(StringMid($data,$t,1))  ;in asciicode umwandeln
    $data2 &= Hex($asciicode, 2)           ;und dann in hex (2stellig)
  next

  For $i = 1 To ($laenge * 2)
    $zw1 = StringMid($data2, $i, 1)

    ;Enable ein + Befehl übermitteln
    $bef = "pcf8574x set 1 0 9" & $zw1
    TCPSend($socket, $bef  & @CRLF)
    sleep(1)
    $recv = TCPRecv( $socket, 2048)
    If $recv <> "" Then
      GUICtrlSetData($cmd, " < " & $bef & @CRLF & " > " & $recv & @CRLF, 
true)
    endif

    ;Enable aus
    $bef = "pcf8574x set 1 0 1" & $zw1
    TCPSend($socket, $bef  & @CRLF)
    sleep(1)
    $recv = TCPRecv( $socket, 2048)
    If $recv <> "" Then
      GUICtrlSetData($cmd, " < " & $bef & @CRLF & " > " & $recv & @CRLF, 
true)
    endif
    sleep(20)
  Next
EndIf

von Gerald *. (pyromane)


Lesenswert?

Vielen Dank für die Antworten

Ago schrieb:
> Also wenn ich das richtig überblicke, enthält $data2 den kompletten
> String data, und zwar jeweils 8 "Bit" als String aus 0 und/oder 1...
Ja, $data2 enthält den Wert aus $data in binärer Form

Ago schrieb:
>     $zw1 = StringMid($data2, (4*$i)-3, 4)
Danke, hatte ich lange gesucht

Ago schrieb:
>     ;Enable ein + Befehl übermitteln
>     $bef = "pcf8574x set 1 0 9" & $zw2
Kurze Erklärung:
pcf8574x set I2C Adressen PCF8574/PCF8574A wert
Ich verwende den PCF8574 mit A0 = 1, A1+A2 = 0 daraus ergibt sich dann 
folgendes:
pcf8574x set 1 0 wert
wert ist in meinem Fall $zw3

Ich habe den gesamten Code mit Kommentaren versehen
1
$laenge = stringlen(GUICtrlRead($tab0data))   ;Länge der Daten feststellen
2
if $laenge > 0 Then                           ;prüfen ob Daten vorhanden sind
3
  if $laenge > 20 Then                        ;Anzeige auf 20 Zeichen limitieren und in $data speichern
4
    $data = StringLeft(GUICtrlRead($tab0data), 20)
5
  Else
6
    $data = GUICtrlRead($tab0data)            ;direkt in $data speicher, da kleiner als 20 Zeichen
7
  EndIf
8
9
  $data2 =""                                  ;Variable anlegen, wird binär $data enthalten
10
  for $t=1 to $laenge                         ;jeden Buchstaben im String
11
    $asciicode=asc(stringmid($data,$t,1))     ;in asciicode umwandeln
12
    for $i=7 to 0 step -1                     ;asciicode in Bits
13
      if bitand($asciicode,2^$i) then
14
        $data2&="1"
15
      else
16
        $data2&="0"
17
      endif
18
    next
19
  next
20
21
  For $i = 1 To (($laenge * 2) - 1) +1      ;Daten fürs übermitteln aufbereiten
22
  $zw1 = StringMid($data2, (4*$i)-3, 4)     ;Nibble filtern
23
  $zw2 = "1001" & $zw1                      ;um Steuerdaten erweitern
24
  $zw3 = _BinaryToHexString($zw2)           ;binäre Daten in hex wandeln
25
  
26
    ;Enable ein + Befehl/Daten übermitteln
27
    $bef = "pcf8574x set 1 0 " & $zw3       ;I2C Befehl erstellen
28
    TCPSend($socket, $bef  & @CRLF)         ;Befehl an AVR-NET-IO übermitteln
29
    sleep(1)
30
    $recv = TCPRecv( $socket, 2048)         ;Antwort speichern
31
    If $recv <> "" Then                     ;Befehl + Antwort anzeigen
32
      GUICtrlSetData($cmd, " < " & $bef & @CRLF & " > " & $recv & @CRLF, true)
33
    endif
34
          
35
    ;Enable aus
36
    $bef = "pcf8574x set 1 0 00"           ;I2C Befehl(=enable aus) erstellen
37
    TCPSend($socket, $bef  & @CRLF)        ;Befehl an AVR-NET-IO übermitteln
38
    sleep(1)
39
    $recv = TCPRecv( $socket, 2048)        ;Antwort speichern
40
    If $recv <> "" Then                    ;Befehl + Antwort anzeigen
41
      GUICtrlSetData($cmd, " < " & $bef & @CRLF & " > " & $recv & @CRLF, true)
42
    endif
43
    sleep(20)
44
  Next
45
EndIf

Edit: die Funktion Hex() hatte bei mir leider nicht den gewünschten 
Effekt gebracht.

von Ago (Gast)


Lesenswert?

Gerald O. schrieb:
> Ago schrieb:
>>     ;Enable ein + Befehl übermitteln
>>     $bef = "pcf8574x set 1 0 9" & $zw2
> Kurze Erklärung:
> pcf8574x set I2C Adressen PCF8574/PCF8574A wert
> Ich verwende den PCF8574 mit A0 = 1, A1+A2 = 0 daraus ergibt sich dann
> folgendes:
> pcf8574x set 1 0 wert
> wert ist in meinem Fall $zw3

So wie ich das sehe, entspricht zw3 in deinem Fall auch "nur" dem 8-Bit 
Wert in Hexform, oder?

Da du ja die "1001" + 4-Bit Nibble als Hexzahl rüberschiebst, sendest du 
also immer "pcf8574x set 1 0 9x" wobei x dem Hex-nibble entspricht.

Nichts anderes sollte bei

$bef = "pcf8574x set 1 0 9" & $zw2

passieren. $zw2 enthält ja bei mir direkt den Hexwert aus $data2.

$bef = "pcf8574x set 1 0 00"           ;I2C Befehl(=enable aus) 
erstellen

Wenn das "00" das Byte ist, welches an den PCF ausgegeben wird, dann 
änderst du auch gleichzeitig mit dem Enable das "RS", wechselst also vom 
Daten in den Command-Modus (während das 2. Nibble ja eigentlich noch 
übertragen werden soll). Das kann nicht gehen.

von Gerald *. (pyromane)


Lesenswert?

Ich habe in der Zwischenzeit noch mal bezüglich LCDs nachgelesen. Man 
darf nur den Enable Pin toggelen, mein Fehler :/

Ich werde die Initialisierung und die restlichen Teile entsprechend 
anpassen, hoffe danach ist der Fehler verschwunden, auf jeden Fall melde 
ich mich danach noch einmal(wahrscheinlich morgen).

Vielen Dank für die Infos und Hinweise.

von Klaus 2. (klaus2m5)


Lesenswert?

Gerald O. schrieb:
> Ich habe in der Zwischenzeit noch mal bezüglich LCDs nachgelesen. Man
> darf nur den Enable Pin toggelen, mein Fehler :/

Genau das stand in der ersten Antwort.

Gerald O. schrieb:
> Ago schrieb:
>> 94h
>> 1ms Pause
>> 14h
>> 1ms Pause
>> 9Ch
>> 1ms Pause
>> 1Ch
> Es erscheint auf dem LCD leider wieder ein D

Hat doch angeblich nicht funktioniert.

von Gerald *. (pyromane)


Lesenswert?

Leider hat auch das Überarbeiten des Skriptes nicht den gewünschten 
Effekt gezeigt und es wurden immer noch falsche Buchstaben angezeigt.

Ich habe mal die gesamten Großbuchstaben versucht und bin auf folgendes 
gekommen:

SOLL  IST    SOLL         IST

H      @    0100 1000   0100 0000
J      B    0100 1010   0100 0010
L      D    0100 1100   0100 0100
M      E    0100 1101   0100 0101
N      F    0100 1110   0100 0110
O      G    0100 1111   0100 0111
X      P    0101 1000   0101 0000
Z      R    0101 1010   0101 0010

Nachdem ich mein Multimeter auf den betreffenden Pin gehängt habe und 
das Skript erneut laufen lassen habe war der Fehler auf einmal weg. >> 
Kapazitives Problem,
Aus Interesse versuchte ich dann noch mein altes Skript, welches auch 
Fehlerfrei funktionierte.

Vielen Dank für die zahlreichen Tipps und auch Lösungsvorschläge.

von Klaus 2. (klaus2m5)


Lesenswert?

Das stand schon in Antwort #2:

Skript Kiddy schrieb:
> Wahrscheinlich ist eine der Datenleitungen von PCF8574 zum Display nicht
> richtig angeschlosen.
>
> tippe mal auf DB7.

von Gerald *. (pyromane)


Lesenswert?

Klaus 2m5 schrieb:
> Das stand schon in Antwort #2:
>
> Skript Kiddy schrieb:
>> Wahrscheinlich ist eine der Datenleitungen von PCF8574 zum Display nicht
>> richtig angeschlosen.
>>
>> tippe mal auf DB7.

Ich hatte an den PINs eine Pegel von 4,95V gemessen, jedoch sagt das 
leider nichts über die Flanken aus.
Nebenbei wurde "Display aus" immer ordnungsgemäß ausgeführt und dieser 
Befehl benötigt DB7.

von Karl H. (kbuchegg)


Lesenswert?

Gerald O. schrieb:
> Klaus 2m5 schrieb:
>> Das stand schon in Antwort #2:
>>
>> Skript Kiddy schrieb:
>>> Wahrscheinlich ist eine der Datenleitungen von PCF8574 zum Display nicht
>>> richtig angeschlosen.
>>>
>>> tippe mal auf DB7.
>
> Ich hatte an den PINs eine Pegel von 4,95V gemessen, jedoch sagt das
> leider nichts über die Flanken aus.

Bei deinen Wartezeiten bis zum Toggeln des E-Pins sind die Flanken 
ziemlich egal. Ich tippe eher auf eine kalte Lötstelle oder sowas 
ähnliches. Wenn du jetzt mit deinem Multimeter draufgehst, schliesst du 
den Kontakt, der ansonsten offen ist.

von Klaus 2. (klaus2m5)


Lesenswert?

Karl heinz Buchegger schrieb:
> Bei deinen Wartezeiten bis zum Toggeln des E-Pins sind die Flanken
> ziemlich egal. Ich tippe eher auf eine kalte Lötstelle oder sowas
> ähnliches. Wenn du jetzt mit deinem Multimeter draufgehst, schliesst du
> den Kontakt, der ansonsten offen ist.

Sehe ich auch so. Keiner kann vorhersagen, was bei einer instabilen 
hochohmigen Verbindung passiert und wann das Signal am Empfänger 
tatsächlich dem gesendeten entspricht oder wann nicht.

von Gerald *. (pyromane)


Lesenswert?

Karl heinz Buchegger schrieb:
> Bei deinen Wartezeiten bis zum Toggeln des E-Pins sind die Flanken
> ziemlich egal. Ich tippe eher auf eine kalte Lötstelle oder sowas
> ähnliches. Wenn du jetzt mit deinem Multimeter draufgehst, schliesst du
> den Kontakt, der ansonsten offen ist.
Ich greife das Signal mit Klemmen am DB7 ab, sobald ich die 
Messleitungen am Multimeter abstecke tritt der Fehler wieder auf.
Beim übertragen der Werte 94h 14h an den PCF8574 merkte ich einen 
kurzzeitigen Spannungseinbruch auf 3,6V am BD7, jedoch nicht an den 
anderen PINs. Leider ist das Multimeter zu träge um genaueres zu sagen.

Wünsche noch einen schönen Abend
Gruß Pyromane

von OpenCollectör (Gast)


Lesenswert?

Pullups an die PCF-Ausgänge.

Also 4k7 (oder irgendwas zwischen 1k und 15k) zwischen + und jede der 
acht Leitungen zwischen PCF und LCD.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.