Forum: Mikrocontroller und Digitale Elektronik DS1620 - Auslesen der Temperatur?


von Oliver P. (atmega32user)


Angehängte Dateien:

Lesenswert?

Hi an das Forum,

ich habe gerade einen DS1620 am ATmega16 (16Mhz) in Betrieb. Das 
auslesen der Temperatur und der TempMin und TempMax Werte klappt soweit.

Jetzt das neue Problem!

Auf dem LCD (2x16 Standart) werden nur aber nur 1°C Schritte angezeigt!?

Anbei die aktuelle ds1620.c Datei.


Wie bringe ich den DS1620 dazu 0.5°C Schritte auszugeben.


Grüße Olli P.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Nette Library! Da war kein Dummer am Werk. Einen Fehler/ein Problem in 
der Library halte ich daher für unwahrscheinlich und konzentriere mich 
auf folgende Frage:

Wie benutzt du die Library?

In dem Anhang kann man genau das nicht sehen, weil das komplette 
Userpergramm ("main()") fehlt.

Dein Problem könnte z.B. die Umrechnung des Ergebnisses, das die Library 
zurück gibt, in eine Temperatur sein.

Oder die Benutzung von ds1620_get_temp() um das DS1620 auszulesen statt 
ds1620_get_temp_L() mit ds1620_get_temp_H(). Denn man erwartet ja ein 
9-Bit Ergebnis.

Oder die Darstellung der Temperatur auf dem LCD, denn es sind 2 Stellen 
mehr anzuzeigen.

Oder die Initialisierung des DS1620, denn an der wurde anscheinend 
gegenüber der Originalversion was geändert.

von Oliver P. (atmega32user)


Lesenswert?

Stefan B. wrote:
> Nette Library! Da war kein Dummer am Werk. Einen Fehler/ein Problem in
> der Library halte ich daher für unwahrscheinlich und konzentriere mich
> auf folgende Frage:
>
> Wie benutzt du die Library?
>
> In dem Anhang kann man genau das nicht sehen, weil das komplette
> Userpergramm ("main()") fehlt.
Main.c
1
int main (void)
2
{
3
  unsigned char buffer[6];
4
  unsigned char buffertlow[6];
5
  unsigned char bufferthigh[6];
6
  
7
  LCDinit ();
8
  _delay_ms(100);
9
    
10
  delay1s();
11
  
12
  
13
  LCDclr();
14
  
15
    
16
  delay1s();
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  ds1620_init();
25
  
26
  delay1s();
27
  LCDclr();
28
    
29
  while(1)
30
  {  
31
  
32
  
33
   dtostrf((double) ds1620_get_temp(), 5, 1,buffer);
34
  
35
  
36
  _delay_ms(10);
37
  
38
   dtostrf( (float)ds1620_read_temp_L(), 5, 1, buffertlow);
39
   
40
  _delay_ms(10);
41
  
42
  
43
   dtostrf((float)ds1620_read_temp_H(), 5, 1, bufferthigh);
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
    
53
  LCDGotoXY(0,1);
54
  LCDsendChar(buffer[0]);
55
  LCDGotoXY(1,1);
56
  LCDsendChar(buffer[1]);  
57
  LCDGotoXY(2,1);
58
  LCDsendChar(buffer[2]);
59
  LCDGotoXY(3,1);
60
  LCDsendChar(buffer[3]);
61
  LCDGotoXY(4,1);
62
  LCDsendChar(buffer[4]);
63
  LCDGotoXY(5,1);
64
  LCDsendChar(buffer[5]);
65
  LCDGotoXY(6,1);
66
  LCDsendChar('C');
67
  
68
  delay1s();
69
  delay1s();
70
71
  CopyStringtoLCD (LCDtemperaturMin,0,0);
72
  LCDGotoXY(0,1);
73
  LCDsendChar(buffertlow[0]);
74
  LCDGotoXY(1,1);
75
  LCDsendChar(buffertlow[1]);  
76
  LCDGotoXY(2,1);
77
  LCDsendChar(buffertlow[2]);
78
  LCDGotoXY(3,1);
79
  LCDsendChar(buffertlow[3]);
80
  LCDGotoXY(4,1);
81
  LCDsendChar(buffertlow[4]);  
82
  LCDGotoXY(5,1);
83
  LCDsendChar(buffertlow[5]);  
84
  LCDGotoXY(6,1);
85
  LCDsendChar('C');
86
  
87
  delay1s();
88
  delay1s();
89
  
90
  CopyStringtoLCD (LCDtemperaturMax,0,0);
91
  LCDGotoXY(0,1);
92
  LCDsendChar(bufferthigh[0]);
93
  LCDGotoXY(1,1);
94
  LCDsendChar(bufferthigh[1]);  
95
  LCDGotoXY(2,1);
96
  LCDsendChar(bufferthigh[2]);
97
  LCDGotoXY(3,1);
98
  LCDsendChar(bufferthigh[3]);
99
  LCDGotoXY(4,1);
100
  LCDsendChar(bufferthigh[4]);
101
  LCDGotoXY(5,1);
102
  LCDsendChar(bufferthigh[5]);
103
  LCDGotoXY(6,1);
104
  LCDsendChar('C');
105
  
106
  delay1s();
107
  delay1s();
108
  
109
  
110
  }
111
  return 0;
112
    
113
}
> Dein Problem könnte z.B. die Umrechnung des Ergebnisses, das die Library
> zurück gibt, in eine Temperatur sein.
Das muß ich noch checken!
> Oder die Benutzung von ds1620_get_temp() um das DS1620 auszulesen statt
> ds1620_get_temp_L() mit ds1620_get_temp_H(). Denn man erwartet ja ein
> 9-Bit Ergebnis.
Mit getByte gibt er bei 8Bit das richtige Ergebnis aus! Bei 9Bit 
halbiert er das Ergebnis!
> Oder die Darstellung der Temperatur auf dem LCD, denn es sind 2 Stellen
> mehr anzuzeigen.
Mit den Stellen hab ich schon 'rumgespielt' -> kein Erfolg!
>
> Oder die Initialisierung des DS1620, denn an der wurde anscheinend
> gegenüber der Originalversion was geändert.
In der Init werden die TempH und TempL mit jeweils 10ms Pause 
reingeschieben. Die Pausen sind wichtig, weil das EEPROM 'Zeit' braucht.

Grüße und Danke für die schnelle Antwort

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Mit dem Datenblatt und der Tabelle 3 zum Rückgabeformat würde ich es so 
machen (nicht die knappste Form, sondern nachvollziehbar geschrieben)
1
  // Ersetze
2
  //    dtostrf((double) ds1620_get_temp(), 5, 1,buffer);
3
  // durch
4
  {
5
    double dtemp;
6
    int itemp;
7
8
    itemp = ds1620_read_temp_L();
9
    itemp += (ds1620_read_temp_H()<<8);
10
    dtemp = (double)(itemp>>1);
11
    if (itemp & 1) // LSB zeigt 0,5 Grad an
12
        dtemp += 0,5;
13
    dtostrf(dtemp, 5, 1, buffer);
14
  }

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ADD: Deine 5 in dstrtof() ist zu knapp. buffer[] anpassen nicht 
vergessen!

    1 Zeichen Vorzeichen
max 3 Zeichen Vorkommazeichen Temperatur
    1 Zeichen Komma/Punkt
    1 Zeichen Nachkommazeichen Temperatur
   ===
    6 Zeichen für dstrtpf()

    1 Nullbyte im buffer[],
      kontrollieren/sicherstellen, dass das auch geschrieben wird!
   ===
    7 Zeichen für buffer[]

von Oliver P. (atmega32user)


Lesenswert?

Hi Stefan,

ich hab das mal mit der Routine ausprobiert! Das klappt soweit. Kann es 
sein das er jetzt damit in Zentel und Huderstel umrechnet. Die Anzeige 
lautet:

066.28°C
1
  LCDGotoXY(0,1);
2
  LCDsendChar(buffer[5]); //Hunderter   0xx.xx
3
  LCDGotoXY(1,1);
4
  LCDsendChar(buffer[0]); //Zehner     x0x.xx
5
  LCDGotoXY(2,1);
6
  LCDsendChar(buffer[1]);  // Einer xx0.xx
7
  LCDGotoXY(3,1);
8
  LCDsendChar(buffer[4]);  //Dezimalpunkt     xxx.xx
9
  LCDGotoXY(4,1);
10
  LCDsendChar(buffer[3]); // Zentel xx.0x
11
  LCDGotoXY(5,1);
12
  LCDsendChar(buffer[2]); // Hunderstel xxx.x0
13
  LCDGotoXY(6,1);
14
  LCDsendChar(buffer[6]); // Gradzeichen xxx.xx°
15
  LCDGotoXY(7,1);
16
  LCDsendChar('C');    //Celsiuszeichen xxx.xxxC
Ich habe das buffer[7] Array angepasst, habe es aber nach obenstehenden 
Muster anpassen müssen. Die Temperatur ist der Vorlauf der Heizung. 
Müsste also einigermasen passen, oder?

Grüße von Olli P.


PS. Danke für deine Mühe

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Verstehe ich nicht.

Laut Doku zur dtostrf 
(http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#g060c998e77fb5fc0d3168b3ce8771d42)
könnte nach diesem Aufruf

   dtostrf((double) 66.28, 5, 1, buffer);

folgendes im buffer stehen:

  0   1   2   3   4   5   6    Index im buffer[]
+---+---+---+---+---+---+---+
| ? | ? |'6'|'6'|'.'| ? | ? |
+---+---+---+---+---+---+---+

An den ? Stellen war ich mir auch nach Lesen der Doku nicht sicher. 
Deshalb habe ich es im AVR Studio simuliert (s. Anhang).

Eine (steht im C-Lehrbuch, vergisst man aber manchmal) Erkenntnis:

1. Der lokal definierte buffer ist zu Anfang nicht mit Nullen gefüllt. 
Wenn man was in diesen Puffer schreibt, sollte man selbst im Sinn von 
good practice gegen Bufferoverflows für einen Abschluss mit einem 
Nullbyte sorgen.

Zum Testen habe ich WinAVR 20071221 verwendet. Das ist insofern wichtig, 
als dass ein paar Ungereimtheiten auftauchen, die ich für Bugs halte. 
Dabei kommt nämlich raus:

2. Die dtostrf() macht einen Abschluss des Puffers mit einem Nullbyte. 
Wenn Platz ist!

3. Es werden keine führenden Nullen ausgegeben sondern Leerzeichen, 
ausser es ist eine Zahl mit Ganzzahlanteil 0 (Bsp. 0.23).

4. Bei positiven Zahlen wird kein + als Vorzeichen ausgegeben. Die 
Stelle des Vorzeichens wird wenn nötig für eventuelle Dezimalzahlstellen 
benutzt Bsp. 123.28 => "123.3"

5. Wenn die Zahl mehr Stellen hat wie der Parameter __width, hält sich 
dtostrf nicht daran (Bsp. 3123.28 => "3123.3", das sind 6 Stellen!). 
dtostrf() schreibt über die ihm zugewiesenen Stellen hinaus, wenn der 
Parameter __val unglücklich ist! Im Computerjargon wäre das jetzt eine 
Zero-Day-Lücke ;-)

6. Bei den Nachkommastellen wird gerundet und nicht abgeschnitten (Bsp. 
3123.28 => "3123.3"

So gesehen, würde ich itemp noch begrenzen z.B. auf 3 Dezimalstellen vor 
dem Komma (das reicht bei dem DS1620 ja dicke)

    dtemp = (double)((itemp>>1) % 1000);

ADD: Wenn die führenden '0' gewollt sind, würde ich nach der Umwandlung 
den buffer scannen und führende ' ' durch '0' ersetzen.

von Oliver P. (atmega32user)


Lesenswert?

Hi an das Forum (Stefan),

immer noch hab ich das Problem mit der 0,5 Grad Stelle des DS1620.
1
unsigned char ds1620_get_byte (void)
2
{
3
  unsigned char byte = 1;
4
    DDR_DS1620 &= ~(1<<DQ_DS1620);
5
  for (unsigned char i=0; i<8; i++)
6
  {
7
    PORT_DS1620 &= ~(1<<CLK_DS1620);
8
    if (PIN_DS1620 & (1<<DQ_DS1620))
9
      byte |= 0x80;
10
      
11
      
12
    PORT_DS1620 |= (1<<CLK_DS1620);
13
                   byte = (byte >> 1);
14
    
15
  }
16
  DDR_DS1620 |= (1<<DQ_DS1620);
17
  return byte;
18
}

Eigentlich müßte die Routine oben 9Bit auslesen (nach Datenblatt)

...
for (unsigned char i=0; i<9; i++)
...

Im Code oben wird aber nur 0 bis <8 entspricht 8Bit ausgelesen.

Wenn ich statt 8 die 9 einsetze dann liest der µC nur halbe Werte aus.

Also 13.0 statt 26.0 !?

An was kann das liegen?

Ich bin schon seit drei Tagen am coden, komme aber nicht weiter mit der 
Halbgradkommastelle nicht weiter!

Danke für Eure Hilfe!

Grüße OLLI

PS: Der Code ist weiter oben zu lesen (Anhang)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du solltest nicht ds1620_get_byte() nehmen, um die Temperatur zu 
lesen. Die Funktion ds1620_get_byte() ist dazu da, um andere 8-Bit Werte 
(Konfiguration, Status, etc.) zu lesen.

Für die Temperatur gibt es andere Funktionen, die mit dem temp im Namen 
(sic!). Du hattest die doch schon benutzt und du warst doch schon damit 
erfolgreich. Warum bist du jetzt zu ds1620_get_byte() umgeschwenkt?

von Oliver P. (atmega32user)


Lesenswert?

Hi Stefan,

erfolgreich zum Teil. Er ließt ja die Temp aber eben nur VOR dem Komma.

Ich krieg noch nen Vogel. ;)

Danke für die schnelle Antwort

Grüße OLLI

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1
// Rest vom Programm hier
2
3
void anzeige_temp(char *s, unsigned char col, unsigned char row)
4
{
5
  while(*s)
6
  {
7
    LCDGotoXY(col++, row);
8
    LCDsendChar(*s++);
9
  }
10
  LCDGotoXY(col++, row);
11
  LCDsendChar(0xB0);      // Gradzeichen?
12
  LCDGotoXY(col, row);
13
  LCDsendChar('C');
14
}
15
16
int main (void)
17
{
18
  _delay_ms(100);
19
  LCDinit ();
20
    
21
  delay1s();
22
  LCDclr();
23
24
  delay1s();
25
  ds1620_init();
26
  
27
  delay1s();
28
  LCDclr();
29
30
  while(1)
31
  {  
32
    unsigned char buffer[7];
33
    double dtemp;
34
    int itemp;
35
    
36
    _delay_ms(10); //(un-)Sicherheitspaeuschen
37
38
    // 9-Bit Wert als zwei getrennten Bytes einlesen
39
    itemp = ds1620_read_temp_L();
40
    itemp += (ds1620_read_temp_H()<<8);
41
42
    // 9-Bit Wert in Temperatur umrechnen
43
    dtemp = (double)((itemp>>1) % 1000); // max. 3 Vorkommastellen
44
    if (itemp & 1)                       // LSB zeigt 0,5 Grad an
45
        dtemp += 0.5;                    // 1 Nachkommastelle
46
47
    // Ausgabe formatieren
48
    dtostrf(dtemp, 5, 1, buffer);        // double => String
49
    buffer[6] = '\0';                    // sicher abschliessen
50
51
    // Auf LCD anzeigen
52
    anzeige_temp(buffer, 0, 1);
53
  }
54
  return 0;
55
}

von Oliver P. (atmega32user)


Lesenswert?

Hi @Stefan,

jetzt hab ich die Routineeingebaut und ......


Anzeige 468.5°C  (das Grad Zeichen ist bei mir 0x00 - Eigner 
Zeichensatz)


was ist jetzt wieder los?


Grüße OLLI

von Oliver P. (atmega32user)


Lesenswert?

Hi @Stefan,


wenn ich die Zeile :// itemp += (ds1620_read_temp()<<8);

ausblende gitbt er 13.5°C mit Halbgradschritten aus und er miss auch 
verschiedene Werte. Jetzt gilts nur den Wert vor dem Komma zu verdoppeln 
oder wo (wie) muß ich das machen?

Grüße OLLI

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Oh sorry, der Blick ins Datenblatt zeigt: Da habe ich was verwechselt! 
Ich schäme mich.

Die Funktionen ds1620_read_temp_L() und ds1620_read_temp_H() sind 
nicht dafür da, um die aktuelle Temperatur auszulesen!

Sie sind dafür da, um die untere und obere Alarmgrenzen auszulesen. Kein 
Wunder dass du bei dem Mix aus unterer Grenze und oberer Grenze solche 
Werte bekommst!

Die aktuelle Temperatur liest man mit der Funktion ds1620_get_temp() 
aus. Und für die höherwertigen Bits wird die ds1620_get_byte() benutzt. 
Denke ich mal aus dem Anschauen der Library her.

Also ersetze das Einlesen mal probeweise bitte so:

// 9-Bit Wert als zwei getrennten Bytes einlesen
itemp = ds1620_get_temp();        // Read Temperature [AAh], LSB first
itemp += (ds1620_get_byte()<<8);  // Read remaining bits (MSB)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Hmm, die Libraryfunktion wirft ein Bit und zwar das für die 0,5°C 
Anzeige weg. Ich habe im Moment noch nicht die ganze Library 
durchgesehen, ob das sonstwo noch auftritt, vermute es aber.

Es kann vielleicht so beabsichtigt sein: Genereller Verzicht auf 0,5 °C 
Auflösung mit 9-Bit, um die Daten platzsparend (z.B. auf einem sehr 
kleinen µC) in 8-Bit = Byte handhaben zu können. Vom Stil der Library 
her denke ich nicht, dass es ein Bug ist.

Man kann das teilweise ändern, zumindest so, dass dein Programm läuft. 
Wie gesagt, kann das aber bei anderen Funktionen auch eine Rolle 
spielen.

Original:
1
unsigned char ds1620_get_byte (void)
2
{
3
  unsigned char byte = 0;
4
  DDR_DS1620 &= ~(1<<DQ_DS1620);
5
  for (unsigned char i=0; i<8; i++)
6
  {
7
    PORT_DS1620 &= ~(1<<CLK_DS1620);
8
    if (PIN_DS1620 & (1<<DQ_DS1620))
9
      byte |= 0x80;
10
    PORT_DS1620 |= (1<<CLK_DS1620);
11
    byte = (byte >> 1);                 // alte Position
12
  }
13
  DDR_DS1620 |= (1<<DQ_DS1620);
14
  return byte;
15
}

Ändere das mal in
1
unsigned char ds1620_get_byte (void)
2
{
3
  unsigned char byte = 0;
4
  DDR_DS1620 &= ~(1<<DQ_DS1620);
5
  for (unsigned char i=0; i<8; i++)
6
  {
7
    PORT_DS1620 &= ~(1<<CLK_DS1620);
8
    byte = (byte >> 1);                  // neue Position
9
    if (PIN_DS1620 & (1<<DQ_DS1620))
10
      byte |= 0x80;
11
    PORT_DS1620 |= (1<<CLK_DS1620);
12
  }
13
  DDR_DS1620 |= (1<<DQ_DS1620);
14
  return byte;
15
}

Vorsicht, das ist ein Hack! Man muss die Library abklopfen, dass dadurch 
nichts anderes zerbrochen wird. Das ist nicht schwer, aber man braucht 
etwas Zeit und Ruhe.

von Oliver P. (atmega32user)


Lesenswert?

Hi @Stefan,

also wenn ich es nach deiner Version mache:

...
// 9-Bit Wert als zwei getrennten Bytes einlesen
itemp = ds1620_get_temp();        // Read Temperature [AAh], LSB first
itemp += (ds1620_get_byte()<<8);  // Read remaining bits (MSB)


...

dann gibt er 13.5°C aus.

Wenn ich oben die Zeile:

itemp += (ds1620_get_byte()<<8);  // Read remaining bits (MSB)

lösche und

 dtemp = dtemp*2;

einfüge dann gibt er 24.5°C aus.

Grüße OLLI

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das hat aber "fast nix" mit der gemessenen Temperatur zu tun.

Das Bit für die 0,5°C ist nicht das gemessene Bit sondern eins aus dem 
Vorkommateil der Messung.

Der Sensor misst z.B. 23,5°C

Die Library schmeisst in der Originalfassung die 0,5°C weg und liefert 
die 23°C (binär 00010111). Wie gesagt, das ist nicht unbedingt ein Bug. 
Es kann Absicht sein, um eine kleine Library zu bekommen, wenn der 0,5° 
Schritt unwichtig ist.

Ich hatte aus dem Datenblatt die 9-Bit Beschreibung gesehen und zu wenig 
in die Library geschaut. Und daher den Ganzzahlanteil durch >>1 
berechnet: 00001011 und das sind 11°C. Dazu hatte ich das unterste Bit 
im Originalergebnis geprüft, ob ein 0,5°C Schritt vorliegt: ja. Ergebnis 
bei mir: 11,5°C. Falsch! Das einfach verdoppelt ergibt: 23°C. Falsch!

Jetzt deine letzte Methode: Das erste Byte auslesen, verdoppeln und dann 
ggf. 0,5 draufaddieren. Erstes Byte 00010111 und das ist 23°C. Geshiftet 
ist 00001011 und das sind 11°C. Das verdoppelt ist 22°C. Dann der Check 
auf 0,5°C beim ersten Byte am untersten Bit: ja, das ist gesetzt, weil 
es eine ungerade Temperatur ist, dann plus 0,5 . Ergebnis 22,5°C. 
Sieht besser aus, weil die .5 da ist ;-) Ist aber falsch!

Obacht, jetzt kommt's!

Wenn man die Library ändert, liefert sie im ersten Byte 00101111 und im 
zweiten Byte 00000000. Geshiftet >>1 sind das 0000 0000 0001 0111 d.h. 
23°C Ganzzahl. Dann im Originalergebnis das niederwertigste Bit auf den 
0,5°C prüfen: ja. also + 0,5°C. Gesamtergebnis: 23,5°C. Richtig!

von Oliver P. (atmega32user)


Lesenswert?

Hi @Stefan,

das mit der Libary kann ich nicht nachvollziehen?

Die Library schmeisst in der Originalfassung die 0,5°C weg und liefert
die 23°C (binär 00010111). Wie gesagt, das ist nicht unbedingt ein Bug.
Es kann Absicht sein, um eine kleine Library zu bekommen, wenn der 0,5°
Schritt unwichtig ist.


Ich hatte den DS1620 am Anfang in Betrieb und er zeigte mit die 
Temperatur ohne großes 'Bitverschieben usw.' so an: 23.5°C . Also mit 
Halbgradkommastelle.

Kann es sein das das EEPROM im DS1620 'verschossen' ist? Ich meine das 
mit get_byte und put_byte Experimenten irgendwie das Config Register 
durcheinander ist?

Welche Library muß ich 'ändern' um an das richtige Messergebniss zu 
kommen?

Grüße OLLI

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du schreibst jetzt:

> Ich hatte den DS1620 am Anfang in Betrieb und er zeigte mit die
> Temperatur ohne großes 'Bitverschieben usw.' so an: 23.5°C . Also mit
> Halbgradkommastelle.

Das verstehe ich nicht, denn im allerersten Posting schreibst du:

>> Auf dem LCD (2x16 Standart) werden nur aber nur 1°C Schritte angezeigt!?

Zu dem Verdacht, dass der DS1620 inzwischen nur noch teurer Sand ist: No 
panic! Der DS1620 ist bestimmt nicht kaputt oder verstellt. 
ds1620_put_byte() wurde ja bisher nicht benutzt. Und wenn, die Viecher 
sollen stabil sein.

Du kannst ja mit der Originallibrary testen, ob plausible Temperaturen 
gemessen werde, wenn du auf die 0,5°C Schritte verzichtest. Du brauchst 
nur eine bekannte Temperaturquelle oder ein anderes Thermometer oder den 
DS1620 beim Messen in die Finger zu nehmen. Wenn die Messungen dann 
ähnlich sind oder der Messwert steigt, ist der DS1620 nicht futsch.

Der Code dafür sähe so aus (nur die Änderungen)
1
#include <stdlib.h>         // wegen itoa() s.u.
2
3
    _delay_ms(10); //(un-)Sicherheitspaeuschen
4
5
// Beginn der Änderungen
6
    // 8-Bit Wert ohne .5 Bit einlesen
7
    itemp = ds1620_read_temp();
8
    
9
    // Ausgabe formatieren
10
    itoa(itemp, buffer, 10);
11
// Ende der Änderungen
12
13
    // Auf LCD anzeigen
14
    anzeige_temp(buffer, 0, 1);

Für die 9-Bit kann man die Library ändern oder - besser - eine eigene 
Funktion schreiben.
1
int ollis_ds1620_get_temp (void)
2
{
3
  int result = 0;
4
  PORT_DS1620 |= (1<<RES_DS1620);
5
  /*send read temperature command*/
6
  ds1620_put_byte (0xAA);
7
  /*receive values stored in temperature-registers*/
8
  DDR_DS1620 &= ~(1<<DQ_DS1620);
9
  for (unsigned char i=0; i<9; i++)
10
  {
11
    PORT_DS1620 &= ~(1<<CLK_DS1620);
12
    result = (result>>1);
13
    if (PIN_DS1620 & (1<<DQ_DS1620))
14
      result |= (1<<8);
15
    PORT_DS1620 |= (1<<CLK_DS1620);
16
  }
17
  DDR_DS1620 |= (1<<DQ_DS1620);
18
  // Vorzeichen der 9-Bit Zahl auf 16-Bit erweitern
19
  if (result & (1<<8))
20
    result |= ~(0x1FF);
21
  PORT_DS1620 &= ~(1<<RES_DS1620);
22
  return result;
23
}

Um die eigene Funktion einzubauen, wird das Programm angepasst:
1
    _delay_ms(10); //(un-)Sicherheitspaeuschen
2
3
// Beginn der Änderungen
4
    // 9-Bit Wert mit .5 Bit einlesen
5
    itemp = olli_ds1620_read_temp();
6
    dtemp = (itemp & 1) ? 0.5 : 0.0; // LSB (.5C Bit) prüfen
7
    itemp /= 2;      // LSB (.5C Bit) entfernen
8
    itemp %= 1000;   // max. 3 Vorkommastellen (+ eventuell Vorzeichen)
9
    dtemp += itemp;
10
    
11
    // Ausgabe formatieren
12
    dtostrf(dtemp, 6, 1, buffer);        // double => String
13
    buffer[6] = '\0';                    // sicher abschliessen
14
// Ende der Änderungen
15
16
    // Auf LCD anzeigen
17
    anzeige_temp(buffer, 0, 1);

von Oliver P. (atmega32user)


Lesenswert?

Hi @Stefan,

so jetzt hab ich Deine 'eigene' Funktion eingebaut. Das LCD gibt jetzt 
24.5°C aus (Raumtemperatur). Mit einem Vergleichsthermometer messe ich 
21.5°C . Also einen Unterschied von 3°C .


Als Vergleich habe ich einen anderen DS1620 genommen. Der reagiert 
genauso!
Folglich ist ein Defekt des DS1620 fast ausgeschlossen.

Ich habe aber vieleicht noch eine andere Vermutung. Kann es sein das 
wenn ich eigene Zeichen (8 Stück) für das LCD definiert habe er im 
PROGMEM da igendwas überschreibt!

der Code für die Zeichen in der lcd.c (Auszug):
1
....
2
static const unsigned char LcdCustomChar[] PROGMEM=
3
{
4
  0x0C, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, // 0. 0/5 degree
5
  0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x12, 0x0C, 0x00, // 1. 1/5 therm empty
6
  0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x0C, 0x00, // 2. 2/5 therm full
7
  0x00, 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x00, // 3. 3/5 Pfeil hoch
8
  0x00, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04, 0x00, // 4. 4/5 Pfeil runter
9
  0x00, 0x0E, 0x15, 0x1F, 0x15, 0x1B, 0x0E, 0x00, // 5. 5/5 Smilie Lach
10
  0x00, 0x0E, 0x15, 0x1F, 0x1B, 0x15, 0x0E, 0x00, // 6. 6/5 Smilie Wein
11
  0x00, 0x0E, 0x15, 0x1F, 0x11, 0x1F, 0x0E, 0x00  // 7. 7/5 Silie  Gleich
12
};
13
.....

Ich habe die Zeichen mal ausgeblendet, also nicht definiert. Es ergibt 
sich aber keine Änderung.


Ist eben nur eine Vermutung da ich in C kein Profi bin.


Grüße OLLI

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wie genau ist genau? Was misst man, wenn man misst?

Bei den Werten

DS1620: 24.5°C
Vergleichsthermometer: 21.5°C

ist IMHO die Software OK. Der Sensor liefert halt ein anderes Ergebnis 
als das Vergleichstermometer. Der Temperaturfehler des Sensors ist im 
Datenblatt angegeben (bei Vcc zwischen 3 und 5,5V und Temperaturen 
zwischen 0 und 70°C: +- 0,5 °C). Wie sieht das bei deinem 
Vergleichsthermometer aus?

In der Praxis würde man ein jetzt eine Kalibrierung machen. Das geht 
u.a.

1. mit Referenztemperaturen auf den Spuren von Anders Celsius
D.h. feste Referenztemperaturen einstellen und die Messung wiederholen. 
Dann die Messwerte auf die Referenztemperaturen anpassen. Einfache 
Referenztemperaturen, für die man kein Thermometer braucht, sind der 
Siedepunkt von Wasser und der Schmelzpunkt von Wasser (Eis/Wasser Mix). 
Wenn du nicht Auf dem Mont Blanc wohnst sind das die bekannten 100 °C 
und 0 °C. Vorsicht: Sensor und Zuleitungen mit dünnem PE-Tütchen o.ä. 
wasserdicht machen!

2. und/oder mit einem kalibrierten oder geeichten Referenzthermometer

Wenn es sehr schön läuft, zeigt dein DS1620 die Temperatur genauer an 
als dein Vergleichsthermometer.

Wenn es schön läuft, ist bloss ein konstanter Offset ("zuviel/zuwenig") 
über den gesamten Messbereich vorhanden.

Wenn es nicht so schön läuft ist ein veränderlicher, aber linearer 
Offset über den gesamten Messbereich vorhanden.

Wenn es hässlich läuft ist ein nicht-linarer Offset vorhanden.

von Oliver P. (atmega32user)


Lesenswert?

Hi @ Stefan,

das mit dem 'Messen' leuchtet mir ein.

Das Vergleichsthermometer: 21.5°C ist hald ein gekauftes Thermometer. 
Ich denke das es recht zuverlässige Werte liefert.

Jetzt habe ich einen Eiswürfel aus der Tiefkühltruhe geholt. Wenn ich 
den Würfel auf die Chipoberfläche draufdrücke bekomme ich einen Wert von 
5.5°C angezeigt. Plus wohlgemerkt. Er müsste doch um die 0°C anzeigen 
oder mischt sich die Umgebungstemperatur dazu und ich bekomme einen 
Messfehler?


Nachtrag:

Anzeige   5.5°C bei Eiswasser (0°C)

Anzeige  24.5°C bei Raumtemp. (21.5°C)



Grüße OLLI

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Den ausführlichen Abschnitt hier

    itemp = olli_ds1620_read_temp();
    dtemp = (itemp & 1) ? 0.5 : 0.0; // LSB (.5C Bit) prüfen
    itemp /= 2;      // LSB (.5C Bit) entfernen
    itemp %= 1000;   // max. 3 Vorkommastellen (+ eventuell Vorzeichen)
    dtemp += itemp;

kann man auch vereinfachen zu

    dtemp = ((double) olli_ds1620_read_temp()) / 2;

In den 8-Bit wird ja die Temperatur als Anzahl von 0,5 Grad Schritten 
gezählt. Und die Anzahl durch die Schrittweite ergibt dann die 
Temperatur. Und wenn man wie oben mit Realzahlen arbeitet und nicht mit 
Ganzzahlen, bleibt die Nachkommastelle bei der Division auch erhalten.

Und wenn es eng im AVR wird, kann man auch auf den ganzen 
Realzahlen-Teil und die Math-Library verzichten und nur mit Ganzzahlen 
arbeiten:

    char *nachkomma;
    itemp = olli_ds1620_read_temp();
    nachkomma = (itemp & 1) ? ",5" : ",0"; // LSB (.5C Bit) prüfen
    itemp /= 2;      // LSB (.5C Bit) entfernen
    itemp %= 1000;   // max. 3 Vorkommastellen (+ eventuell Vorzeichen)
    itoa(itemp, buffer, 10);
    strcat(buffer, nachkomma);

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Draufdrücken reicht nicht und der Eiswürfel frisch aus dem Schrank ist 
auch nicht OK. Der Eiswürfel aus der Eistruhe kann typ. -18 °C haben!

Für den Schmelzpunkt von Wasser stell dir ein Gläschen hin, mach den 
Eiswürfel rein und etwas Wasser. Wenn du deutlich siehst, dass der 
Eiswürfel schmilzt, hast du ein Gleichgewicht zwischen Eis und Wasser 
und die 0 °C.

Dann den geschützten Sensor eintunken und etwas warten, bis sich die 
Temperaturanzeige nicht mehr ändert. Im Sekundenbereich geht das nicht. 
Die Temperatur muss sich gleichmäßig durch das Chipgehäuse im Chip 
verteilen. Das braucht etwas Zeit.

Ich werde mal schauen, ob ich einen DS1620 auftreiben kann. Dann kann 
ich auch kontrollieren, ob "meine" Routine auch bei neg. Temperaturen 
richtig ist. Ich denke schon, aber Kontrolle ist besser als Vertrauen.

von Oliver P. (atmega32user)


Lesenswert?

Hi @ Stefan,

ich möchte mich auf diesem Wege mal bei Dir bedanken das Du Dir die Mühe 
machst mir "auf die Sprüge" zu helfen. Ich progge gern mit C und durch 
Dich hab ich wieder viiieeel dazugelernt. Danke!

Über die Länge des Codes mach ich mir z.Zt. keinen Kopf. Der ATmega16 
denke ich reicht für zwei Fühler. Hex z.Zt. 3706 Byte

Grüße OLLI

von Anthony S. (anthony_02)


Lesenswert?

Hi, ich weiß der Thread ist schon etwas älter aber hier wurde mein 
Problem schon am ausführlichsten diskutiert.

Ich habe das gleiche Problem, dass ich keine Nachkommastelle habe.

Den Wert den ich aus dem DS1620 erhalte schicke ich mir über die UART 
Schnittstelle eines ATTiny2313 an meinen Rechner.

Ich erhalte bei Raumtemperatur immer: (0x001B ; 0000 0000 0001 1011)
Laut Datenblatt wäre das: 13,5°C (was eher Unwahrscheinlich ist)
Oder es fehlt der LSB: 27°C (0000 0000 0011 011X)

Ich habe die Funktion verwendet, welche auch oben angegeben ist:

>int ollis_ds1620_get_temp (void)
>{
>  int result = 0;
>  PORT_DS1620 |= (1<<RES_DS1620);
>  /*send read temperature command*/
>  ds1620_put_byte (0xAA);
>  /*receive values stored in temperature-registers*/
>  DDR_DS1620 &= ~(1<<DQ_DS1620);
>  for (unsigned char i=0; i<9; i++)
>  {
>      PORT_DS1620 &= ~(1<<CLK_DS1620);
>      result = (result>>1);
>      if (PIN_DS1620 & (1<<DQ_DS1620))
>        result |= (1<<8);
>      PORT_DS1620 |= (1<<CLK_DS1620);
>  }
>  DDR_DS1620 |= (1<<DQ_DS1620);
>  // Vorzeichen der 9-Bit Zahl auf 16-Bit erweitern
>  if (result & (1<<8))
>  result |= ~(0x1FF);
>  PORT_DS1620 &= ~(1<<RES_DS1620);
>  return result;
>}


Und habe den "result" Wert dann folgender Maßen bearbeitet:

>main (void)
>{
>    InitUART(12);
>    ds1620_init();
>    while (1)
>    {
>
>    if(ReceiveUART() == 0x41)
>    {
>      int i_byte = phil_ds1620_get_temp();
>      unsigned char globale_byte_0 = ((i_byte>>8) & >0x01);
>      unsigned char globale_byte_1 = (i_byte & 0xFF);
>      TransmitUART(globale_byte_0);
>      TransmitUART(globale_byte_1);
>    }
>    }
>}


Hat jemand eine Idee?

Gruß
Anthony

von Anthony S. (anthony_02)


Lesenswert?

Hat hier keiner eine Idee worann es liegen könnte???

Gruß
Anthony

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.