PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C PCF8574A Interruptleitung nutzen ??



Roberto
21.11.2006, 16:19
Hallo Leute

Habe da wieder ein Problem.. ](*,)

Möchte meinen Avr mit dem PCF8574A (I2C Expander) erweitern und dazu den Interruptausgang (INT)vom Baustein nutzen.

Der INT Pin zieht ja gegen Masse wenn am PCF8574er ein Pin auf Eingang geht.

Dazu habe ich vom AVR den INT0 Eingang verwendet, der mir bei fallender Flanke dann den PCF8574 auslesen soll...

Leider funktioniert das Ganze nicht so richtig.
Irgendwie spinnt der AVR dann und bringt nur mehr wirres Zeug oder bleibt hängen oder der Int0 reagiert nicht mehr ...

Das Ganze läuft normalerweise auf einem Mega32.
Zum testen und damit ich einen Minimalcode zum zeigen zusammenbekomme, habe ich das nochmal mit dem Mega8 aufgebaut.

Hier der Code:


'============ PCF 8574 versuch_2 mit INT0=================================

$regfile = "m8def.dat"
$crystal = 10000000

$hwstack = 250
$swstack = 250
$framesize = 250



'##################### Config für LCD ################################################## ##
Config Lcd = 40 * 2
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portb.1 , Db6 = Portb.2 , Db7 = Portb.3 , Rs = Portb.4 , E = Portb.5
Config Lcdbus = 4
Config Lcdmode = Port
Cursor On
Cls



'############################ Config I2C Bus ###################################
Config Scl = Portd.1 ' I2C-Port festlegen
Config Sda = Portd.0 ' I2C-Port festlegen

Config Portd.2 = Input 'Int0
Portd.2 = 1 'Pull up



'############################ Config INT0 #######################################
Config Int0 = Falling
On Int0 Int0_auswerten
Enable Int0


Dim Tasten As Byte
Dim Taste0 As Byte
Dim Taste1 As Byte
Dim Taste2 As Byte
Dim Zaehler As Word

Enable Interrupts

'################################################# ##############################

Do



'Tasten_lesen:
I2cstart
I2cwbyte &B01110001 'lese Adresse von PCF8574A
I2crbyte Tasten , Nack
I2cstop

Locate 2 , 2
Lcd Tasten

Loop

End






'################# Tasten_lesen Anfang (INT0) ##################################
Int0_auswerten:

Waitms 10

'Tasten_lesen:
I2cstart
I2cwbyte &B01110001 'lese Adresse von PCF8574A Baustein B
I2crbyte Tasten , Nack
I2cstop

Taste0 = Tasten.0
Taste1 = Tasten.1
Taste2 = Tasten.2

Locate 1 , 1
Lcd Tasten
Locate 1 , 7
Lcd Taste0


If Taste1 = 0 Then
If Taste0 = 0 Then
Zaehler = Zaehler + 1

Locate 1 , 30
Lcd " Arbeite!!"
Wait 1
Locate 1 , 30
Lcd " "
Wait 1

Locate 2 , 25
Lcd "Zaehler= " ; Zaehler ; " "

End If
End If

Return


Irgendwie passiert beim Mega8 das gleiche.
Nach ein paar mal aktivieren von einem Pin vom PCF8574er , habe ich am LCD nur mehr wirre zeichen und dann sehe ich gar nix mehr... ](*,)

Hat jemand schon mal diesen Ausgang vom PCF8574er ausgewertet ?
Könnt Ihr vielleicht einen Fehler in meinem Code sehen ?
Ideen?

Bin für jeden Tipp dankbar :-)

Ps.:
Der I2C Bus ist mit 10K gegen +5V und am INT hängen 5k gegen +5V


l.G. Roberto

PicNick
21.11.2006, 16:35
In der Do... Hauptschleife werkst du permanent an LCD und I2C Bus.

d.h. die ISR fährt dir da mitten drein. Das gibt Chaos

Roberto
21.11.2006, 16:56
Hallo Robert :-)

mmhhh...
Wie müsste ich das richtig machen ?

In der INT0-ISR alles abschalten?! (wie?)

(beim Meag32 laufen noch 3 Timer dazu und ein Grafik LCD )

-------
Kann man eigentlich aus der INT0-ISR auch mit Goto rausspringen oder kann ich in der ISR nur Werte übergeben und diese dann im normalem Code auswerten ?

l.G. Roberto

PicNick
21.11.2006, 17:03
Ich würde in der ISR nur einen Schalter setzen.
In der normalen Hauptschleife diesen Schalter abfragen.
Wenn gesetzt, löschen und den PCF abfragen und ggf. werte herzeigen

Roberto
21.11.2006, 18:15
Hallo Robert (Danke für die schnelle Antwort )




In der Do... Hauptschleife werkst du permanent an LCD und I2C Bus.

d.h. die ISR fährt dir da mitten drein. Das gibt Chaos


Wie soll ich das verhindern ?

Hatte schon mal nur in der ISR die Werte am LCD ausgegeben, aber reagiert noch gleich..?!

l.G. Roberto

PicNick
21.11.2006, 18:46
Schau mal:


'============ PCF 8574 versuch_2 mit INT0=================================

$regfile = "m8def.dat"
$crystal = 10000000

$hwstack = 250
$swstack = 250
$framesize = 250



'##################### Config für LCD ################################################## ##
Config Lcd = 40 * 2
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portb.1 , Db6 = Portb.2 , Db7 = Portb.3 , Rs = Portb.4 , E = Portb.5
Config Lcdbus = 4
Config Lcdmode = Port
Cursor On
Cls



'############################ Config I2C Bus ###################################
Config Scl = Portd.1 ' I2C-Port festlegen
Config Sda = Portd.0 ' I2C-Port festlegen

Config Portd.2 = Input 'Int0
Portd.2 = 1 'Pull up



'############################ Config INT0 #######################################
Config Int0 = Falling
On Int0 Int0_auswerten
Enable Int0


Dim Tasten As Byte
Dim Taste0 As Byte
Dim Taste1 As Byte
Dim Taste2 As Byte
Dim Zaehler As Word


Dim isr_flag As byte 'NEWNEWNEW


Enable Interrupts

'################################################# ##############################

Do

if isr_flag = 1 then
isr_flag = 0

I2cstart
I2cwbyte &B01110001 'lese Adresse von PCF8574A
I2crbyte Tasten , Nack
I2cstop

Locate 2 , 2
Lcd Tasten

Taste0 = Tasten.0
Taste1 = Tasten.1
Taste2 = Tasten.2

Locate 1 , 1
Lcd Tasten
Locate 1 , 7
Lcd Taste0

If Taste1 = 0 Then
If Taste0 = 0 Then
Zaehler = Zaehler + 1

Locate 1 , 30
Lcd " Arbeite!!"
Wait 1
Locate 1 , 30
Lcd " "
Wait 1

Locate 2 , 25
Lcd "Zaehler= " ; Zaehler ; " "
End If
End If

End If

Loop

End


'################# (INT0) ##################################
Int0_auswerten:
isr_flag = 1
Return

Roberto
21.11.2006, 20:56
Hallo Robert

Ja, so funktioniert es. :-)

Ich darf da wohl nur Parameter in der ISR übergeben :-(

Das Problem ist ein bisschen, dass an den PCF auch Endschalter dran kommen und das Programm sollte sofort reagieren, wenn ein Endschalter schaltet.

Beim Mega32 laufen dann noch 3 Timer mit ca. 20khz Taktausgabe und ein Grafik LCD und ein ADC.....

Da kann es leicht sein, dass das Hauptprogramm ein bisschen langsam reagiert. :-(

Aber ich werde es mal so proboeren..

Danke nochmal :-)

l.G. Roberto

kolisson
23.11.2006, 12:46
hallo da...

ich hab das zwar noch nicht gemacht, denke aber dass der befehl pushall am eingang der int-routine und der befehl popall am ende der routine das problem lösen müsste.

siehe bascom hilfe -> language reference

PicNick
23.11.2006, 13:08
Wovon spricht er ? Uns gehen ja keine register verloren.
Und da keine float-routinen da sind, pushed Bascom völlig ausreichend.

kolisson
23.11.2006, 14:03
war ja auch nur ne idee...
wenn bascom dass ausreichend selbst verwaltet, wie du sagst, wieso soll es dann nicht möglich sein in der int-routine richtig zu arbeiten ?

gruss

linux_80
23.11.2006, 21:20
Das Problem ist, das ein Interrupt dann auftritt, wenn man ihn nicht erwartet, deshalb heisst er auch Interrupt. Im ungünstigsten Fall, wenn das Hauptprogramm grad mitten dabei ist Zeichen an das LCD zu senden, und in der ISR auch wieder Zeichen an das LCD gesendet werden sollen, gibts Chaos, weil sich das LCD nimmer auskennt wo es grad ist, und eben Buchstabensalat anzeigt.

Der Interrupt wartet nämlich nicht bis irgendein Programmteil abgeschlossen ist, der kommt mittenrein, deswegen ist es besser in der ISR nur Flags zu setzen die im Hauptprogramm ausgewertet werden.
Das ist dann zwar nicht aufs 100stel Zeitnah, aber i.d.Regel reicht das trotzdem.

Roberto
23.11.2006, 21:42
Hallo Linux_80

Könnte man z.B. in der ISR das LCD Reseten ? (z.B. mit CLD ?)

Macht es dem I2C auch was aus, wenn man ihn unterbricht?
Könnte ja in der ISR mit START... wieder neu starten ?

l.G

linux_80
23.11.2006, 22:19
Können schon, aber da gibts dann die Probleme im Hauptprogramm !
Das weiss ja nix von der Kommunikation die in der ISR geschieht, und kommt deshalb aus dem Tritt. Und der Slave denkt sich auch sonst was, wenn mittendrin ein anderer angesprochen werden soll, wenns überhaupt geht, da vorher kein Stop da war :-k

Das beste Programmstyling ist immer noch in der ISR eine Variable (bzw. Flag, oder Schalter) zu setzen, den man im Hauptprogramm abfrägt (und zurücksetzt), dann kommt nix durcheinander.
So wie's oben PicNick schon gezeigt hat.
Ist auch viel einfacher und überschaubarer.

kolisson
23.11.2006, 22:51
@linux_80
nur zur vervollständigung meines verständnisses:
was du da erklärt hast ist vollkommen einleuchtend! wie sähe es denn mit ner variante aus, in der man im hauptprogramm während kritischer (wichtiger) vorgänge die interrupts sperrt und dann zwischendrin (wenns halt besser passt) wieder freigibt ?

gruss

linux_80
24.11.2006, 00:22
Da kommen wir dann in die Richtung "atomarer" Code, da gibts im Wiki etwas dazu, die Beispiele sind zwar auf C bezogen, aber die Sprache an sich ist egal.

Auf diesen Seiten nach "atomar" suchen (mehrere Stellen!):
https://www.roboternetz.de/wissen/index.php/Fallstricke_bei_der_C-Programmierung
https://www.roboternetz.de/wissen/index.php/Avr-gcc

kolisson
24.11.2006, 01:05
vielen dank für den excurs!
habe die beiden links nachgelesen und verstanden.

da war ich ja nur zufällig in diesen thread reingeplappert, konnte auf dem weg aber was wichtiges in mein hirn speichern. das verhindert dann grosse verwunderungen wenn ich dann demnächst mal ne int-routine aufsetzte.

gruss

Roberto
24.11.2006, 01:50
Hallo (Linux_80)

Interessant . Gut zu wissen :-)

Weil wir gerade bei Thema sind.. ;-)

Wie ist das den bei meinem Programm, wenn zusätzlich noch 3 Timer laufen, die Pin's von zwei Port's takten.
(mit ca. 20kHz bei 10Mhz Quarz)

Gebe es da auch Gefahren, macht das dem Takt vom I2C und LCD nicht so viel aus?
Bis jetzt habe ich noch nix gemerkt..

Und, sehe ich das richtig, dass ein ISR nicht von einem anderen unterbrochen werden kann ?

l.G. Roberto

PicNick
24.11.2006, 07:55
Normalerweise kann immer nur eine USR laufen, d.h. die wird nie unterbrochen.
Enab/disab Interrupts im Hauptprogramm: Auch damit kann man sich helfen. Gibt immer mehrere Möglichkeiten.