Hallo,
ich habe gerade ein paar Probleme mit einem PCF8574.
Ich möchte ihn mit der I²C Lib von Peter Fleury in C ansteuern.
So funktioniert das auf jeden Fall:
1
i2c_start_wait(0x70+I2C_WRITE);
2
i2c_write(0xff);
3
i2c_stop();
Ist ja auch soweit nicht sonderlich schwer. Jetzt möchte ich aber LEDs
einzeln aus- und anschalten. Ich kann die Ports ja nicht einzeln setzen.
Ich muss immer alle zusammen in Binär bzw. Hex senden. Wenn ich also
eine LED setze, weiß ich ja nicht, ob eine andere schon an ist, die
würde ich so, wie das oben gemacht wird ja ausschalten. Ich müsste also
erst die Ports auslesen und in eine Variable schreiben, dann diese
Variable so ändern, dass z.B. das 4. Bit gesetzt oder gelöscht wird. Wie
mache ich das? Soweit bin ich schon:
1
voidsetPortPCF8574(uint8_tadr,uint8_tport,uint8_tsetOrDel)//Adresse, Pin Nr., die gesetzt/gelöscht werden soll, Pin setzen oder löschen
2
{
3
i2c_start_wait(adr+I2C_WRITE);//I²C Kommunikation starten (schreiben)
ports=(ports|(1<<port));//sonst (z.B. bei 1) Pin setzen
15
}
16
17
i2c_start_wait(adr+I2C_WRITE);//I²C Kommunikation starten (schreiben)
18
i2c_write(ports);//ports senden
19
i2c_stop();//I²C Kommunikation stoppen
20
}
Das funktioniert aber irgendwie nur halb... So z.B.:
1
setPortPCF8574(0x70,4,1);
2
_delay_ms(500);
3
setPortPCF8574(0x70,4,0);
4
_delay_ms(500);
5
setPortPCF8574(0x70,4,1);
6
_delay_ms(500);
7
setPortPCF8574(0x70,4,0);
8
_delay_ms(500);
9
setPortPCF8574(0x70,4,1);
10
_delay_ms(500);
blinkt die LED an P4, so, wie es sein sollte.
Hier:
1
setPortPCF8574(0x70,4,1);
2
_delay_ms(500);
3
setPortPCF8574(0x70,5,1);
4
_delay_ms(500);
5
setPortPCF8574(0x70,6,1);
6
_delay_ms(500);
7
setPortPCF8574(0x70,7,1);
8
_delay_ms(500);
9
setPortPCF8574(0x70,7,0);
10
_delay_ms(500);
11
setPortPCF8574(0x70,6,0);
12
_delay_ms(500);
13
setPortPCF8574(0x70,5,0);
14
_delay_ms(500);
15
setPortPCF8574(0x70,4,0);
16
_delay_ms(500);
hängt sich der ATmega8 aber beim Ausschalten der LEDs (letzter
Übergabeparameter 0) auf. So:
1
setPortPCF8574(0x70,4,1);
2
_delay_ms(500);
3
setPortPCF8574(0x70,5,1);
4
_delay_ms(500);
5
setPortPCF8574(0x70,6,1);
6
_delay_ms(500);
7
setPortPCF8574(0x70,7,1);
8
_delay_ms(500);
9
10
i2c_start_wait(0x70+I2C_WRITE);
11
i2c_write(0xff);//Alle LEDs aus
12
i2c_stop();
13
14
setPortPCF8574(0x70,7,0);
15
_delay_ms(500);
16
setPortPCF8574(0x70,6,0);
17
_delay_ms(500);
18
setPortPCF8574(0x70,5,0);
19
_delay_ms(500);
20
setPortPCF8574(0x70,4,0);
21
_delay_ms(500);
gehen die, nachdem alle eingeschaltet wurden, alle ordnungsgemäß aus.
Das Programm hängt sich aber nicht auf.
So wiederum:
1
setPortPCF8574(0x70,4,1);
2
3
_delay_ms(500);
4
setPortPCF8574(0x70,5,1);
5
6
_delay_ms(500);
7
8
setPortPCF8574(0x70,6,1);
9
10
_delay_ms(500);
11
12
setPortPCF8574(0x70,7,1);
13
14
_delay_ms(500);
15
16
17
i2c_start_wait(0x70+I2C_WRITE);
18
i2c_write(0xff);//Alle LEDs aus
19
20
i2c_stop();
21
22
setPortPCF8574(0x70,7,1);
23
24
_delay_ms(500);
25
setPortPCF8574(0x70,6,1);
26
27
_delay_ms(500);
28
29
setPortPCF8574(0x70,5,1);
30
31
_delay_ms(500);
32
33
setPortPCF8574(0x70,4,1);
34
35
_delay_ms(500);
gehen die LEDs erst der Reihe nach an, dann alle aus, dann geht eine an,
dann hängt sich das Programm auf.
Alles etwas merkwürdig...
Danke und
Viele Grüße
Jan
auskommentiere/lösche, gehen die LEDs der Reihe nach aus. Wenn ich aber
z.B. schreibe:
1
setPortPCF8574(0x70,4,1);
2
3
_delay_ms(500);
4
setPortPCF8574(0x70,5,1);
5
6
_delay_ms(500);
7
8
setPortPCF8574(0x70,7,1);
9
10
_delay_ms(500);
11
12
setPortPCF8574(0x70,6,1);
13
14
_delay_ms(500);
15
16
17
setPortPCF8574(0x70,7,0);
18
19
_delay_ms(500);
20
setPortPCF8574(0x70,6,0);
21
22
_delay_ms(500);
23
24
setPortPCF8574(0x70,5,0);
25
26
_delay_ms(500);
27
28
setPortPCF8574(0x70,4,0);
29
30
_delay_ms(500);
,also zuerst versuche, die LED an P7 anzuschalten, hängt sich das
Programm auch auf. P4 und P5 gehen an. Also immer, wenn ich die LED an
P7 versuche, anzuschalten...
Jan B. schrieb:> würde ich so, wie das oben gemacht wird ja ausschalten. Ich müsste also> erst die Ports auslesen und in eine Variable schreiben, dann diese> Variable so ändern, dass z.B. das 4. Bit gesetzt oder gelöscht wird. Wie> mache ich das?
Du versuchst erst gar nicht auszulesen, sondern du hast eine Variable im
Programm in der du dir ständig die aktuelle Ausgabe merkst. Wenn du eine
LED einschalten willst, dann setzt du das entsprechende Bit in dieser
Variablen (oder löscht es, je nachdem) und gibst die neue Belegung
komplett als Byte aus.
Der Baustein verändert von sich aus die Ausgabe nicht, also musst du
auch nicht den Aufwand treiben, da jedesmal die aktuelle Ausgabe vom
Baustein zu lesen, wenn du sie auch ganz einfach im Programm in einer
Variablen mitführen kannst.
Bit setzen
Variable |= ( 1 << Bitnummer );
Bit löschen
Variable &= ~( 1 << Bitnummer );
Bitmanipulation
Hallo,
bist Du Dir da sicher? Soweit ich weiß, geht das beim PCF8574 nicht. Ich
habe das Problem auch gelöst: In meinem void muss man beim Abfragen
nicht schreiben i2c_readAck, sondern i2creadNak.
Trotzdem danke und
Viele Grüße
Jan
Jan B. schrieb:> Hallo,> bist Du Dir da sicher? Soweit ich weiß, geht das beim PCF8574 nicht.
Was geht nicht?
Du hast doch oben geschrieben, dass das hier ...
1
i2c_start_wait(0x70+I2C_WRITE);
2
i2c_write(0xff);
3
i2c_stop();
... funktioniert.
Also was hindert dich jetzt daran
1
uint8_tportState;
2
3
voidSetBit(uint8_tbitNr)
4
{
5
portState|=(1<<bitNr);
6
7
i2c_start_wait(0x70+I2C_WRITE);
8
i2c_write(portState);
9
i2c_stop();
10
}
11
12
voidClearBit(uint8_tbitNr)
13
{
14
portState&=~(1<<bitNr);
15
16
i2c_start_wait(0x70+I2C_WRITE);
17
i2c_write(portState);
18
i2c_stop();
19
}
Selbst mit dem variablen Bitshift geht das immer noch schneller, als
wenn du vorher mittels I2C den vorliegenden Status des Portes ausliest.
Hallo,
OK, jetzt habe ich es verstanden. Danke für den Tip, probiere ich aus!
Das mit dem Auslesen hat aber den Vorteil, dass ich, nachdem mein ATmega
resetet wurde, ich immer noch weiß, was vorher gesetzt war und was
nicht. Dann könnte man aber einfach eine Abfrage am Anfang des Programms
machen.
Nochmal Danke und
Viele Grüße
Jan
@ Jan Blumenkamp (diphthong)
>Das mit dem Auslesen hat aber den Vorteil, dass ich, nachdem mein ATmega>resetet wurde, ich immer noch weiß, was vorher gesetzt war und was>nicht.
Stimmt nicht. Ein Schreibzugriff setzt die Open Drain Ausgänge (write
only), ein Lesezugriff liefert den Zustand der Pins (read only). Je nach
Aussenbeschaltung kann man sich da irren.
http://www.mikrocontroller.net/articles/Port-Expander_PCF8574
MFG
Falk