www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PIC I2C Problem beim Daten empfangen


Autor: Mario G. (rodenberger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich komme einfach nicht mehr weiter.

Ich benutze einen PIC 16F877A und betreibe einen TMC222 über I2C damit.
Senden an I2C ist kein Problem.

Das auslesen von Adressen geht aber nicht, da erhalte ich immer 255.
Prinzipiell kann das auslesen aber nicht falsch sein, da sich der TMC222 
sonnst auch nicht ansprechen lassen würde. (Man MUSS erst Daten lesen)

Ein weiteres Problem ist, das ich wenn ich I2C OFF schalte das System 
hängt, wenn ich auf eine Reaktion warte....


; I2C-BUS WIEDER FREIGEBEN
I2C_OFF
        BANKSEL SSPCON2
        BSF     SSPCON2, PEN    ; BUS FREIGABE ANWEISEN
        BANKSEL 0

  Return <---Ohne steht das System, es gehört da aber nicht hin !!!

I2C_WARTE
        BTFSS   PIR1, SSPIF     ; FERTIG?
         GOTO    I2C_WARTE       ; NEIN, NOCH NICHT
        BCF     PIR1, SSPIF     ; JA, ALLES FERTIG, NUN NOCH SSPIF 
ZURÜCKSETZEN

        RETURN

; WEITERE UNTERPROGRAMME

I2C_ON  BCF PORTA , 0
        BCF     PIR1, SSPIF     ; SSPIF BIT LÖSCHEN
        BSF     STATUS, RP0
        BSF     SSPCON2, SEN    ; BUS ÜBERNAHME ANWEISEN
        BCF     STATUS, RP0
        GOTO    I2C_WARTE

; EIN BYTE AUS W SENDEN
I2C_TX
        MOVWF   SSPBUF          ; -> ZUM I2C-SLAVE ÜBERTRAGEN
        GOTO    I2C_WARTE

;EIN BYTE VOM SLAVE EMPFANGEN (NACH SSPBUF)
I2C_RX
        BSF     STATUS, RP0
        BSF     SSPCON2, RCEN   ; DATEN EMPFANG EINSCHALTEN
        BCF     STATUS, RP0


I2C_R7
        BTFSS   PIR1, SSPIF     ; FERTIG?
        GOTO    I2C_R7    ; NEIN, NOCH NICHT
        BCF     PIR1, SSPIF     ; JA, ALLES FERTIG, SSPIF ZURÜCKSETZEN

        MOVF    SSPBUF,0 ;DATEN NACH W <-----hier habe ich immer 255
        ;CALL SENDEN
         Return

ACK

        BANKSEL SSPCON2 ; ACK SENDEN
        BSF   SSPCON2, ACKEN
        BANKSEL 0
         RETURN

Das meiste ist von SPRUT!
Mit den PullUPs habe ich auch schon experimentiert, Nichts

Ich vermute das es ein Problem mit I2C OFF ist, da ich ja erst die 
Adresse an den TMC senden muss, dann I2C ausschalten und wieder 
einschalten zum lesen.
Das Prinzip I2C ist auch klar, einen EEPROM kann ich lesen und 
beschreiben.
Die Taktrate ist auch sehr niedrig eingestellt (mehreres probiert)

Vielen Dank für jeden Tipp.

Autor: Sven Stefan (stepp64) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Bus nach dem Senden der Adresse wieder freizugeben ist meiner 
Meinung nach falsch. Du willst lesen, also holst du dir als erstes den 
Bus (I2C_ON), dann sendest du die Adresse mit Bit0=1 (lesen). Danach 
empfängst du einfach die beiden Bytes (I2C_RX). Erst wenn alle Daten 
empfangen wurden, gibst du den Bus mit I2C_OFF wieder frei.

Auch wenn du lesen willst liefert der Master den Takt. Die Daten werden 
also nicht vom Slave gesendet, sondern vom Master abgeholt. Wenn du vor 
dem Senden den Bus wieder frei gibst, könnte es sein, dass den TMC den 
Lesevorgang abbricht, weil dein Master dann auch kein ACK mehr sendet.

Sven

Autor: Isabelle Tanmoue (isa08)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kann nicht mehr weiter!!!
kann jemandem mir sagen wie man der Compiler scb9328 installieren kann 
und zwar unter Linux?Ich habe das Programm mir per mail zugeschickt,aber 
kann nicht aufrufen und damit das einfache Programm "Hallo world" 
schreiben.
Ich brauche eure hilfe Bitte!!!!!!

Autor: Sven Stefan (stepp64) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und was hat das jetzt mit dem Originalthema zu tun?

Autor: Mario G. (rodenberger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Sven,

das verstehe ich jetzt nicht.
Wenn ich an den Slave etwas senden möchte, gebe ich die Adresse vom 
Slave an und sende dann gleich die Daten.
Beim lesen geht das doch nicht. Hier muss ich doch erst die Adresse vom 
Slave senden und die Adresse was ich möchte. Dann muss ich aber I2C OFF 
und wieder ON schalten um dem Slave zu sagen das ich wieder lesen will. 
(Bit 0 von 0 auf 1). Jedenfalls habe ich das so verstanden.
Bei einem EEPROM funktioniert das so.
Laut Datenblatt des TMC ist das auch so, nur das er nach dem letzten 
gelesenem Byte ein NoACK möchte.

Den Bus gebe ich erst frei, wenn die Daten auch angekommen sind, bzw das 
NoACK gesendet ist.( etwa wie in I2C_R7 )
Nur scheint unter gewissen Umständen der Bus nicht auf H zu gehen und 
das System hängt dann.

Aber mal agesehen von dem letzen empfangenen Byte, ist das erste auch 
schon 255, obwohl es einen anderen Wert haben sollte.
RS232 ist ok!

Gruß Mario

Autor: Sven Stefan (stepp64) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kenne zwar deinen Chip nicht, aber bei einem LM75 Temperatursensor 
habe ich das Lesen des Statusbyte ähnlich programmiert. Allerdings habe 
ich nach dem senden der Adresse und dem senden des gewünschten Registers 
den Bus nicht frei gegeben. Das Lesen der Antwortdaten wird dann mit 
einem Restartkommando eingeleitet. Dadurch kannst du auf Lesen 
umschalten ohne den Bus freizugeben. Eventuell reagiert dein IC ja 
ähnlich. Ich hänge mal meine I2C Routinen mit an.
;***I2C UNTERPROGRAMME************************************************************
;
; I2C-Bus im Master-Mode übernehmen
; Warten bis MSSP-Modul frei ist
i2c_idle
  Bank1
    btfsc   SSPSTAT, R_W  ;läuft eine Übertragung?
    goto    $-1        ;ja, warten...
i2cidle_loop2
    movfw   SSPCON2      ;nein, läuft ein anderes Ereignis?
    andlw   0x1F            ;test auf ACKEN, RCEN, PEN, RSEN, SEN
    btfss   STATUS,Z    
    goto    i2cidle_loop2  ;ja, warten...
  Bank0
  return          ;MSSP Modul ist nicht beschäftigt

i2c_start
  call    i2c_idle    ;Bus frei?
    Bank1
    bsf     SSPCON2, SEN    ;Bus Übernahme anweisen und Startbit senden
    btfsc   SSPCON2, SEN  ;Auf das Ende der Startkondition warten
    goto    $-1
   Bank0
  return

;Restart aktivieren
i2c_rstart
    call    i2c_idle    ;Bus frei?
  Bank1
    bsf     SSPCON2, RSEN   ;Restart Sequence einleiten      
  btfsc   SSPCON2, RSEN
    goto  $-1
  Bank0
    return

;ein Byte aus W senden
;Rückgabewert in W: 0=ACK empfangen, 1=ACK nicht empfangen 
i2c_tx
  movwf  i2c_Puffer
    call    i2c_idle      ;Bus frei?
    bcf     PIR1, SSPIF     ;Lösche Interrupt Flag
  movfw  i2c_Puffer
    movwf   SSPBUF          ;Byte wird gesendet
    btfss   PIR1, SSPIF     ;Senden fertig?                
    goto  $-1

    Bank1
  btfss   SSPCON2, ACKSTAT ;Test ob ACK vom Slave empfangen wurde
  goto  i2c_tx_ack
  Bank0
    retlw   d'1'      ;ACK wurde nicht empfangen
i2c_tx_ack
  Bank0
    retlw   d'0'            ;ACK wurde empfangen

;ein Byte vom Slave empfangen ohne ACK
;Rückgabewert in W
i2c_rx
    call    i2c_idle
    bcf     PIR1,SSPIF    ;Interrupt Flag löschen
  Bank1                   
    bsf     SSPCON2, RCEN   ;Empfang einschalten
  Bank0     
  btfss   PIR1,SSPIF      ;Byte empfangen?
    goto  $-1        ;noch nicht

    Bank1
  bsf     SSPCON2, ACKDT  ;kein ACK senden (ACK=High)
    bsf     SSPCON2, ACKEN  ;sende negatives ACK
    btfsc   SSPCON2, ACKEN  ;fertig?
    goto    $-1
  Bank0
  movfw  SSPBUF      ;Empfangenen Wert nach W
    return

;ein Byte vom Slave empfangen mit ACK
;Rückgabewert in W
i2c_rx_ack
    call    i2c_idle
    bcf     PIR1,SSPIF    ;Interrupt Flag löschen
  Bank1
    bsf     SSPCON2, RCEN   ;Empfang einschalten
  Bank0     
  btfss   PIR1,SSPIF      ;Byte empfangen?
    goto  $-1        ;noch nicht

    Bank1
  bcf     SSPCON2, ACKDT  ;ACK senden
    bsf     SSPCON2, ACKEN
    btfsc   SSPCON2, ACKEN  ;fertig?
    goto    $-1
  Bank0
  movfw  SSPBUF      ;Empfangenen Wert nach W
    return

; I2C-Bus wieder freigeben
i2c_stop
    call    i2c_idle
  Bank1
    bsf     SSPCON2, PEN    ;Stop Bit senden und Bus frei geben
    btfsc   SSPCON2, PEN  ;fertig?
  goto  $-1
  Bank0
    return

;***ENDE UNTERPROGRAMME**********************************************************

Autor: Mario G. (rodenberger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Sven,

Du bist mein Retter ;o)
Ich habe jetzt deinen Code übernommen und in der Programiersprache 
entsprechend angepasst.
Ich benutze zwar den RESTART nicht, aber es funktionierte auf anhieb.
Nun wüste ich gerne warum das so ist, da ich nicht nur den Code kopieren 
sondern auch verstehen will.
Mir fällt allerdings schon auf, das Du andere Bits abfragst ob I2C 
beschäftigt ist oder nicht.
Mein Code entspricht in etwa dem von der Microchip-Seite.
Wie schon geschrieben funktionierte das auch mit einem EEPROM.

Bin mal gespannt ob es später mit dem EEPROM auch noch geht, da der auch 
an diesen I2C-Bus kommt.

Also nochmals BESTEN DANK!!!

Gruß Mario

Autor: Sven Stefan (stepp64) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ehrlich gesagt, hatte ich die Routinen auch nur irgendwo im iNet 
gefunden, nachdem die sprut Routinen bei meinem LM75 nicht klappten (der 
Fehler lag allerdings woanders, glaube ich). Ich hatte vor ein paar 
Wochen den Fehler hier beschrieben allerdings finde ich den Beitrag 
nicht mehr. Wie sucht man hier eigentlich nach seinen eigenen Beiträgen?

Ich habe mich aber ein wenig mit den Routinen beschäftigt und mit dem 
Datenblatt verglichen. Mir erschienen diese Routinen irgendwie richtiger 
als die von sprut, da hier immer genau die Bits abgefragt werden, welche 
für den jeweiligen Vorgang relevant sind. Auch die Abfrage auf Idle ist 
so im Datenblatt beschrieben. Bei mir laufen die Routinen mit dem LM75 
und einem I/O Driver am Bus bisher problemlos. Ein EEPROM soll auch noch 
dran, das hab ich aber noch nicht probiert.

Freut mich das es bei dir geht.

Sven

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.