Bitbanging i2c-Problem mit ACK vom Slave

Ich versuche, Bit-Banging i2c zu implementieren, um zwischen dem GPIO eines Atmega128A und einem SHT21 zu kommunizieren (I2C-Bus wurde für einige andere Geräte verwendet). Die erste Aufgabe besteht darin, eine Schreibsequenz an das SHT21 zu senden. Mit einem Oszilloskop kann ich sehen, dass die vom Atmega gesendete Sequenz das richtige Startsignal, die richtige Reihenfolge der Bits, das richtige Stoppsignal und die Signalpegel richtig sieht. Der serielle Analysator aus dem Oszilloskop liest die korrekte I2C-Nachricht aus: S80W~A (SHT21-Adresse ist 0x80, Schreiben, also letztes Bit ist 0). Es gibt jedoch keine ACK-Antwort vom SHT21. SDA und SCL werden beide über 6,7-K-Widerstände auf 3,3 V hochgezogen.

Ich brauche wirklich Hilfe, um herauszufinden, was falsch ist.

Code, der das erste Byte wiederholt sendet, wenn kein ACK empfangen wird:

 i2c_start();
  while(!i2c_send(0x80)){
    i2c_stop();
    i2c_start();
  }

Code des i2c-Protokolls:

void i2c_start ()
{
    // Pull data high and sck low to ensure transition of start sequence
    DATA_HIGH ();

    SCK_HIGH ();
    DATA_LOW ();
    SCK_LOW ();
}
void i2c_stop ()
{
    DATA_LOW ();
    SetBit (DDRD, 7);
    //pull data high while clck is high to end transmission.
    SCK_HIGH ();
    DATA_HIGH ();
}

uchar i2c_send (uchar command)
{
    uchar i;

    for (i = 0; i < 8; i++)     // Send command
    {


        if ((command & 0x80) == 0x80)
            DATA_HIGH ();
        else
            DATA_LOW ();
        SCK_LOW ();
        SCK_HIGH ();
        SCK_LOW ();

        command = command << 1;
    }

    Delay(5);
    ClrBit (DDRD, 7);       // Change Data Direction
    //SetBit (PORTD, 7);      // Turn on internal pull-up

    //SCK_LOW ();
    SCK_HIGH ();

    if (!CheckBit (PIND, 7))     // Read ACK
    {
        SCK_LOW ();
        SetBit (DDRD, 7);
        return 1;
    }
    else
    {
        SCK_LOW ();
        SetBit (DDRD, 7);
        return 0;               // NO ACK
    }

}
Reagiert das Gerät, wenn Sie es auf den richtigen I2C-Bus legen?
Ich nehme an, Sie fragen nach dem SHT21, ja, es reagiert korrekt auf einem richtigen I2C-Bus
@ user3421560 Können Sie Ihre Frage bearbeiten und noch ein paar Dinge hinzufügen: Ausschnitt Ihres Bit-Banging-Codes, Oszilloskop-Screenshot des ersten Bytes auf Ihrem I2C (sowohl SDA als auch SCL, wenn möglich)?
Sie haben dieselbe Frage zu Stackoveflow gestellt, und ich wiederhole meinen Kommentar: Versetzen Sie die GPIOs tatsächlich in den Open-Collector/Drain-Modus? Mit anderen Worten, wenn Sie SCK_HI oder DATA_HI aufrufen, gibt Ihr GPIO die Leitung einfach frei (richtig) oder erzwingt sie hoch (schlecht)?
@DoxyLover Vielen Dank für deinen Kommentar. Ich habe es hier eingefügt, da jemand einen Kommentar hinterlassen hat, der besagt, dass es mehr Glück bringen würde, es hier zu versuchen. Über das Problem. Im Code setze ich SCK und SDA hoch, indem ich setbit(port, pinnumber) aufrufe. Es scheint, als würde es die Linie hoch treiben. Ich werde versuchen, es so schnell wie möglich zu beheben
Sein Code versetzt DDRD 7 in den Eingabemodus (High Z), um die Leitung für den Slave freizugeben.
@user3421560 Posten Sie Ihre Fragen nicht. Die StackExchange-Richtlinie ist gegen Cross-Posting . Sie können den Moderatoren eine Flagge geben, um diese Frage zu migrieren, wenn Sie dies wünschen.

Antworten (1)

Laut Ihrem Kommentar sind Ihre GPIO-Pins kein Open-Collector, sondern erzwingen sowohl High als auch Low. I2C erfordert Open-Collector sowohl auf der Takt- als auch auf der Datenleitung. Ohne dies kann der Slave beispielsweise nicht bestätigen, indem er die Datenleitung auf Low zieht (da der Master sie aktiv auf High zieht).

Wenn Sie den Open-Collector-Modus nicht einstellen können, besteht eine andere Möglichkeit darin, das Ausgangsdatenbit niedrig zu lassen und den Pin-Modus zwischen Ausgang (niedrig) und Eingang (effektiv Open-Collector) umzuschalten.