Forum: Mikrocontroller und Digitale Elektronik AM2320 und I2C


von Thomas O. (tom-tom92)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich habe hier einen AM2320 Temperatur&Feuchte-Sensor an einem ATMEGA88.

Ich bring den Sensor einfach nicht zuverlässig zum Laufen. Sporadisch 
hat es schon geklappt, daher glaube ich, dass es nur an einer 
Kleinigkeit liegen kann.

Ich vermute, dass es am WakeUp-Befehl scheitert (Datenblatt-Auszug habe 
ich angehängt).

Der Witz: Mit der Arduino-Lib "AM232X" von Rob Tillaart funktioniert es 
sehr zuverlässig. Obwohl die 800µs nicht eingehalten werden.
(wenn ich das Datenblatt richtig interpretiere muss ich das eh nicht? 
Der uC macht das automatisch?)

Ich habe versucht die Lib nachzubauen. Mit der I2C von Peter Fleury. 
Hier mal ein Auszug, mit dem ich den Screenshot vom Logic-Analyzer 
gemacht habe)
1
bool AM2320_init()
2
{
3
  i2c_init();
4
  if (!AM2320_wakeup(30))    //wake up is min 800 us max 3000 us
5
  {
6
    return false;
7
  }
8
  return true;
9
}
10
11
bool AM2320_wakeup(uint16_t timeout)
12
{
13
  
14
    i2c_start(AM2320_ADDRESS + I2C_WRITE);
15
    _delay_us(800); // Hier habe ich schon mit div. Zeiten experimentiert
16
    i2c_stop();
17
18
  return true;
19
}

Was Auffällig ist, ist, dass bei der Wire-Lib eine lange Zeit SCL und 
SDA
 gemeinsam auf Low sind - wie im Datenblatt. Hier denke ist der Grund, 
warum es bei mir nicht funktioniert.

Hab ihr eine Idee wo ich hier ansetzen kann, dass ich SCL und SDA vom 
Timing auch so hinbekomme??

Beim Adruino klappts auf einem ATMEGA328 mit dem Timing ja auch. Da 
sollte um ATMEGA88 nicht so viel anders sin.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Thomas O. schrieb:
> Ich bring den Sensor einfach nicht zuverlässig zum Laufen. Sporadisch
> hat es schon geklappt, daher glaube ich, dass es nur an einer
> Kleinigkeit liegen kann.

Wenn ich dein rechtes Bild richtig sehe, dann scheint es mir, daß du die 
Stop-Condition nach deinem esten Byte nicht sendest.
Also:
Start-Condition = SDA geht von H nach L, während SCL high ist
Stop-Condition = SDA geht von L nach H, während SCL high ist

Normaleweise geht es so:
- Start-Condition
- Byte-Transfer(s)
- Stop-Condition

Jeder Transfer MUSS am Ende mit einer Stop-Condition beendet werden.

W.S.

von Thomas O. (tom-tom92)


Lesenswert?

W.S. schrieb:
> Wenn ich dein rechtes Bild richtig sehe, dann scheint es mir, daß du die
> Stop-Condition nach deinem esten Byte nicht sendest.

Doch, die Stop wird gesendet. Siehe kleines oranges Viereck. Nach dem 
zweiten Byte kommt die 800µS Pause. Hier ist das Stop nicht mehr im 
Bild. Hab hier bisschen herumprobiert.

Mittlerweile bin ich schon einen kleinen Schritt weiter. Scheinbar 
entspricht der Wakeup-Befehl nicht dem I2C-Standard.
Diese 800µS-Pause (SCL & SDA auf GND) können deshalb nicht so einfach 
umgesetzt werden.

Nun kann ich meine Frage auch konkretisieren:

Wie bekomme ich den geforderten WakeUp mit dem TWI hin:
(Siehe Datenblattauszug im ersten Post)

- Start-Condition
- Byte-Transfer (Adresse + Write
- 800µS-Pause mit SCL & SDA auf GND
- Stop-Condition

Nur ungern möchte ich auf Software-I2C ausweichen.

: Bearbeitet durch User
von Thomas O. (tom-tom92)


Lesenswert?

Soooo, ich hab eine Lösung gefunden, wie der AM2320 in Verbindung mit 
der I2C-Lib von Peter Fleury zuverlässig funktioniert (mit mehreren 
Sensoren getestet, keine Ausfälle, ...).

Das Ergebnis sieht dann aus wie mit einem Arduino + Lib "AM232X" von Rob 
Tillaart. (Siehe Bild im ersten Post)

Die Lösung ist, das TW_MT_SLA_NACK-Flag im TWSR-Register abzufragen.
(die Wire-Lib bei Arduino macht das beim Interrupt auch)
1
void AM2320_init(void)
2
{
3
  i2c_init();
4
}
5
6
void AM2320_wakeup(uint16_t timeout)
7
{
8
  // ticks ist meine "Systemzeit": beim Timer0-Überlauf ticks++
9
  uint64_t start = ticks;
10
  i2c_start(AM2320_ADDRESS + I2C_WRITE);
11
  // Workaround: abwarten bis TWSR == TW_MT_SLA_NACK
12
  while ((ticks - start < timeout) && !(TWSR == TW_MT_SLA_NACK));
13
  i2c_stop();
14
}
15
16
int AM2320_read()
17
{...}

Was ich eigenartig finde: Die Abfrage des Flags muss sofort nach 
i2c_start(...) erfolgen. Wenn ich zwischen dem i2c_start(...) noch z.B. 
eine Variable hochzähle, sieht der Bus aus, als hätte ich die Abfrage 
garnicht dort eingebaut.

: Bearbeitet durch User
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.