mikrocontroller.net

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


Autor: Oliver P. (atmega32user)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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
int main (void)
{
  unsigned char buffer[6];
  unsigned char buffertlow[6];
  unsigned char bufferthigh[6];
  
  LCDinit ();
  _delay_ms(100);
    
  delay1s();
  
  
  LCDclr();
  
    
  delay1s();
  
  
  
  
  
  
  
  ds1620_init();
  
  delay1s();
  LCDclr();
    
  while(1)
  {  
  
  
   dtostrf((double) ds1620_get_temp(), 5, 1,buffer);
  
  
  _delay_ms(10);
  
   dtostrf( (float)ds1620_read_temp_L(), 5, 1, buffertlow);
   
  _delay_ms(10);
  
  
   dtostrf((float)ds1620_read_temp_H(), 5, 1, bufferthigh);
  
  
  
  
  
  
  
  
    
  LCDGotoXY(0,1);
  LCDsendChar(buffer[0]);
  LCDGotoXY(1,1);
  LCDsendChar(buffer[1]);  
  LCDGotoXY(2,1);
  LCDsendChar(buffer[2]);
  LCDGotoXY(3,1);
  LCDsendChar(buffer[3]);
  LCDGotoXY(4,1);
  LCDsendChar(buffer[4]);
  LCDGotoXY(5,1);
  LCDsendChar(buffer[5]);
  LCDGotoXY(6,1);
  LCDsendChar('C');
  
  delay1s();
  delay1s();

  CopyStringtoLCD (LCDtemperaturMin,0,0);
  LCDGotoXY(0,1);
  LCDsendChar(buffertlow[0]);
  LCDGotoXY(1,1);
  LCDsendChar(buffertlow[1]);  
  LCDGotoXY(2,1);
  LCDsendChar(buffertlow[2]);
  LCDGotoXY(3,1);
  LCDsendChar(buffertlow[3]);
  LCDGotoXY(4,1);
  LCDsendChar(buffertlow[4]);  
  LCDGotoXY(5,1);
  LCDsendChar(buffertlow[5]);  
  LCDGotoXY(6,1);
  LCDsendChar('C');
  
  delay1s();
  delay1s();
  
  CopyStringtoLCD (LCDtemperaturMax,0,0);
  LCDGotoXY(0,1);
  LCDsendChar(bufferthigh[0]);
  LCDGotoXY(1,1);
  LCDsendChar(bufferthigh[1]);  
  LCDGotoXY(2,1);
  LCDsendChar(bufferthigh[2]);
  LCDGotoXY(3,1);
  LCDsendChar(bufferthigh[3]);
  LCDGotoXY(4,1);
  LCDsendChar(bufferthigh[4]);
  LCDGotoXY(5,1);
  LCDsendChar(bufferthigh[5]);
  LCDGotoXY(6,1);
  LCDsendChar('C');
  
  delay1s();
  delay1s();
  
  
  }
  return 0;
    
}
> 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit dem Datenblatt und der Tabelle 3 zum Rückgabeformat würde ich es so 
machen (nicht die knappste Form, sondern nachvollziehbar geschrieben)

  // Ersetze
  //    dtostrf((double) ds1620_get_temp(), 5, 1,buffer);
  // durch
  {
    double dtemp;
    int itemp;

    itemp = ds1620_read_temp_L();
    itemp += (ds1620_read_temp_H()<<8);
    dtemp = (double)(itemp>>1);
    if (itemp & 1) // LSB zeigt 0,5 Grad an
        dtemp += 0,5;
    dtostrf(dtemp, 5, 1, buffer);
  }


Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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[]

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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
  LCDGotoXY(0,1);
  LCDsendChar(buffer[5]); //Hunderter   0xx.xx
  LCDGotoXY(1,1);
  LCDsendChar(buffer[0]); //Zehner     x0x.xx
  LCDGotoXY(2,1);
  LCDsendChar(buffer[1]);  // Einer xx0.xx
  LCDGotoXY(3,1);
  LCDsendChar(buffer[4]);  //Dezimalpunkt     xxx.xx
  LCDGotoXY(4,1);
  LCDsendChar(buffer[3]); // Zentel xx.0x
  LCDGotoXY(5,1);
  LCDsendChar(buffer[2]); // Hunderstel xxx.x0
  LCDGotoXY(6,1);
  LCDsendChar(buffer[6]); // Gradzeichen xxx.xx°
  LCDGotoXY(7,1);
  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

Autor: Stefan B. (stefan) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Verstehe ich nicht.

Laut Doku zur dtostrf 
(http://www.nongnu.org/avr-libc/user-manual/group__...)
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.

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi an das Forum (Stefan),

immer noch hab ich das Problem mit der 0,5 Grad Stelle des DS1620.
unsigned char ds1620_get_byte (void)
{
  unsigned char byte = 1;
    DDR_DS1620 &= ~(1<<DQ_DS1620);
  for (unsigned char i=0; i<8; i++)
  {
    PORT_DS1620 &= ~(1<<CLK_DS1620);
    if (PIN_DS1620 & (1<<DQ_DS1620))
      byte |= 0x80;
      
      
    PORT_DS1620 |= (1<<CLK_DS1620);
                   byte = (byte >> 1);
    
  }
  DDR_DS1620 |= (1<<DQ_DS1620);
  return byte;
}

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)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert

// Rest vom Programm hier

void anzeige_temp(char *s, unsigned char col, unsigned char row)
{
  while(*s)
  {
    LCDGotoXY(col++, row);
    LCDsendChar(*s++);
  }
  LCDGotoXY(col++, row);
  LCDsendChar(0xB0);      // Gradzeichen?
  LCDGotoXY(col, row);
  LCDsendChar('C');
}

int main (void)
{
  _delay_ms(100);
  LCDinit ();
    
  delay1s();
  LCDclr();

  delay1s();
  ds1620_init();
  
  delay1s();
  LCDclr();

  while(1)
  {  
    unsigned char buffer[7];
    double dtemp;
    int itemp;
    
    _delay_ms(10); //(un-)Sicherheitspaeuschen

    // 9-Bit Wert als zwei getrennten Bytes einlesen
    itemp = ds1620_read_temp_L();
    itemp += (ds1620_read_temp_H()<<8);

    // 9-Bit Wert in Temperatur umrechnen
    dtemp = (double)((itemp>>1) % 1000); // max. 3 Vorkommastellen
    if (itemp & 1)                       // LSB zeigt 0,5 Grad an
        dtemp += 0.5;                    // 1 Nachkommastelle

    // Ausgabe formatieren
    dtostrf(dtemp, 5, 1, buffer);        // double => String
    buffer[6] = '\0';                    // sicher abschliessen

    // Auf LCD anzeigen
    anzeige_temp(buffer, 0, 1);
  }
  return 0;
}


Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:

unsigned char ds1620_get_byte (void)
{
  unsigned char byte = 0;
  DDR_DS1620 &= ~(1<<DQ_DS1620);
  for (unsigned char i=0; i<8; i++)
  {
    PORT_DS1620 &= ~(1<<CLK_DS1620);
    if (PIN_DS1620 & (1<<DQ_DS1620))
      byte |= 0x80;
    PORT_DS1620 |= (1<<CLK_DS1620);
    byte = (byte >> 1);                 // alte Position
  }
  DDR_DS1620 |= (1<<DQ_DS1620);
  return byte;
}


Ändere das mal in

unsigned char ds1620_get_byte (void)
{
  unsigned char byte = 0;
  DDR_DS1620 &= ~(1<<DQ_DS1620);
  for (unsigned char i=0; i<8; i++)
  {
    PORT_DS1620 &= ~(1<<CLK_DS1620);
    byte = (byte >> 1);                  // neue Position
    if (PIN_DS1620 & (1<<DQ_DS1620))
      byte |= 0x80;
    PORT_DS1620 |= (1<<CLK_DS1620);
  }
  DDR_DS1620 |= (1<<DQ_DS1620);
  return byte;
}


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.

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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)

#include <stdlib.h>         // wegen itoa() s.u.

    _delay_ms(10); //(un-)Sicherheitspaeuschen

// Beginn der Änderungen
    // 8-Bit Wert ohne .5 Bit einlesen
    itemp = ds1620_read_temp();
    
    // Ausgabe formatieren
    itoa(itemp, buffer, 10);
// Ende der Änderungen

    // Auf LCD anzeigen
    anzeige_temp(buffer, 0, 1);


Für die 9-Bit kann man die Library ändern oder - besser - eine eigene 
Funktion schreiben.

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;
}

Um die eigene Funktion einzubauen, wird das Programm angepasst:

    _delay_ms(10); //(un-)Sicherheitspaeuschen

// Beginn der Änderungen
    // 9-Bit Wert mit .5 Bit einlesen
    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;
    
    // Ausgabe formatieren
    dtostrf(dtemp, 6, 1, buffer);        // double => String
    buffer[6] = '\0';                    // sicher abschliessen
// Ende der Änderungen

    // Auf LCD anzeigen
    anzeige_temp(buffer, 0, 1);


Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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):

....
static const unsigned char LcdCustomChar[] PROGMEM=
{
  0x0C, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, // 0. 0/5 degree
  0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x12, 0x0C, 0x00, // 1. 1/5 therm empty
  0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x0C, 0x00, // 2. 2/5 therm full
  0x00, 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x00, // 3. 3/5 Pfeil hoch
  0x00, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04, 0x00, // 4. 4/5 Pfeil runter
  0x00, 0x0E, 0x15, 0x1F, 0x15, 0x1B, 0x0E, 0x00, // 5. 5/5 Smilie Lach
  0x00, 0x0E, 0x15, 0x1F, 0x1B, 0x15, 0x0E, 0x00, // 6. 6/5 Smilie Wein
  0x00, 0x0E, 0x15, 0x1F, 0x11, 0x1F, 0x0E, 0x00  // 7. 7/5 Silie  Gleich
};
.....

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Oliver P. (atmega32user)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Anthony Swofford (anthony_02)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Anthony Swofford (anthony_02)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat hier keiner eine Idee worann es liegen könnte???

Gruß
Anthony

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.