Hi Thorsten,
also mal was zum PCF8574 ...
Ich beschreibe nun mal den ganzen internen Aufbau. Bitte lies es dir GENAU durch. Notfalls mehrere male. Überfliege es nicht sondern lese es langsam und sorgfältig.
Zuerst mal das interne Blockschaltbild.
Wie man sieht werden immer 8 Bit (alle IO-Pins) auf einmal bearbeitet. Also entweder alle auf einmal gelesen oder geschrieben. Der rechte Block I/O-Port ist im nachfolgenden Bild noch einmal genauer zu sehen ...
EIN Pin vom I/O-Port. Also nur einer der 8 Anschlüsse weil es sonst unübersichtlich wird.
Links kommen die ganzen Steuer- und Datenleitungen der internen Steuerlogik vom Chip. Rechts geht es bei "P0 to P7" zum I/O-Pin (also zum IC-Beinchen).
Nach Low (0, GND oder V
SS) kann er direkt über den Transistor schalten. Dort verträgt der Pin laut Datenblatt maximal 25mA.
Wenn man nach High (1, +5V oder V
DD) schaltet, dann ist dort am oberen Transistor eine Konstantstromquelle mit eingebaut. Nach High liefert der Pin also nur 100µA (
Mikroampere) an den Ausgang.
Diese Konstantstromquelle kann man auch als PullUp-Widerstand zweckentfremden.
Wenn man also etwas an den I/O-Pin anschließen will, dann sollte man das folgendermaßen machen ...
- Eingänge von anderen ICs benötigen normalerweise wenig Strom und können direkt angeschlossen werden.
- Eine LED legt man mit einem Vorwiderstand zwischen +5V und dem IC-Beinchen. Wenn man auf Low (0, GND) schaltet, dann leuchtet sie.
- Wenn man mehr Strom benötigt, dann wird an dem IC-Beinchen ein Transistor (MIT Basisvorwiderstand) angeschlossen, der dann die Last schalten kann.
- Wenn man einen Taster anschließen möchte, dann legt man den vom IC-Beinchen nach GND. Damit kann man dann die interne Konstantstromquelle als PullUp-Widerstand verwenden indem man bei einem Schreibzugriff eine 1 an diese Stelle setzt. Das MUSS man auch so tun. Wenn man den Taster drückt, dann liest man bei einem Lesezugriff auf das IC an der Stelle des Bytes eine 0 ein da der Taster ja den Pin auf GND zieht. Durch die Konstantstromquelle im IC kann nichts kaputt gehen.
WICHTIG! Wenn man von außen an das IC-Beinchen +5V anlegt (zB mit einem Taster nach Vcc/+5V) und dann eine Null (Low) an die entsprechende Stelle für den IO-Pin schreibt, dann hat man einen
KURZSCHLUSS von Vcc, über den Taster, dann in das IC-Beinchen und den internen Transistor nach GND. Eine sichere Methode um ICs zu schrotten!
Man sollte also bei einem Schreibzugriff bei allen Bits die als Eingang verwendet werden eine EINS reinschreiben! Das kann man auch im Datenblatt lesen ...
7.3 Quasi-bidirectional I/Os
A quasi-bidirectional I/O can be used as an input or output without the use of a control signal for data direction (see Fig.15). At power-on the I/Os are HIGH. In this mode only a current source to VDDis active. An additional strong pull-up to VDDallows fast rising edges into heavily loaded outputs. These devices turn on when an output is written HIGH, and are switched off by the negative edge of SCL. The I/Os should be HIGH before being used as inputs. A quasi-bidirectional I/O can be used as an input or output without the use of a control signal for data direction (see Fig.15). At power-on the I/Os are HIGH. In this mode only a current source to VDDis active. An additional strong pull-up to VDDallows fast rising edges into heavily loaded outputs. These devices turn on when an output is written HIGH, and are switched off by the negative edge of SCL. The I/Os should be HIGH before being used as inputs.
Hier nun ein Schreibzugriff (also eine Ausgabe)
Das hast du ja soweit auch schon umgesetzt ...
Code:
I2cstart ' Startsignal auf dem I2C-Bus senden. Anfang vom Transfer
I2cwbyte PCF8574_Schreibadresse ' Mit der Schreibadresse dem IC sagen das
' das nächste Byte ausgegeben werden soll
I2cwbyte Daten_Byte ' Nun das Byte senden was ausgegeben werden soll
I2cwbyte Daten_Byte ' und noch ein Byte in das Ausgaberegister senden
I2cstop ' Stopsignal auf dem I2C-Bus senden. Transfer ist zu Ende
Du sagst dem PCF8574 also mit der Schreibadresse das er das nachfolgende Byte (Daten_Byte) in das Ausgaberegister schreiben soll.
Wenn du keine Stop-Bedingung sendest, dann schreibt der PCF8574 weiter jedes empfangene Byte vom I2C-Bus in sein Ausgaberegister und damit auf seine IC-Beinchen/IO-Pins. Erst durch die Stop-Bedingung weiß der PCF8574 das es nun zu Ende ist und er "wieder Ruhe" hat.
Und nun der Lesegrugriff (also eine Eingabe/Abfrage der IO-Pins)
Das ist auch so ähnlich wie der Schreibzugriff. Nur das sich nach dem Senden der Adresse quasi "Master und Slave umdrehen". Der Atmel wird also beim Daten lesen nach dem Senden der Adresse quasi zum "Slave" (Nennt sich genau gesagt Masterreceiver). Das geht nun also folgendermaßen ...
Code:
I2cstart ' Startsignal auf dem I2C-Bus senden. Anfang vom Transfer
I2cwbyte PCF8574_Leseadresse ' Mit der Leseadresse dem IC sagen das
' das er nun mit Daten senden dran ist
I2crbyte Daten_Byte , Ack ' Ein Byte aus dem Eingaberegister (von den IO-Pins) lesen
I2crbyte Daten_Byte , Nack ' Und nochmal die IO-Pins abfragen und mit NACK alles beenden
I2cstop ' Stopsignal auf dem I2C-Bus senden. Transfer ist zu Ende
Man sagt dem PCF8574 nun also mit der Leseadresse das er dran ist mit Daten senden. Der Atmel liest nun vom I2C-Bus das vom PCF8574 gesendete Byte ein. Das Byte zeigt Eins-zu-Eins den Zustand der IO-Pins vom PCF8574. Hier hab ich beim ersten Lesen ein ACK gesetzt (Acknowledge). Damit sagt der Atmel dem PCF8574 ... alles OK ich will weiterlesen. Dann lese ich ein zweites Mal die IO-Pins ein (einfach mal aus Spaß). Nun sage ich aber NACK (Negative Acknowledge). Das sagt dem PCF8574 ... der Atmel hat genug und ich kann aufhören. Der PCF8574 legt sich also nach diesem NACK dann zur Ruhe. Das folgende I2CSTOP gibt den I2C-Bus dann wieder frei.
Die 4 Grafiken sind eigentlich die wichtigsten aus dem gesamten Datenblatt. Ich habe, soweit wie in der Kürze möglich, alles nochmal genau erklärt. Normalerweise sollten keine Fragen mehr zum PCF8574 offen sein.
Als Beispiel noch ein kleiner Programmschnipsel ...
Code:
DIM PCF8574_Lesedaten AS BYTE
DIM PCF8574_Sendedaten AS BYTE
PCF8574_Sendedaten = &B1101_0111 ' Alle Pins auf High die Eingaenge sein sollen
' P0-P2 ist Eingang (Taster)
' P3 ist Ausgang (Relais ueber Transistor)
' P4 ist Eingang (Taster)
' P5 ist Ausgang (LED nach Vcc)
' P6-P7 ist Eingang (Taster)
RESET PCF8574_Sendedaten.5 ' Pin5 des PCF8574 auf 0 (GND) setzen (zB LED5 anschalten)
RESET PCF8574_Sendedaten.3 ' Pin3 des PCF8574 auf 1 (Vcc) setzen (zB Relais1 anschalten)
I2cstart ' Startsignal auf dem I2C-Bus senden. Anfang vom Transfer
I2cwbyte PCF8574_Schreibadresse ' Mit der Schreibadresse dem IC sagen das
' das nächste Byte ausgegeben werden soll
I2cwbyte PCF8574_Sendedaten ' Nun das Byte senden was ausgegeben werden soll
I2cstop ' Stopsignal auf dem I2C-Bus senden. Transfer ist zu Ende
I2cstart ' Startsignal auf dem I2C-Bus senden. Anfang vom Transfer
I2cwbyte PCF8574_Leseadresse ' Mit der Leseadresse dem IC sagen das
' das er nun mit Daten senden dran ist
I2crbyte PCF8574_Lesedaten , Nack ' Ein Byte aus dem Eingaberegister (von den IO-Pins) lesen
I2cstop ' Stopsignal auf dem I2C-Bus senden. Transfer ist zu Ende
' In der Variable PCF8574_Lesedaten findet man nun in den entsprechenden
' Bits die Zustände der IO-Pins vom PCF8574
Gruß
Dino