Forum: Mikrocontroller und Digitale Elektronik I2C-Schnittstelle funktioniert nicht.


von Florian G. (suffix)


Lesenswert?

Hallo,

ich habe ein kleines I2C-Netzwerk aus 2 AtMega16 aufgebaut. Beide haben 
externe Taktquellen(Quarz 4MHZ), die FuseBits sind dementsprechend 
gesetzt. Als Pull-Up Widerstände habe ich 2k genommen. Jedoch lässt sich 
mit einem Oszilloskop nicht einmal der Schiebetakt SCL an PC0 lesen, wo 
er eigentlich sein sollte. Der Sende-Controller(Master) läuft auf einem 
STK500, für den Controller, der empfangen soll(Slave), habe ich eine 
kleine Schaltung aus Spannungsversorgung und Quarz aufgebaut. Das 
Oszilloskop ist aber allgemein etwas komisch, sodass es sein kann, dass 
es etwas falsches anzeigt. Ich poste jetzt mal die beiden Queltexte für 
beide Controller, vielleicht sind die ja falsch:

Sender:
    .INCLUDE "m16def.inc"
    .CSEG
    rjmp  start
    .ORG  $2A
start:  ldi    r16,LOW(RAMEND)    ;Stapel anlegen
    out    SPL,r16        ;
    ldi    r16,HIGH(RAMEND)  ;
    out    SPH,r16        ;
    ldi    r16,50        ;Vorteiler 50
    out    TWBR,r16      ;Faktor 1
    ldi    r16,$1        ;in die Taktregister
    out    TWSR,r16      ;für Takt ca. 10Khz
loop:  sbis  PIND,PD0      ;Wenn Taster gedrückt
    rjmp  send        ;sende
    rjmp  loop        ;
send:  ldi    r16,(1 << TWINT) | (1 << TWSTA) | (1 << TWEN)
    out    TWCR,r16      ;Startbedingung ausgeben
send1:  in    r16,TWCR      ;
    sbrs  r16,TWINT      ;überprüfen, ob gesendet
    rjmp  send1        ;
    ldi    r16,0b00000010    ;Adresse+Write laden
    out    TWDR,r16      ;in Datenregister
    ldi    r16,(1 << TWINT) | (1 << TWEN)
    out    TWCR,r16      ;Adresse senden
send2:  in    r16,TWCR      ;
    sbrs  r16,TWINT      ;Prüfen, ob gesendet
    rjmp  send2        ;
    ldi    r16,$00        ;00 laden =
    out    TWDR,r16      ;alle LEDS an
    ldi    r16,(1 << TWINT) | (1 << TWEN)
    out    TWCR,r16      ;Daten senden
send3:  in    r16,TWCR      ;
    sbrs  r16,TWINT      ;Prüfen, ob alles
    rjmp  send3        ;gesendet
    ldi    r16,(1 << TWINT) | (1 << TWSTO) | (1 << TWEN)
    out    TWCR,r16      ;Stopbedingung ausgeben
    rjmp  loop



Empfänger:
    .INCLUDE "m16def.inc"
    .CSEG
    rjmp  start
    .ORG  TWIaddr        ;Bei Interrupt
    jmp  rec            ;an TWI gehe zu rec
    .ORG  $2A
start:  ldi    r16,LOW(RAMEND)    ;Stapel
    out    SPL,r16        ;
    ldi    r16,HIGH(RAMEND)  ;
    out    SPH,r16        ;
    ser    r16          ;
    out    DDRB,r16      ;DDRB ist Ausgang
    out    PORTB,r16      ;alle LEDS aus
    ldi    r16,0b00000010    ;Adresse ohne
    out    TWAR,r16      ;General Call laden
    ldi    r16,(1 << TWEA) | (1 << TWEN)
    out    TWCR,r16      ;ACK anschalten
    sei              ;Interrupts setzen
loop:  rjmp  loop        ;Warteschleife
rec:  cli              ;Interrupts abschalten
    ldi    r16,(1 << TWINT) | (1 << TWEN)
    out    TWCR,r16      ;Daten holen
rec1:  in    r16,TWCR      ;
    sbrs  r16,TWINT      ;und kontrollieren
    rjmp  rec1        ;
    in    r16,TWDR      ;nach r16
    out    PORTB,r16      ;dann PortB
    sei              ;Interrupts an
    reti            ;Rücksprung

von otto (Gast)


Lesenswert?

Hallo Florian,

weshalb hast Du kein DDR beim Sender beschrieben - ist das ein Trick, 
den ich nicht durchschaue ?

Gruss Otto

von Florian G. (suffix)


Lesenswert?

das soll nur ein Versuch sein, der Sender sendet permanent 00, damit 
beim Empfänger alle LED's angehen. und für I2C braucht man doch kein 
DDR, oder irre ich mich?

von Falk (Gast)


Lesenswert?

@ Florian Glaser

> das soll nur ein Versuch sein, der Sender sendet permanent 00, damit
> beim Empfänger alle LED's angehen. und für I2C braucht man doch kein
> DDR, oder irre ich mich?

Er irrt sich. Die I2C Leitungen sind open Drain, d.h. du kannst nicht 0 
und 1 ausgeben, sondern nur 0 und Z (Tristate). Dazu brauchst du das DDR 
Register, um die Pins zwischen Ausgang (0) und Eingang (Z) umzuschalten.

MfG
Falk


von Florian G. (suffix)


Lesenswert?

aha. und das bedeutet ich muss auf PC0 und PC1 das DDR-Bit 0 setzen? 
Dass die Pins Tristate sind, habe ich übrigens heute mittag mit meinem 
Oszilloskop gemerkt ;).

Ich muss also bei Initialisieren einfach die DDR-Register noch setzen?

von Falk (Gast)


Lesenswert?

@ Florian Glaser

> aha. und das bedeutet ich muss auf PC0 und PC1 das DDR-Bit 0 setzen?
> Dass die Pins Tristate sind, habe ich übrigens heute mittag mit meinem
> Oszilloskop gemerkt ;).

> Ich muss also bei Initialisieren einfach die DDR-Register noch setzen?

Schreib in DDRx und PORTx erstmal 0. D.h. alles Tristate, die exteren 
Pull-ups ziehen dann auf HIGH. (warum 2k? 10K tuns meist völlig)
Wenn jetzt ein AVR Daten ausgeben will (Daten oder ACK-Bit), schreib er 
die in DDRx, NICHT in PORTx.

0 ausgeben : DDRx = 1 (Ausgang, Portx ist 0, 0 wird ausgegeben)
1 ausgeben : DDRx = 0 (Eingang, Tristate, 1 wird ausgegeben, gezogen 
durch Pull-ups.)

MFG
Falk

von Florian G. (suffix)


Lesenswert?

Um sicher zu gehen, dass wir nicht aneinander vorbeireden: Ich spreche 
von einem AtMeag16, mit integrierter TWI-Steuerung. PC0 ist takt und PC1 
datenleitung. und dafür muss man die DDR-Register setzen?

von Falk (Gast)


Lesenswert?

Ohhh, das ist natürlich was anderes. Ich dachte du machst das per 
Software. Wie das mit dem TWI-Modul im Detail läuft weis ich nicht. 
Entschuldigung.

MfG
Falk

von Florian G. (suffix)


Lesenswert?

;) kein Problem. das will ich ja gar nicht. so tief will ich da gar 
nicht eintauchen, einfach den bus benutzen. also ich probier das jetzt 
nochmal aus, irgendwas kann da nicht stimmen. danke für deine antworten, 
hoffentlich schreibt noch jemand anderes was :)

von otto (Gast)


Lesenswert?

Hallo Florian,

leider kann ich Dir auch nicht sagen, ob beim TWI
die DDR gesetzt werden müssen.

>> Das Oszilloskop ist aber allgemein etwas komisch,
>> so dass es sein kann, dass es etwas falsches anzeigt.

Evtl. versuchst Du es zuerst mal mit LED und setze
ausserdem noch die DDR.

Gruss Otto

von Florian G. (suffix)


Lesenswert?

Okey, das Problem hat sich nun bis auf weiteres erledigt.

Folgendes:

Die DDR-Rehister müssen NICHT gesetzt werden, sie werden kompeltt 
gesperrt, sobald man in TWBR bzw TWCR etwas schreibt. Mein Oszi misst 
nun mit 2k Pull-Up einen Takt, und wenn man auf einen Taster drückt auch 
Daten :T Diese werden zwar nur als gezackte Doppellinie angezeigt, das 
liegt aber wohl an dessen Auflösung. Da ich meinen 2ten Atmega heute 
mittag durch einen Kurzschluss geschrottet habe :( besorge ich mir da 
einen neuen, und probiers dann nochmal.


Danke an alle, die mir so schnell geantwortet haben, wenn man jemand 
hat, der mit einem redet, ist das Lösen eines Problemes immer viel 
einfacher :T

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
Noch kein Account? Hier anmelden.