C Portexpander PCF8574

avr_newbie

Mitglied
13. Apr. 2013
127
0
16
Bayern
Sprachen
  1. ANSI C
Hallo,

ich habe gerade ein kleines Problem. Ich probier gerade dieses Beispiel aus:
http://www.mikrocontroller.net/articles/Port-Expander_PCF8574

Beim lesen der Eingänge hängt sich alles auf, sobald ich am P7 des Portexpanders Masse lege.
Jedoch bekomm ich den Wert noch, also return von "pcf8574_get_inputs" bekomm ich noch.
danach, hängts....

Bei den anderen Eingängen funktioniert es aber wunderbar !



Jetzt hab ich festgestellt, wenn ich bei der Funktion pcf8574_get_inputs "pcf8574_send_stop ();" auskommentier dann funktoniert es?

Kann mir das jemand erklären? Bin ziemlich ratlos.... :confused:
 
Hi,

ich habe gerade ein kleines Problem. Ich probier gerade dieses Beispiel aus:
http://www.mikrocontroller.net/artic...pander_PCF8574
ähhmm ... da bin ich auch ratlos weil dein Link nicht funktioniert. Da wurde zuviel durch Punkte ersetzt :rolleyes:

Beim lesen der Eingänge hängt sich alles auf, sobald ich am P7 des Portexpanders Masse lege.
Jedoch bekomm ich den Wert noch, also return von "pcf8574_get_inputs" bekomm ich noch.
danach, hängts....

Bei den anderen Eingängen funktioniert es aber wunderbar !

Jetzt hab ich festgestellt, wenn ich bei der Funktion pcf8574_get_inputs "pcf8574_send_stop ();" auskommentier dann funktoniert es?
hört sich alles irgendwie nach C an wenn ich den Rest richtig interpretiere.

Gruß
Dino
 
oh ^^...

ist korrigiert...
Das Beispiel kann man sich unten am Seitenende runterladen....
link:
www.mikrocontroller.net/mc-project/Pages/Projekte/ICs/Port%20Expander/Portexpander%20Beispiel.zip

mhh... neue erkenntnis:

es liegt wohl an " pcf8574_read_byte"
Und es scheint ein ACK-Problem zu sein?

wenn ich

TWCR = (1<<TWINT) | (1<<TWEN);

in pcf8574_read_byte verwende , klappts auch .... nur ist mir nicht ganz klar, wieso dieser Effekt auftritt, vorallem nur bei P7 des Expanders

Code:
unsigned char pcf8574_read_byte (void)
{
    /*send content of TWDR; TWEA = enable ACK*/
    TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
    /*wait, until byte has been received --> ACK*/
    while (!(TWCR & (1<<TWINT)));
    
    return TWDR;
}


Hi,


ähhmm ... da bin ich auch ratlos weil dein Link nicht funktioniert. Da wurde zuviel durch Punkte ersetzt :rolleyes:


hört sich alles irgendwie nach C an wenn ich den Rest richtig interpretiere.

Gruß
Dino
 
wieder neue erkenntnis ^^ hab immer noch das problem
aber, hab festgestellt, dass es in der while schleife dann hängen bleibt, und zwar in der folgenden funktion:

Code:
unsigned char pcf8574_send_start (void)
{
    /*writing a one to TWINT clears it, TWSTA=Start, TWEN=TWI-enable*/
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    /*wait, until start condition has been sent --> ACK*/
    while (!(TWCR & (1<<TWINT)))
    {
        Display_DisplayDecimal8(90,90,1);
    }
    return TWSR;
}

Also zusammengefasst:

ruf ich die funktion pcf8574_get_inputs auf und leg P7 des Expanders auf Masse:

Code:
unsigned char pcf8574_get_inputs (unsigned char address)
{
    pcf8574_init ();
    pcf8574_send_start ();
    pcf8574_send_add_rw (address, 1);
    unsigned char input = pcf8574_read_byte ();
    pcf8574_send_stop ();
    return input;
}

Dann bekom ich noch das return. Da ich dauernd die Eingänge einlese - in ner schleife - hängt es dann beim nächsten mal einlesen, und zwar in pcf8574_send_start, in der while schleife.
Es bleibt aber komischerweise nur beim P7 in der while schleife hängen.

Kann mir da jemand helfen ?
 
besteht zwischen diesen zwei code zeilen ein unterschied?
Code:
	TWCR = 0;
	
	TWCR |= (1<<TWINT) ;
	TWCR |=  (1<<TWSTA);
	TWCR |= (1<<TWEN);

Code:
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
 
Mal davon abgesehen dass obriges weniger lesbar ist.

Also wenn der Compiler das nicht zufällig weg optimiert (was ich nicht glaube) setzt du jedes einzelne Bit. Also Wert laden, das OR mit dem neuem Wert, zurück schreiben. Und das 3x. Vielleicht kommt der Controller auch dabei etwas durcheinander, aber da ich I²C/TWI nicht nutze kann ich dazu nichts sagen.

Beim unterem weist du den Wert direkt zu. Eine Operation.
Sollte man auch immer so machen, außer wenn es nicht anders geht (die Prozedur den Watchdog abzuschalten ist zum Beispiel so etwas wo bestimmte Bits in bestimmten Zeitabständen gesetzt werden müssen)


Zum Rest kann ich leider nichts sagen.


Edit zum Post unter mir (muss ja nich extra n neuen machen):
Edit: Bäh... Thomas war schon wieder schneller...
Du dafür ausführlicher ;)
 
strenggenommen ja.
Bei Variante 1 werden zuerst alle Bits des Zielregisters mit einer 0 beschrieben (2 oder 3 Takte, je nach Registeradresse), was bei dem Flag nichts ändert. Danach werden nacheinander die 3 Bits einzeln gesetzt (bzw bei dem Flag dadurch selbiges gelöscht). Je nach Registeradresse (und Controller) kostet das jeweils zwischen 2 (SBI) bis 5 (LDS/ORI/STS) Takte.
Bei Variante 2 werden alle 3 Bits gleichzeitig ins Zielregister geschrieben, einmal. 2-3 Takte.

Also einerseits liegt das Resultat bei Variante 2 schneller vor, andererseits tritt hier die Wirkung der 3 gesetzten Bits gleichzeitig ein. Bei Variante 1 werden erstmal alle Bits bis auf das Flag gelöscht (mit 0 beschrieben) - ein ggf gesetztes Twint bleibt gesetzt. Dann wird Twint gelöscht (1 schreiben) - die anderen Bits sind weiterhin 0. Dann wird Twsta gesetzt (obwohl alle anderen Bits weiterhin 0 sind - insbesondere auch TWEN... kA, wie sich das mit der StartCondition da auswirkt. eigentlich sollte Twen da immer aktiv bleiben - mal ins DB schauen...).
Als letztes wird da Twen gesetzt.

Bei Variante 1 werden alle Bits wirklich mit einer 0 beschrieben (jaja, das Flag interessierts nicht), wenn auch nur kurz. Insbesondere wird also auch TWEN kurz 0. Bei Variante 2 werden die 3 Bits einfach mit 1 (Flag blabla), alle anderen mit 0 beschrieben. Egal, was da vorher stand. War TWEN vorher 1, bleibt es durchgehend 1.

Edit: Bäh... Thomas war schon wieder schneller...
Knackpunkt ist aber, daß bei Variante1 kurzzeitig das TWI deaktiviert wird, und somit die entsprechenden Pins auch kurzzeitig zu regulären I/Os entsprechend dem DDR/PORT-Registern...
 
hmm.... das komische ist, wenn ich die bits einzeln setz, dann tritt der Fehler wie oben beschrieben nicht mehr auf.

dass hat dann wohl damit zu tun, , daß bei Variante1 kurzzeitig das TWI deaktiviert wird - wie du beschrieben hast?? ...
dann frag ich mich, was dann falsch läuft.... -.-

wenn ichs so mach:
Code:
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
dann tritt der fehler auf....
 
So liebe Gemeinde :D

Ich habe festgestellt, dass das bit TWSTO gesetzt wird, wenn ich P7 des Expanders als Eingang verwende.
Meine Abhilfe ist bisher, das Bit zu löschen in "pcf8574_send_start". Nur bin ich mir da nicht sicher, ob das eine gute Idee ist :confused:

Gibts denn hier keinen I²C Speziallisten? ;)

Code:
   void pcf8574_init (void)
{
	/*set bus speed*/
	TWBR = 0x10;
}


unsigned char pcf8574_send_start (void)
{
	/*writing a one to TWINT clears it, TWSTA=Start, TWEN=TWI-enable*/
	
	TWCR &= ~(TWSTO); //clear TWSTO - AVR BUG ? if P7 of Expander as Input
		
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
	/*wait, until start condition has been sent --> ACK*/
	while (!(TWCR & (1<<TWINT)));
	return TWSR;
}


void pcf8574_send_stop (void)
{
	/*writing a one to TWINT clears it, TWSTO=Stop, TWEN=TWI-enable*/
	
	TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
	
	//TWCR =0;
	//
	//TWCR |= (1<<TWINT) ;
	//TWCR |= (1<<TWSTO);
	//TWCR |= (1<<TWEN);
	//
}


unsigned char pcf8574_send_add_rw (unsigned char address, unsigned char rw)
{
	/*address can be 0 .. 8; rw=0 --> write, rw=1 --> read*/
	unsigned char addr_byte = 0;
	/*shift address one bit left*/
	addr_byte = address << 1;
	/*set RW-Bit, if necessary*/
	addr_byte |= rw;
	/*0b0100xxx0 --> address of Expander*/
	addr_byte |= 0b01110000;
	/*TWDR contains byte to send*/
	TWDR = addr_byte;
	/*send content of TWDR*/
	TWCR = (1<<TWINT) | (1<<TWEN);
	/*wait, until address has been sent --> ACK*/
	while (!(TWCR & (1<<TWINT)));
	return TWSR;
}


unsigned char pcf8574_send_byte (unsigned char byte)
{
	/*TWDR contains byte to send*/
	TWDR = byte;
	/*send content of TWDR*/
	TWCR = (1<<TWINT) | (1<<TWEN);
	/*wait, until byte has been sent --> ACK*/
	while (!(TWCR & (1<<TWINT)));
	return TWSR;
}


unsigned char pcf8574_read_byte (void)
{
	/*send content of TWDR; TWEA = enable ACK*/
	TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
	/*wait, until byte has been received --> ACK*/
	while (!(TWCR & (1<<TWINT)));
	return TWDR;
}


unsigned char pcf8574_get_inputs (unsigned char address)
{
	pcf8574_init ();
	pcf8574_send_start ();
	pcf8574_send_add_rw (address, 1);
	unsigned char input = pcf8574_read_byte ();
	pcf8574_send_stop ();
	return input;
}


void pcf8574_set_outputs (unsigned char address, unsigned char byte)
{
	pcf8574_init ();
	pcf8574_send_start ();
	pcf8574_send_add_rw (address, 0);
	pcf8574_send_byte (byte);
	pcf8574_send_stop ();
}
 
Hallo!

Ich weis zwar nicht was du genau auf deinem Display ausgeben willst, aber sollte das nicht eher so lauten:
Code:
unsigned char pcf8574_send_start (void)
{
    /*writing a one to TWINT clears it, TWSTA=Start, TWEN=TWI-enable*/
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    /*wait, until start condition has been sent --> ACK*/
    while (!(TWCR & (1<<TWINT)));
    Display_DisplayDecimal8(90,90,1);
   
    return TWSR;
}

Vielleicht hilfts ja weiter? :)

lg macgyver
 
Hallo!

Ich weis zwar nicht was du genau auf deinem Display ausgeben willst, aber sollte das nicht eher so lauten:
Code:
unsigned char pcf8574_send_start (void)
{
    /*writing a one to TWINT clears it, TWSTA=Start, TWEN=TWI-enable*/
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    /*wait, until start condition has been sent --> ACK*/
    while (!(TWCR & (1<<TWINT)));
    Display_DisplayDecimal8(90,90,1);
   
    return TWSR;
}


Vielleicht hilfts ja weiter? :)
lg macgyver

ne, das hilft nicht weiter ^^

das war schon so gewollt, dass es in der schleife ist..... war nur ne testausgabe....
 
I2C Bus

Hallo , noch eine Frage zum I2C - Bus.

Ich verwende den PCF8574.

Der Mikrokontroller wird mit 5V versorgt. der PCF auch mit 5V (aber externe 5V / also nicht die gleiche Versorgungsspannung wie der Mikrokontroller).
Funktoniert das dann noch wegen den SCL/SDA Pegeln, oder kann es da zu Problemen kommen, wenn nicht das selbe Bezugspotenzial vorhanden istt?
 
Die Spannungen dürfen nicht zu weit auseinander liegen. Aber da beides 5V ist, ok.
Nur gemeinsame Masse müssen sie haben.
 
Hallo,

Der Mikrokontroller wird mit 5V versorgt. der PCF auch mit 5V (aber externe 5V / also nicht die gleiche Versorgungsspannung wie der Mikrokontroller).
Funktoniert das dann noch wegen den SCL/SDA Pegeln, oder kann es da zu Problemen kommen, wenn nicht das selbe Bezugspotenzial vorhanden ist?

So wie TommyB schon geschrieben hat müssen die Massen verbunden sein. Denn DIE sind dein Bezugspotential. Auf GND beziehen sich alle Spannungen in der Schaltung.

Wenn du Vcc (+5V) als Bezugspotential nehmen würdest, dann wäre Vcc sozusagen 0V und GND dann logischerweise -5V :p :confused: :cool: Alles eine Sache der Definition. Früher war das öfter in Schaltungen mit PNP-Transistoren zu sehen. Aber normalerweise ist GND = 0V und auch dein Bezugspotential.

Gruß
Dino
 
Falls jemand das unten beschriebene Problem auch hat. Verwendet nicht das Beispiel, wie im Link angegeben.
Ich arbeite jetzt mit der I2C Bibliothek von Peter Fleury. Mit der kann ich den PCF auch wunderbar ansteuern.

Allerdings habe ich auch diese Routinen geändert da diese einen kleinen Nachteil hat. Da hier While-Schleifen verwendet werden, kann es passieren, dass quasi der Bus/bzw. der ganze Controller in der Schleife hängen bleibt, wenn ein Fehler auftritt, bzw. der Baustein nicht mehr erreichbar ist oder.....
Ich habe dazu ein Timeout gesetzt, damit nach einer bestimmten Zeit bei einem Fehler, aus der Schleife gesprungen wird. und der Bus neu in initialisiert wird.

oh ^^...

ist korrigiert...
Das Beispiel kann man sich unten am Seitenende runterladen....
link:
www.mikrocontroller.net/mc-project/Pages/Projekte/ICs/Port%20Expander/Portexpander%20Beispiel.zip

mhh... neue erkenntnis:

es liegt wohl an " pcf8574_read_byte"
Und es scheint ein ACK-Problem zu sein?

wenn ich

TWCR = (1<<TWINT) | (1<<TWEN);

in pcf8574_read_byte verwende , klappts auch .... nur ist mir nicht ganz klar, wieso dieser Effekt auftritt, vorallem nur bei P7 des Expanders

Code:
unsigned char pcf8574_read_byte (void)
{
    /*send content of TWDR; TWEA = enable ACK*/
    TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
    /*wait, until byte has been received --> ACK*/
    while (!(TWCR & (1<<TWINT)));
    
    return TWDR;
}
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)