Hallo Wir benutzen den AT89S52. Wollen eine I²C Verbindung zu einer Eingabeplatine bestehend aus 8 Schaltern mit dem PCF8574P aufbauen. Ausgegeben soll der Zustand über 8 LEDs auf dem µC-Board, welche am P0 angeschlossen sind. Mit dem unten stehenden Code klappt dies auch, einzige Einschränkung ist, dass wenn wir den achten Schalter betätigen und dann mit P3.2 bzw P3.3 das Bitmuster auf die LEDs übertragen wollen, diese machen was sie wollen. Kann es sein das hiermit das Carrybit geschrieben wird? Also ein Übertrag? Was müßten wir machen damit dies funktioniert? #include "8051.h" #include "I2C_ASM.h" ; ; 8574er Kennung: 0100xxxy ; SEND000 .equ 01000000b ; ON ON ON SEND001 .equ 01000010b ; ON ON off SEND010 .equ 01000100b ; ON off ON SEND100 .equ 01001000b ; off ON ON SEND101 .equ 01001010b ; off ON off ; READ000 .equ 01000001b ; ON ON ON ; MAIN LOOP TASTEN jnb P3.2, UNDLOS ; Taster KISS-Board jnb P3.3, UNDLOS ; Taster 8574-Platine ljmp TASTEN UNDLOS lcall I2C_START mov A, #READ000 lcall I2C_WRITE lcall I2C_READ lcall I2C_STOPP mov P0, A ljmp LOOP .end
da wird kein Carry geschrieben. Um den Fehler zu finden brauchen wir schon den Rest von Code. Carry wird bei math. Operationen geändert und beim schieben über Carry.
Das die I²C - Header -Datei ;********************************************************* ; I2C-Routinen ;********************************************************* ; Assembler-Routinen zur Kommuinikation uber einen I2C-Bus. ; Einbinden in das *.asm-File durch "include" am Anfang. ; 24.2.2008 E. Ofenbach SDA .equ P3.5 ;Datenleitung SCL .equ P3.4 ;Taktleitung ljmp I2C_ENDE I2C_START: ;Startbedingung am Bus erzeugen ;************************************************* ; Aufruf: ; SDA=H, SCL=H ; keine Uebergabe ; Ende: ; SDA=L, SCL=L ; keine Rueckgabe ; keine Register unveraendert ;************************************************* ;lcall vom Aufruf 2Z clr SDA ;Daten auf LOW nop ;4us warten 1Z nop ; 1Z nop ; 1Z nop ; 1Z clr SCL ;Takt auf LOW ret ; 2Z ;********************************************************* I2C_STOPP: ;Stoppbedingung am Bus erzeugen ;************************************************* ; Aufruf: ; SDA=X, SCL=L ; keine Uebergabe ; Ende: ; SDA=H, SCL=H ; keine Rueckgabe ; Register unveraendert ;************************************************* ;lcall beim Aufruf 2Z clr SDA ;SDA auf L, falls noch nicht da 1Z setb SCL ;Takt auf HIGH nop ;4us warten 1Z nop ; 1Z nop ; 1Z nop ; 1Z setb SDA ;SDA=H nop ;4.7us/2 warten 1Z ret ; 2Z ;********************************************************* I2C_WRITE: ;Schreiben eine Bytes ;************************************************* ; Aufruf: ; SDA=X, SCL=L ; Akku enthaelt Datenbyte ; Ende: ; SDA=H, SCL=L ; ACK-Bit wird in Carry zurueckgegeben ; Register unveraendert ;************************************************* ;lcall vom Aufruf 2Z push 0 ;Register 0 sichern 2Z push ACC ;Akku sichern 2Z mov R0,#8 ;Schleifenzähler (8Bit) 1Z I2C_WRITE_LOOP: rlc A ;Bit in Carry schieben 1Z mov SDA,C ;Carry auf Bus legen 2Z ;setup time=250ns setb SCL ;pos. Taktflanke nop ;4us warten 1Z nop ; 1Z I2C_WRITE_WAIT: jnb SCL,I2C_WRITE_WAIT ;Taktverlaengerung? 2Z clr SCL ;neg. Taktflanke (hold time=0) nop ; 1Z nop ; 1Z djnz R0,I2C_WRITE_LOOP ;Alle 8 Bit? 2Z I2C_WRITE_ACK: setb SDA ;SDA "loslassen" 1Z setb SCL ;SCL=H, t_SU_DAT=250ns nop ;t_HIGH_min=4us 1Z nop ; 1Z I2C_WRITE_ACK_WAIT: jnb SCL,I2C_WRITE_ACK_WAIT ;Taktverlaengerung? 2Z mov C,SDA ;Status der SDA Leitung einlesen clr SCL ;SCL=L pop ACC ;Akku wieder herstellen 2Z pop 0 ;Register 0 wieder herstellen 2Z ret ; 2Z ;********************************************************* I2C_READ: ;Lesen eines Bytes ;************************************************* ; Aufruf: ; SDA=X, SCL=L ; Wenn das F0-Flag=1 ist wird NACK gesendet. ; Notwendig beim letzten Byte vor Stopp ; Ende: ; SDA=H, SCL=L ; Byte wird im Akku zurueckgegeben ; keine Aenderung der Register ;************************************************* ;lcall vom Aufruf 2Z setb SDA ;SDA freigeben push 0 ;Register 0 sichern 2Z mov R0,#8 ;Schleifenzähler (8Bit) 1Z I2C_READ_LOOP: setb SCL ;pos. Flanke nop ;t_HIGH_min=4us 1Z nop ; 1Z I2C_READ_WAIT: jnb SCL,I2C_READ_WAIT ;Taktverlaengerung? 2Z mov C,SDA ;Bit in Carry 1Z rlc A ;aus Carry in Akku 1Z clr SCL ;neg. Taktflanke nop ;t_LOW_min=4.7us 1Z nop ; 1Z nop ; 1Z djnz R0,I2C_READ_LOOP ;Alle 8 Bit? 2Z jbc F0,I2C_READ_ACK ;F0=1 => NACK (SDA=H, s.o.) clr SDA ;ACK auf Bus 1Z I2C_READ_ACK: setb SCL ;pos. Flanke nop ;t_HIGH_min=4us 1Z nop ; 1Z pop 0 ;Register 0 wieder herstellen 2Z clr SCL ;neg. Flanke setb SDA ret ; 2Z ;********************************************************* I2C_ENDE: Brauchste die 8051 Header-Datei auch?
Am P0 sind ja die LEDs Also wenn der achte Schalter ein ist und dann mit den Tastern das Muster übertragen werden soll, ist mal die achte LED ein, mal nur halb so hell, mal aus - immer anders.
jbc F0,I2C_READ_ACK ;F0=1 => NACK (SDA=H, s.o.) wo ist denn das F0 flag definiert ?? Und wie wird es gesetzt ? Da sollte man suchen.
Anders herum. auf dem µC-Board sind auch 8 Taster. Wenn ich von hier auf eine Ausgabeplatine sende, klappt dies und es gibt keinen Fehler. Dafür benutze ich folgenden Code: #include "8051.h" #include "I2C_ASM.h" ; ; 8574er Kennung: 0100xxxy ; SEND000 .equ 01000000b ; ON ON ON SEND001 .equ 01000010b ; ON ON off SEND010 .equ 01000100b ; ON off ON SEND100 .equ 01001000b ; off ON ON SEND101 .equ 01001010b ; off ON off ; READ000 .equ 01000001b ; ON ON ON ; MAIN LOOP TASTEN jnb P3.2, UNDLOS ; Taster KISS-Board jnb P3.3, UNDLOS ; Taster 8574-Platine ljmp TASTEN UNDLOS lcall I2C_START nop nop nop nop mov A, #SEND000 lcall I2C_WRITE nop nop nop mov A, P2 lcall I2C_WRITE nop nop nop lcall I2C_STOPP mov P0, A ljmp LOOP .end
Mov F0,x ?? Woher kommt das Bit für F0 ? Über I²C werden 8 Bits eingelesen. Wenn es das 8te Bit ist dann eben Mov F0,A.7 nachdem alle 8 eigelesen wurden. Man kann auch Mov F0,C schreiben. das letzte Bit bleibt ja im C.
MAIN LOOP TASTEN jnb P3.2, UNDLOS ; Taster KISS-Board jnb P3.3, UNDLOS ; Taster 8574-Platine ljmp TASTEN UNDLOS lcall I2C_START mov A, #READ000 lcall I2C_WRITE lcall I2C_READ lcall I2C_STOPP Mov F0,C <------------------------- mov P0, A ljmp LOOP So klappt es Danke!
F0 ist ein frei verwendbares Flag im PSW, wenn ich's richtig im Kopf habe. Ralf
langsam.... Im I²C read Teil wollt ihr die Schleife mit Afrage des F0 beenden. jbc F0,I2C_READ_ACK ;F0=1 => NACK (SDA=H, s.o.) Ihr "füttert" F0 aber nicht in der Schleife. !! Ihr macht: I²C write, Read ohne F0 zu tangieren und dann stop. Wie bitte wollt Ihr JBC F0 erfüllen ??? im I²C_read_Wait ??? Nicht am Symtom basteln !! Die Ursache finden !! Ob im PSW oder sonstwo. Flags müssen gesetzt und gelöscht werden !! Nur sehe ich nichts vom setzen !!
Ralf schrieb: > F0 ist ein frei verwendbares Flag im PSW, wenn ich's richtig im Kopf > habe. > > Ralf Jepp, ist richtig. Trotzdem muss es gesetzt werden wenn man mit JBC F0 arbeiten will. Das heist ja nur Springe wenn F0 gesetzt nach xy und lösche F0.
Stefan schrieb:
> liegt das also doch am Carry-Bit oder was heißt das für mich?
Das heißt nur das Du F0 als Flag nie benutzt hast.
Du hast es gelesen, aber nie gesetzt !!
Ich hasse I²C wie die Pest und bin daher auch nicht fit damit.
Aber ich denke das Stoppbit sollte nach F0.
Also 8 bit +1 Soppbit lesen. Read Schleifeenzähler mit #9 laden.
Aber nur 8 Mal RLC A machen. Das letzte Bit im c nach F0 laden.
Dann weißt Du das alles gesendet wurde und sendest dann dein ACK.
Vermutlich...
Muß ich dieses F0 überhaupt verwenden? Oder kann man das in der Header-Datei ändern, das dieses überhaupt nicht aufgerufen wird?
Stefan schrieb: > Muß ich dieses F0 überhaupt verwenden? Oder kann man das in der > Header-Datei ändern, das dieses überhaupt nicht aufgerufen wird? Wer soll das beantworten ? DU mußt wissen was Du willst. Du mußt F0 nicht benutzen. Du kannst auch ein anderes Flag definieren. Du kannst auch JB c,xy nehmen wenn im Carry Dein Stopbit ist und auf ein zusätzliches Flag ganz verzichten. Schau Dir andere Routinen im Web an. Aber nicht einfach nur kopieren, und geht. Dabei lernt man nicht. Diese Fragen sollte eigentlich Dein PAP beantworten.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.