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.
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.
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
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 | }
|
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[]
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
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.
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)
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?
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
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 | }
|
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
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
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)
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.
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
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!
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
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);
|
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
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.
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
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);
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.
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
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
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.
|