Forum: Mikrocontroller und Digitale Elektronik DS18S20 Temperatur auslesen mit C geht nicht


von unknown (Gast)


Lesenswert?

Hallo,

ich versuche schon länger einen DS18S20 Temperatursensor zum laufen zu 
bringen, scheitere aber immer am Auslesen der Temperatur.

Um die Temperatur auslesen zu können muss ich laut Doku ein READ-Signal 
senden und danach die Temperatur empfangen. Da ich sowohl senden als 
auch empfangen muss um eine Temperatur zu bekommen weiß ich nicht in 
welcher Funktion der Fehler ist (vllt. auch in beiden).

Die Initialisierung des Sensors funktioniert auf jeden Fall, das hab ich 
bereits testen können - er ist also nicht defekt oder so.

Der Code:
1
void write(unsigned char c)
2
{
3
  char cnt;
4
  for (cnt = 0; cnt < 8; ++cnt) {
5
    DQ = 0;
6
    t0_wait(0xFF, 0xF1);   // 15µs
7
    DQ = (c >> cnt) & 1;   // write bit to sensor
8
    t0_wait(0xFF, 0xD3);   // 45µs
9
  }
10
}
1
void read()
2
{
3
  char cnt;
4
  write(FC_READ);
5
  for (cnt = 0; cnt < 8; ++cnt) {
6
    DQ = 0;
7
    t0_wait(0xFF, 0xFE);   // 1µs
8
    Tlow |= ((char) DQ << cnt);  // read bit from sensor
9
    t0_wait(0xFF, 0xC4);   // 60µs
10
  }
11
  DQ = 0;
12
  t0_wait(0xFF, 0xFE);   // 1µs
13
  Thigh = DQ;
14
}
DQ ist das Bit an das die Daten gesendet werden, Tlow das erste 
gesendete Byte, Thigh das Zweite (von dem ich aber nur ein Bit brauche).

Ich hoffe hier ist jemand dabei, der einen DS18S20 schon mal zum laufen 
gebracht hat und der mir sagen kann was da falsch dran ist. Das 
Datasheet: 
http://www.datasheetcatalog.net/de/datasheets_pdf/D/S/1/8/DS1820.shtml

von Klaus W. (mfgkw)


Lesenswert?

Schon mal die Suchfunktion bemüht?
Es gibt hier doch bestimmt schon lauffähige Lösungen.
Wenn nicht, kann ich auch eine herauskramen.

von Benni L. (sutter_cain)


Lesenswert?

Ich habe gerade keine Zeit, das alles durchzuprüfen, aber ich hab hier 
mal bisschen was aus meine alten Code herausgekramt, ich hoffe das hilft 
dir:
1
void OW_write_bit (unsigned char write_bit)
2
{
3
  if (write_bit)
4
  {
5
    //writing a bit '1'
6
    drive_OW_low();         // Drive the bus low
7
    wait(DELAY_6Us);        // delay 6 microsecond (us)
8
    drive_OW_high ();          // Release the bus
9
    wait(DELAY_64Us);        // delay 64 microsecond (us)
10
  }
11
  else
12
  {
13
    //writing a bit '0'
14
    drive_OW_low();         // Drive the bus low
15
    wait(DELAY_60Us);        // delay 60 microsecond (us)
16
    drive_OW_high ();          // Release the bus
17
    wait(DELAY_10Us);        // delay 10 microsecond for recovery (us)
18
  }
19
}
1
unsigned char OW_read_bit (void)
2
{
3
  unsigned char read_data; 
4
  //reading a bit 
5
  drive_OW_low();             // Drive the bus low
6
  wait(DELAY_6Us);            // delay 6 microsecond (us)
7
  drive_OW_high ();              // Release the bus
8
  wait(DELAY_9Us);            // delay 9 microsecond (us)
9
10
  read_data = read_OW();          //Read the status of OW_PIN
11
12
  wait(DELAY_55Us);            // delay 55 microsecond (us)  
13
  return read_data;
14
}

von Benni L. (sutter_cain)


Lesenswert?

So nun habe ich ein wenig Zeit gefunden, die beiden Dinge zu 
vergleichen:

Zu deiner read Funktion:
- warum liefert diese Funktion keine Werte zurück? bzw. wo befinden sich 
Tlow und Thigh? werden diese auch vor Aufruf der Funktion richtig 
initialsiert? Ich würde Pointer an die Funktion übergeben, dann richtig 
initialisieren und erst dann schreiben. Wäre dann übersichtlicher.

- zum Lesen solltest du den Bus wieder freigeben, das konnte ich bei dir 
nirgends finden da steht nur DQ=0. Ich gebe den Bus nach 6 µs wieder 
frei, 1µs sollte allerdings auch ausreichen.

- du liest direkt nach 1µs den Bus aus, das Signal des DS18S20 ist aber 
erst nach 15 µs nach den fallende Flange gültig, das steht im Text des 
Datenblatt unter READ-TIME SLOTS S.13

Zu deiner write Funktion:
- du solltest zwischen den Bits auch noch 1 µs warten. Das wären dann 
bei dir mind. 46 µs statt 45.
-sonst siehts gut aus


Probier das mal aus und berichte dann wieder.

von unknown (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Schon mal die Suchfunktion bemüht?
> Es gibt hier doch bestimmt schon lauffähige Lösungen.
Ja, hab ich. Aber das hat mir alles leider nicht wirklich 
weitergeholfen.

Benni L. schrieb:
> - warum liefert diese Funktion keine Werte zurück? bzw. wo befinden sich
> Tlow und Thigh? werden diese auch vor Aufruf der Funktion richtig
> initialsiert? Ich würde Pointer an die Funktion übergeben, dann richtig
> initialisieren und erst dann schreiben. Wäre dann übersichtlicher.

Der Code ist noch im Betastatus, weshalb ich ihn erst auf die einfachste 
Weise geschrieben hab, die mir eingefallen ist. Sobald er mal läuft 
werde ich ihn überarbeiten. Ich lese in der read-Funktion gleich beide 
Bytes aus, weshalb ich auch keine Werte zurückgeben brauche. Die 
einzelnen Bits schiebe ich dann einfach an den richtigen Platz. Das hab 
ich im Simulator-Debugger getestet und das hat auch funktioniert.
Tlow und Thigh sind global und initialisiert.

Benni L. schrieb:
> - zum Lesen solltest du den Bus wieder freigeben, das konnte ich bei dir
> nirgends finden da steht nur DQ=0. Ich gebe den Bus nach 6 µs wieder
> frei, 1µs sollte allerdings auch ausreichen.
Hab gedacht das freigeben würde automatisch über diesen "pullup 
resistor" erfolgen. Hab ich zu Testzwecken aber mal eingebaut.

Benni L. schrieb:
> - du liest direkt nach 1µs den Bus aus, das Signal des DS18S20 ist aber
> erst nach 15 µs nach den fallende Flange gültig, das steht im Text des
> Datenblatt unter READ-TIME SLOTS S.13
Da steht doch: "Output data from the DS18S20 is valid for 15μs after the 
falling edge that initiated the read-time slot." Das bedeutet doch, dass 
die Daten nur 15μs gültig sind und nicht, dass sie es erst ab 15μs 
gültig sind.

Benni L. schrieb:
> - du solltest zwischen den Bits auch noch 1 µs warten. Das wären dann
> bei dir mind. 46 µs statt 45.
Hab mir gedacht, dass der Code ja auch noch Zeit benötigt bis er 
ausgeführt ist, weshalb ich das nicht berücksichtigt hab. Aber hab es 
sicherheitshalber mal eingebaut.

Trotz aller Ratschläge bekomme ich dennoch kein Signal vom Sensor.
Ich hab deinen Code, Benni, mal fast 1:1 übernommen, er geht bei mir 
aber dennoch nicht:
1
void write(unsigned char c)
2
{
3
  char cnt;
4
  for (cnt = 0; cnt < 8; ++cnt) {
5
    DQ = 0;
6
    if (((c >> cnt) & 1) == 1) {
7
      t0_wait(0xFF, 0xFA);  // 6µs
8
      DQ = 1;
9
      t0_wait(0xFF, 0xC0);  // 64µs
10
    } else {
11
      t0_wait(0xFF, 0xC4);  // 60µs
12
      DQ = 1;
13
      t0_wait(0xFF, 0xF5);  // 10µs
14
    }
15
  }
16
}
1
void read()
2
{
3
  char cnt;
4
  write(FC_READ);
5
  for (cnt = 0; cnt < 8; ++cnt) {
6
    DQ = 0;
7
    t0_wait(0xFF, 0xFA);  // 6µs
8
    DQ = 1;
9
    t0_wait(0xFF, 0xF6);  // 9µs
10
    Tlow |= ((char) DQ << cnt);
11
    t0_wait(0xFF, 0xC9);  // 55µs
12
  }
13
  DQ = 0;
14
  t0_wait(0xFF, 0xFA);  // 6µs
15
  DQ = 1;
16
  t0_wait(0xFF, 0xF6);  // 9µs
17
  Thigh = DQ;
18
}

von Klaus W. (mfgkw)


Angehängte Dateien:

Lesenswert?

Vielleicht gehen ja die Dateien im Anhang.
Damit hatte ich mal erfolgreich von einem DS1820 gelesen
(atmega32, 16MHz).

Leider in C++, aber der für dich relevante Teil ist reines C.
Als Ausgangsbasis kannst du ja damit anfangen und weglassen, was
du nicht brauchst (in C++ ist eigentlich nur die LCD-Ausgabe).

von Klaus W. (mfgkw)


Lesenswert?

PS: sehe gerade, daß da auch noch auskommentiert das gleiche
Spiel für einen TSic 206 dabei ist.

Ebenso wird irgendwo eine LED an- oder asusgeschaltet, der
Kommentar dazu faselt von einem Relais (für das der Quelltext später 
verwendet wurde).

Nicht verwirren lassen!

von BvB (Gast)


Lesenswert?

Du kannst auch mal hier schauen, da wird speziell das Timing und der 
Zugriff auf den DS18S20er recht gut erklärt:

Beitrag "1-Wire-Bus-Projekt: DS1820  DS18S20  DS2450  DS2408  unter C und 8051"

Bernd

von unknown (Gast)


Lesenswert?

Danke für eure Codes, die kann ich auf meinem μC aber leider nicht 
benutzen. Und große Unterschiede zu meinem Code kann ich nicht erkennen 
- trotzdem geht er nicht.
Ansonsten bin ich genau so vorgegangen wie in deinem Dokument, BvB, das 
echt super ist. Dennoch funktioniert nach wie vor nur das Resetsignal.

Ich hab den Code jetzt zwar so umgeschrieben, dass der komplette 
Scratchpad (9 Bytes) ausgelesen wird, ich erhalte aber nur lauter Einsen 
als Ausgabe, was bedeutet, dass der Sensor nicht reagiert:
1
void write(unsigned char c)
2
{
3
  char cnt;
4
  for (cnt = 0; cnt < 8; ++cnt) {
5
    DQ = 0;
6
    if ((c >> cnt) & 1 == 1)
7
      DQ = 1;
8
    delay_us(12); // 100µs
9
    DQ = 1;  
10
  }
11
}
1
void read()
2
{ 
3
  char cnt, i;
4
  for (i = 0; i < 9; ++i) {
5
    for (cnt = 0; cnt < 8; ++cnt) {
6
      DQ = 0;
7
      DQ = 1;
8
      delay_us(2);  // 15µs
9
      ds1820[i] |= ((char) DQ << cnt);
10
      delay_us(12);  // 100µs
11
    }
12
  }
13
}
Ich setze DQ ja immer auf 1, weshalb diese auch immer in das Array 
ds1820 geschrieben wird.
Da alle gelesenen Bits kein Signal zurückgeben, muss der Fehler muss 
entweder in der Zeitverzögerung der read-Funktion liegen (zu kurz), oder 
in der write-Funktion. Ich hab schon alle möglichen minimale bis 
maximale mögliche Werte probiert, aber leider keine Änderung.

Weiß jemand wie der Sensor reagiert, wenn der vorhergehende READ-Befehl 
nicht erfolgreich war? Antwortet er dann überhaupt?

von Benni L. (sutter_cain)


Lesenswert?

Ich habe da gerade so eine Befürchtung ;)

was benutzt du eigentlich für einen Controller? Und kannst du mal hier 
posten wie DQ definiert ist.

Ich befürchte nämlich, dass du den Bus mit beim Lesen nicht in den 
hochohmigen Zustand versetzt sondern auf aktiv High (Pin von Output auf 
Input ändern beim Lesen). Bei Atmel musst du dazu das DDR ändern, bei 
PIC das TRIS Register.

unknown schrieb:
> Weiß jemand wie der Sensor reagiert, wenn der vorhergehende READ-Befehl
>
> nicht erfolgreich war? Antwortet er dann überhaupt?

Das meine ich mit meinem Post. Er wird womöglich versuchen zu antworten, 
aber es nicht schaffen den Bus gegen den Controller herunterzuziehen.

von unknown (Gast)


Lesenswert?

Ich hab einen AT89C5131 von Atmel. Kompilieren tu ich mit dem 
C51-Compiler, der auch von Atmel ist.
1
sfr p = 0xA0;       // Port 2
2
sbit DQ = P2^0;     // Daten I/O

Bisher hab ich nur auf DQ zugegriffen. Beim DDR hab ich nichts gemacht. 
Ich wüsste auch gar nicht was man da ändern kann. ;)

Wäre schön wenn du mir das noch genauer erklären könntest.

von Benni L. (sutter_cain)


Lesenswert?

http://www.mikrocontroller.net/articles/Ausgangsstufen_Logik-ICs#Tri-state

Beim AVR kann man über das DDR (DataDirectionRegister) in den 
hochohmigen Zustand schalten.

http://www.freewebs.com/maheshwankhede/basic.html
Da ist so einiges beschrieben. Meine Vermutung ist, du musst entweder 
die OpenDrain I/O an P0 benutzen oder die selbst eine Ausgangsstufe 
diskret bauen.

von unknown (Gast)


Lesenswert?

Also selber bauen geht leider nicht, da ich davon keine Ahnung hab. Ich 
steuere die Bausteine nur an, kann sie aber nicht selbst herstellen...

Und den Sensor an P0 anzuschließen hat leider auch keinen Erfolg 
gebracht. Aber das liegt vllt. auch daran, weil der bei mir irgendwie 
defekt ist. Da funktioniert nicht einmal das Reset-Signal. Aber sind die 
Signale denn nicht identisch? Ich mein, wenn der Sensor auf einen Reset 
antworten kann, dann müsste er doch auch auf einen Lese-Befehl antworten 
können.

von Benni L. (sutter_cain)


Lesenswert?

Hmm ich hab mir das Bild der I/O vom AT89C5131 nochmal genauer 
angeschaut. Du hast recht, es sollte auch mit P2 funktionieren und DQ = 
1. Wie hast du den DS18S20 angeschlossen? VCC und GND und den Bus mit 
Pullup? Oder mit parasitärer Versorgung nur über den Bus?

Woher weisst du, dass du den Presence Pulse sicher empfängst? Dürfte ich 
da mal die Funktion dafür sehen? Ein Oszi hast du nich zufällig?

von unknown (Gast)


Lesenswert?

Ich hab den Sensor mit allen drei Anschlüssen am Port angeschlossen.

Die reset-Funktion:
1
char TEMP_SENSOR_reset()
2
{
3
  char ret = 0;
4
5
  DQ = 0;
6
  delay_us(500);
7
  DQ = 1;
8
  delay_us(70);
9
  ret = DQ;
10
  delay_us(500);
11
  return ret;
12
}
Wenn ich DQ nicht angeschlossen hab wird eine 1 zurückgegeben, ansonsten 
eine 0 - was bedeutet, dass der Sensor geantwortet hat.

von unknown (Gast)


Lesenswert?

Und nein, ich hab keinen Oszi.

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.