Forum: Mikrocontroller und Digitale Elektronik (AVR-gcc) Lesen vom PCF8574 I2C-Port-Expander gelingt nicht


von Christian S. (roehrenvorheizer)


Angehängte Dateien:

Lesenswert?

Hallo,

in der Datei pcf8574_experiment.c wollte ich gezielt untersuchen, warum 
das Lesen vom Port-Expander nicht funktioniert.
Trotz mehrerer Versuche und Nachlesen über das TWI sowie im Forum sind 
die Versuche ergebnislos geblieben.



Ich verwende pcf8574.c und pcf8574.h von diesem vorgefertigten Beispiel 
hier:

http://www.mikrocontroller.net/articles/Port-Expander_PCF8574
http://www.mikrocontroller.net/mc-project/Pages/Projekte/ICs/Port%20Expander/Portexpander%20Beispiel.zip


Aufruf im Hauptprogramm erfolgt dann mit diesen Zeilen hier:
//Port-Expander bedienen:
//Adresse des Portexpanders PCF8574: A2, A1, A0 sind auf GND gelötet 
-->> 0100 000 = 0x40
  /*address can be 0 .. 8; rw=0 --> write, rw=1 --> read*/
//  pcf8574_set_outputs (i, j);    //PCF8574: A2, A1, A0 sind auf GND 
gelötet -->> 0100 000X = 0x40 oder ein Bit nach

rechts verschoben: 0x20
//  pcf8574_set_outputs (0x20, i);    //PCF8574 hat Adresse 0x20!!! 
<<<---<<<--- OK funktioniert 0x20 ist falsch, da UP

0..8 erwartet.!!!!!!!!!!!!!<<<---<<<---
//  pcf8574_set_outputs (0, i);    //PCF8574 hat Adresse 0 !!! 
<<<---<<<--- OK funktioniert. 0x20 ist falsch, da

UP 0..8 erwartet.!!!!!!!!!!!!!<<<---<<<---
  /*address can be 0 .. 8; rw=0 --> write, rw=1 --> read*/

//  input = pcf8574_get_inputs (0x20);  //PCF8574: A2, A1, A0 sind auf 
GND gelötet -->> 0100 000 = 0x40
//  pcf8574_set_outputs (0, 0xFF);    //Ausgänge sollen vor dem Lesen 
high sein!
  input = pcf8574_get_inputs (0);  //PCF8574: A2, A1, A0 sind auf GND 
gelötet -->> 0100 000 = 0x40
  GLCD_WriteString(6,0, itoa( input, s, 10));  //Stelle6, Zeile1, 
Ausgabe des gelesenen Bytes vom PCF8574
//Ende Port-Expander bedienen





Gut funktioniert das Schreiben euf ein LCD siehe 
dg14032-demo24C08_11:I2C_LCD_speed-test.c.


Kann mal bitte jemand schauen, ob in der Datei pcf8574_experiment.c im 
Unterprogramm "pcf8574_get_inputs" und "pcf8574_read_byte"
ein Fehler enthalten ist?


mit freundlichem Gruß

von Patrick C. (pcrom)


Lesenswert?

Versuch mal ob das schreiben Komplett gut geht - ich meine ob du da das 
korrekte ACK-abhandlung messt. Kannst du einen Oscilloscope drauf setzen 
?

von Christian S. (roehrenvorheizer)


Lesenswert?

Danke für den Hinweis. Ich werde mir mal die Signale auf dem Bus 
ansehen. Vielleichts stimmt dabei schon etwas nicht und man kann daraus 
Rückschlüsse ziehen, welcher Befehl da nicht greift.

Rückmeldung morgen dann...

MfG

von spess53 (Gast)


Lesenswert?

Hi

>unsigned char pcf8574_get_inputs (unsigned char address)
>{
>  unsigned char input;>
>  pcf8574_init ();
>  pcf8574_send_start ();

>  pcf8574_send_add_rw (address, 0);      //Adresse
>  pcf8574_send_byte (0xFF);
                             <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>  pcf8574_send_add_rw (address, 1);Adresse senden und Lesen einstellen
>  pcf8574_read_byte ();

<<<<<<<<<<<<<<< Da fehlt eine repeated start condition.

MfG Spess

von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,


danke für den Hinweis. Da habe ich also noch einen Fehler zusätzlich 
eingebaut, weil ich innerhalb der Leseroutine erst die Ausgänge auf high 
setzen wollte.
Mit dem repeated-start geht es auch nicht.

Nun geht es aber:
Schaltet man direkt zu +5V, wird entsprechend eingelesen, das Display 
reagiert und auf dem Oszilloskop sieht man schön das entsprechende Bit.
Die Ausgänge stehen auf high, die offenen Eingänge lesen aber 0 = 
0b00000000 aus. Die Ausgänge liegen auf ca 2 Volt bei high.
Kontakt zu +5V setzt das dem Pin entsprechende Bit. Mein Denkfehler war, 
die auf high stehenden Ausgänge mit GND verbinden zu wollen.


Das hätte man auch ohne Oszilloskop hinbekommen können ;-)

funktionierender Code:
unsigned char pcf8574_get_inputs (unsigned char address)
{
  unsigned char input;
  pcf8574_init ();
  pcf8574_send_start ();

  pcf8574_send_add_rw (address, 1);//Adresse senden und Lesen einstellen
  input = pcf8574_read_byte ();

  pcf8574_send_stop ();
  return input;
}


unsigned char pcf8574_read_byte (void)
{
  /*send content of TWDR; TWEA = enable ACK*/
//  TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);  //<<<<<<------- Programm 
bleibt beim Lesen hängen
  TWCR = (1<<TWINT) | (1<<TWEN);        //<<<<<<--<<--<- Programm läuft 
durch, liest einzelnes Byte

  /*wait, until byte has been received --> ACK*/
  while (!(TWCR & (1<<TWINT)));
  return TWDR;
}

//Aufruf aus dem Hauptprogramm:
input = pcf8574_get_inputs (0);  //PCF8574: A2, A1, A0 sind auf GND 
gelötet


MfG

von spess53 (Gast)


Lesenswert?

Hi

>  /*send content of TWDR; TWEA = enable ACK*/
>//  TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);  //<<<<<<------- Programm
>bleibt beim Lesen hängen
>  TWCR = (1<<TWINT) | (1<<TWEN);        //<<<<<<--<<--<- Programm läuft
>durch, liest einzelnes Byte

Das ist aber nicht allgemein gültig. Beim Lesen vom Slave muss der 
Master vor der Stop Condition ein NAK (TWCR = (1<<TWINT) | (1<<TWEN);) 
senden. Da du hier nur ein Byte liest ist das so richtig.

Werden mehrere Bytes hintereinander, z.B. von einem EEPROM, gelesen, 
muss der Master, bis auf das letzte Byte, alle Bytes mit einem ACK (TWCR 
= (1<<TWINT) | (1<<TWEA) | (1<<TWEN)) bestätigen. Beim letzten Byte wird 
dann wieder mit NACK gelesen.

Lesenswert:

http://www.nxp.com/documents/user_manual/UM10204_JA.pdf

MfG Spess

von Christian S. (roehrenvorheizer)


Lesenswert?

Ich werde mich bei der Thematik  MCP 23017, Page read beim EEPROM, AVR 
als Slave und ähnlichem noch genügend damit austoben können.


MfG

von Christian S. (roehrenvorheizer)


Lesenswert?

hier der Link für NichtJapaner: (oute mich hier als solcher)

http://www.nxp.com/documents/user_manual/UM10204.pdf

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.