Forum: Mikrocontroller und Digitale Elektronik DS18B20 Datenformat


von Björn H. (firefunk)


Lesenswert?

Hallo zusammen,

ich verwende eine DS18B20 Lib von Stefan Sicklinger Link: 
http://www.sicklinger.com/en/atmel-avr-atmega-ds18x20-library-in-c.html

Ich bin quasi blutiger Anfänger und bin zu blöd den Temperaturwert an 
mein Display zu übergeben. Mein genaues Problem habe ich unten im Code 
kommentiert.
Bitte Helft mir.

hier mein Main:
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <string.h>
5
#include "i2cmaster.h"
6
#include "ds18x20lib.h"
7
#include <stdio.h>
8
#include <stdlib.h>
9
10
11
12
13
14
15
//**********************************************************************************************
16
// Display Ausgabe
17
//**********************************************************************************************
18
19
#define SLAVE_ADDRESS1 0xa0
20
21
22
void max6953_1(char cmd, char data)
23
{
24
i2c_start(SLAVE_ADDRESS1 | I2C_WRITE);
25
i2c_write(cmd);
26
i2c_write(data);
27
i2c_stop();
28
}
29
30
void writestr1(char *s)
31
{
32
char i;
33
for (i = 0; i < 4; i++)
34
max6953_1(0x20 | i, s[i]);
35
}
36
37
void main(void)
38
{
39
40
unsigned char temp_po_str[8];
41
float temp_po;
42
43
ds1820_init(DS1820_pin_po); //Initialize DS1820 Lufttemp
44
45
temp_po = ds1820_read_temp(DS1820_pin_po);//Get temperature from DS1820 Lufttemp
46
47
sprintf(temp_po_str,"%.0f",temp_po); //Convert temp. Lufttemp to string
48
49
unsigned char i;
50
unsigned char a;
51
52
53
char msg []= "Hallo";
54
55
 //Anstatt Hallo, wollte ich den Temperatur Wert Temp_po_str an das Char //Array msg übergeben.
56
57
//Nur leider bekomme ich nur ein völliges Wirwar angezeigt. Ich möchte die //Temperaturwerte auf einre Nachkommastelle und mit Vorleichen angezeigt //bekommen. Aber ohne das eigentliche Komma. z.B. +12,7°C = +127  oder //-6,9°C = -69
58
59
//Pins und Ports habe ich geändert und das Signal ist gut messbar auf der //Datenleitung.
60
61
//Verwende DS18B20 und Atmega16 bei 16 MHz
62
63
64
i2c_init();
65
if (i2c_start(SLAVE_ADDRESS2 | I2C_WRITE) != 0)
66
{
67
DDRB |= (1<<0); // falls Addresse 0 dann LED an PORTB.0 an.
68
PORTB &= ~(1<<0); // erste LED
69
}
70
i2c_stop();
71
max6953_1(0x01, 0xFF); // Intensität 10
72
73
max6953_1(0x02, 0xFF); // Intensität 32
74
75
max6953_1(0x03, 0x01); // scan limit
76
77
max6953_1(0x04, 0x01); // kein shutdown
78
79
max6953_1(0x07, 0x00); // display test mode
80
81
_delay_ms(2000); // 2 Sekunden warten
82
for (i = 0x60; i < 0x63; i++)
83
max6953_1(i, 0); // schreibe D0, D1
84
85
_delay_ms(4000);
86
while(1)
87
{
88
if (++i > strlen(msg) - 4) i = 0;
89
writestr1(msg + i); // schreibe vier Zeichen
90
_delay_ms(250);
91
92
}
93
return 0;
94
}

: Bearbeitet durch User
von Basti (Gast)


Lesenswert?

Hardware?? 10k pullup ??

von Björn H. (firefunk)


Lesenswert?

Basti schrieb:
> Hardware?? 10k pullup ??

Also wie gesagt: Das Signal ist gut messbar und ich verwende 4,7k Pullup 
an PA1 des Atmega16. Sensor ist ein DS18B20 Temparatursensor.
Ich bräuchte ledeglich jemand der sich mit der Umwandlung von Datentypen 
auskennt.

char msg []= "Hallo";

Anstatt Hallo (Funktioniert), wollte ich den Temperatur Wert Temp_po_str 
an das Char
Array msg übergeben.

Nur leider bekomme ich nur ein völliges Wirwar angezeigt.
Ich weiß nicht welche Art von Daten der String beinhaltet.
Ich möchte die Temperaturwerte auf einre Nachkommastelle und
mit Vorleichen angezeigt bekommen.
Aber ohne das eigentliche Komma. z.B. +12,7°C = +127  oder
-6,9°C = -69

von leluno (Gast)


Lesenswert?

du brauchst eine Funktion zur Umwandlung von Zahlen in Strings, da das 
LCD nur Zeichen ausgeben kann?
1
//------------------int als Dezimalzahl ausgeben ---------------
2
3
void lcd_dez(int int1)
4
{
5
char ausgabe[18];
6
int int2,int3;
7
int2= int1/100;
8
int3=int1-(int2*100);
9
utoa(int2,ausgabe,10);
10
lcd_write(ausgabe);
11
lcd_write(",");
12
utoa(int3,ausgabe,10);
13
lcd_write(ausgabe);
14
}

von Peter Körner (Gast)


Lesenswert?

Hi

dein Problem ist nicht AVR oder DS18B20-Spezifisch sondern ein 
generelles C-Problem. Ich würde dir daher empfehlen, das was du tun 
willst, außerhlb des AVR mit einem normalen C-Compiler zu testen.


In C sind Strings Null-Terminiert. Hast du also ein Array-of-Char das so 
ausschaut:
[H, a, l, l, o, \0, x, y, z]
wird dir strlen den Wert 5 zurückgeben, denn der String endet am 
Null-Byte.
Wenn du ein array-of-char mit fester Größe allozierst  (in deinem Code 
z.B. temp_po_str[8]), musst du darauf achten, dass maximal 7 Zeichen 
darin gespeichert werden und das 8. ein Null-Byte ist. dein sprintf-Call 
kann aber durchaus länger werden und dann über die Grenzen des Arrays 
hinaus schreiben.

Verwende daher lieber snprintf, gib die Länge als -1 deines 
array-of-char an und schreibe manuell an das ende des strings ein 
null-byte.

So viel zur Theorie.
In deinem Code ist temp_po_str ja bereits ein Array-of-char, also ein 
String. Du kannst es anstatt msg verwenden.

Lg, Peter

von Björn H. (firefunk)


Lesenswert?

Hallo leluno,
vielen Dank für deine Unterstützung! Könntest du deinen Code etwas 
kommentieren, damit ich es besser verstehen kann? Das wäre toll!

Hallo Peter,

ich habe jetzt temp_po_str direkt für msg verwendet.
temp_po_str erzeuge ich jetzt so:

snprintf(temp_po_str, sizeof(temp_po_str-1), "\0", temp_po);

aber da scheint noch ein Fehler versteck zu sein.

"Hallo" ist ja ein Char String oder?

bei:

char msg []= "Hallo";
oder auch
char msg []= "123456789";

wird ja keine länge vorgegeben...
mein Display hat vier Stellen und wenn der String länger als 4 Zeichen 
ist, wird msg unten im Code immer um "eins" erhöht und so als 
laufschrift dargestellt.

Vielen Dank schon mal!

von Roland .. (rowland)


Lesenswert?

Übergibst Du 'temp_po_str' direkt an Deine Ausgabefunktion, oder willst 
Du 'temp_po_str' erst in 'msg' kopieren und dann 'msg' mit Deiner 
Ausgabefunktion ausgeben?

von Praktikant (Gast)


Lesenswert?

Hallo,

ich mach das bei mir wie folgt:

1. Variable für bereitstellen
1
int buf[10];
2
float Temperature1;

2. Temperatur einlesen. Wobei meine Funktion auch einen Float-Wert 
liefert
1
Temperature1=DS18B20_Read_Addressed_Temperature(rom1,byte);

3. Meine LCD-Funktion erwartet ebenfalls einen String. Ich wandle meine 
Floatvariable mittels dtostrf() um
1
LCD_String(3,13,dtostrf(Temperature1,3,1,buf));

von atmeltierchen (Gast)


Lesenswert?

Du würdest uns einen gewaltigen Gefallen tun, wenn:

a. der Code anständig formatiert waere

b. die Variablen bezeichner haetten, die sich selbst erklären würden

c. du auf "Magische Nummern" verzichten würdest, z.B.


if (++i > strlen(msg) - 4) i = 0;

versteht kein Schwein.


Nimms mir nicht übel, aber in so einer Wüste helf ich niemanden 
Freiwillig.

von Björn H. (firefunk)


Lesenswert?

@ Roland: die zweite Variante wäre mir lieber.

@ Praktikant:

Ich habe jetzt mal das hier geschrieben aber es seint aucht nicht zu 
funktionieren :-(

temp_po = ds1820_read_temp(DS1820_pin_po);

int buf[10];


char msg(3,13,dtostrf(temp_po,3,1,buf));

was mache ich falsch?

von F. F. (foldi)


Lesenswert?

Vielleicht hast du auch den falschen Sensor oder die falsch lib zu 
diesem Sensor.
Hatte mal DS18*B*20 bestellt (dachte ich zumindest) und dann habe ich 
den DS18*S*20 bekommen. Kam auch nur Mist raus, weil für den S musste 
noch was umgerechnet werden.

Vielleicht hilft das weiter?

von Björn H. (firefunk)


Lesenswert?

@ F. Fo:
Daran habe ich auch schon gedacht und deshalb auch den Ersteller der Lib 
für den DS18B20 oder DS18S20 kontaktier aber leider noch keine Antwort 
erhalten.

Ich Finde die Lib recht übersichtlich und für mich leicht zu verstehen.
Ich kann zwar so nur einen Sensor pro Pin nutzen aber das reicht mir.

Vielleicht kennt ihr ja eine gute Lib für den DS18B20 bei der sich der 
Pin leicht einstellen lassen kann und den Temperatur Wert in Form eines 
Char String ausspuckt.

Grüße Björn

von Björn H. (firefunk)


Lesenswert?

Habe es jetzt mal so versucht:

snprintf(temp_po_str, sizeof(temp_po_str-1), "12.5");

anstatt der float Variablen temp_po habe ich jetzt mal "12.5" eingefügt.

Ergebnis = Mist

was kann ich da eintragen um einen definierten "float" Wert zu haben?

von Pete K. (pete77)


Lesenswert?

Bei float musst Du auch die Float-Lib mit linken. Ist das geschehen?

von Pete K. (pete77)


Lesenswert?

Laut library ist der Rückgabewert vom Typ unsigned char temp_po_str[8] 
und muss nicht weiter konvertiert werden.

Vielleicht mal mit Ausgaben an RS232 debuggen?

von Björn H. (firefunk)


Lesenswert?

Pete K. schrieb:
> Laut library ist der Rückgabewert vom Typ unsigned char temp_po_str[8]
> und muss nicht weiter konvertiert werden.
>
> Vielleicht mal mit Ausgaben an RS232 debuggen?

Die Float lib ist mit drinnen.

Was meinst du mit Ausgabe an RS232 debuggen?

Grüße Björn

von F. F. (foldi)


Lesenswert?

Björn Hiekel schrieb:

> Ich kann zwar so nur einen Sensor pro Pin nutzen aber das reicht mir.

Hä? Das ist One-Wire, da kannst du so viele dran hängen wie du willst.

Ich hatte das mit Arduino gemacht, bei C bin ich noch nicht so weit, 
deshalb überlasse ich das mal den anderen dir hier weiter zu helfen.

Hast du das Datenblatt mal gelesen? Da sind gar nicht viele Befehle.
Bei Dallas gibt es ne Lib, aber ich glaube Peter Danegger hat da wohl 
was besseres geschrieben.
Ist schon fast zwei Jahre her, seit ich mich damit auseinander gesetzt 
habe. Für meine Fritzbox brauchte ich noch mal einen, das habe ich dann 
aber mit Arduino gemacht. Da ist das alles Pipifax, weil alles im Grunde 
fertig ist.

von Roland .. (rowland)


Lesenswert?

Björn Hiekel schrieb:
> snprintf(temp_po_str, sizeof(temp_po_str-1), "12.5");
>
> anstatt der float Variablen temp_po habe ich jetzt mal "12.5" eingefügt.
>
> Ergebnis = Mist

Du hast nun die float-Variable 'temp_po' durch eine Zeichenkette ersetzt 
"12.5". Wenn musst Du 12.5 übergeben, ohne "".

von Praktikant (Gast)


Lesenswert?

Versuch es mit


msg=dtostrf(temp_po,3,1,buf));

Geht aber nur, wenn der temp_po wirklich ein floa ist

von Praktikant (Gast)


Lesenswert?

Wenn das zutrifft


Pete K. schrieb:
> Laut library ist der Rückgabewert vom Typ unsigned char temp_po_str[8]
> und muss nicht weiter konvertiert werden.

Dann musst du schreiben
1
msg=ds1820_read_temp(DS1820_pin_po);
Irre ich mich, oder muss msg nicht vorher noch irgendwie die anzahl der 
Felder bekommen? z.B.: msg[10]

von Praktikant (Gast)


Lesenswert?

Björn Hiekel schrieb:
> Was meinst du mit Ausgabe an RS232 debuggen?

Er meint, dass du dir die Variblen über die serielle Schnittstelle 
anschauen sollst.

Terminalprogramm öffnen. Mit deinem µC verbinden und der soll dir dann 
über die RS232 die Variableninhalte an das Terminalprogramm senden

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

F. Fo schrieb:
> Hä? Das ist One-Wire, da kannst du so viele dran hängen wie du willst.

Die Lib ist so konzipiert, dass sie nur ein Gerät am Bus unterstützt.
Für mehrere Geräte, müssen halt mehrere Busse (Pins) verwendet wrden.
Das ist alles.

von Karl K. (leluno)


Lesenswert?

du scheinst Anfänger zu sein. deswegen vergiss float.  werDein Ansatz, 
die Kommas wegzulassen, ist zur Vereinfachung richtig.

der ds1820 liefert dir einen 16bit Wert temp. dieser muss in einen 
Integerwert umgesetzt werden:
1
//CelsiusTemp=((temp&0b1111000000000000) | (temp>>4) )*10  + (temp << 12) / 6553 ;
2
if(gbi(temp,15)){//negativ
3
CelsiusTemp=((temp & 0xf000) | (temp>>4) )*10-
4
(10-((temp - (temp & 0xfff0))*10+8)/16);
5
}else{//positiv
6
CelsiusTemp=((temp & 0xf000) | (temp>>4) )*10+((temp - (temp & 0xfff0))*10+8)/16;
7
}

dieser Integerwert muss für dein Lcd aufbereitet werden. Einen 
Integerwert zerlegt man zur Anzeige auf dem Lcd in einzelne Ziffern, die 
dann als char auf dem Lcd dargestellt werden. Dafür gibt es fertige 
Funktionen. Als Anfänger sollte man sich darüber keinen Kopf machen. Die 
Funktion findest du in der lib, aus der du deine lcd-Ansteuerung 
genommen hast.

von Björn H. (firefunk)


Lesenswert?

Ich habe das ganze jetzt so gelöst und es wird mir auch was angezeigt 
nur leider nicht meine Zimmer Temperatur. Es werden in etwa - 51C° 
angezeigt und bei Erwärmung steigt es auch. k. A. woran es liegt... 
vielleicht habe ich doch den falschen Sensor. Wie kann ich das 
herausfinden bzw. wo könnte ich in meinem Code einen Testwert eintragen? 
z.B. 1111 1111 1111 1000 für -0.5C°

Grüße Björn

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "i2cmaster.h"
#include <stdio.h>
#include <stdlib.h>
#include "ds18x20lib.h"
#include "delay.h"

#define SLAVE_ADDRESS1  0xa0

void Display_1(char cmd, char data) //Funktion für Datenübermittlung an 
Display 1
{
  i2c_start(SLAVE_ADDRESS1 | I2C_WRITE);
  i2c_write(cmd);
  i2c_write(data);
  i2c_stop();
}

void WriteStr_D_1(char *s) // Funktion bei längeren Zeichenketten als 
vier Buchstaben (Laufschrift)
{
  char i;
  for (i = 0; i < 4; i++)
  Display_1(0x20 | i, s[i]);
}

void START_DISPLAY (char i) //Funktion Display Start
{
  i2c_init();
  i2c_start(SLAVE_ADDRESS1 | I2C_WRITE) != 0;
  i2c_stop();

  Display_1(0x01, 0xFF);   // Intensität 10
  Display_1(0x02, 0xFF);   // Intensität 32
  Display_1(0x03, 0x01);   // scan limit
  Display_1(0x04, 0x01);   // kein shutdown
  Display_1(0x07, 0x01);   // display test mode on

  _delay_ms(4000);       // 4 Sekunden Displaytest

  Display_1(0x07, 0x00);   // display test mode off

  _delay_ms(200);      // 200m Sekunden warten

  for (i = 0x60; i < 0x64; i++)
  Display_1(i, 0);      // schreibe D0, D1
}


void main(void)        //Main
{_delay_ms (4000);

    unsigned char i;
  unsigned char temp_S1_LUFT_Str[8];
  float temp_S1_LUFT;

  START_DISPLAYS(i);

while(1)
{
  ds1820_init(DS1820_pin_po);   //Initialize DS1820 Sensor 1 Luft

        temp_S1_LUFT = ds1820_read_temp(DS1820_pin_po); //temperature 
from
        Sensor 1 Luft(float)

  char WERT_Temp_Luft[8];

  dtostrf(temp_S1_LUFT,3,1,WERT_Temp_Luft);  //Float zu ASCII

  _delay_ms(5000);

  WriteStr_D_1(WERT_Temp_Luft);    // schreibe vier Zeichen
  _delay_ms(250);

}
  return 0;
  }

von leluno (Gast)


Lesenswert?

Björn Hiekel schrieb:
> = ds1820_read_temp(DS1820_pin_po); //temperature

Der DS1820 liefert dir einen 16bit Integer-Wert. Was willst du da mit 
float?

temp_S1_LUFT muss ein 16bit integer sein.

lass es dir direkt anzeigen, rechne es in binär um -calc.exe-, vergleich 
es mit dem Manual,  dann weißt du ob dein Sensor richtig arbeitet. 
Danach kommt die Umrechnung in Celsius.

von Praktikant (Gast)


Lesenswert?

@Leluna
Die *.lib liefert ihm einen float Wert. Ergo macht er schon alles 
richtig


Björn Hiekel schrieb:
> Hallo zusammen,
>
> ich verwende eine DS18B20 Lib von Stefan Sicklinger Link:
> http://www.sicklinger.com/en/atmel-avr-atmega-ds18x20-library-in-c.html

Klick auf den Link und staune. Unter Punkt 4 steht:

"Der Rückgabewert von ds1820_read_temp(uint8_t DS1820_pin) ist float."


@ Björn:

Initialisiere mal die Variable 'WERT_Temp_Luft' als int und nicht als 
char.
Bei mir funzt das nämlich nur mit int.

von Björn H. (firefunk)


Lesenswert?

Guten Morgen zusammen,

also wie bereits erläutert, bekomme ich einen float Wert.

@Praktikant:
Ich habe die Initialisierung jetzt auf Int umgestellt nur ändert sich 
leider nichts. Jetzt zeigt es mir -70C° an. Ich habe einfach mal den 
Temperatursensor DS18S20 anstatt DS18B20 bestellt. Es steht zwar 
geschrieben, dass die lib für DS18x20 ist - also für beide aber in der 
lib selber lese ich immer nur DS18s20.

Hätte man mit sicherheit ganz einfach umprogrammieren können, aber wie 
gesagt ich bin froh das es überhaupt schon mal was anzeigt. ;-)

Ich melde mich wieder mit dem neuen Sensor in der Hand.

Danke!

von leluno (Gast)


Lesenswert?

hast du die Umrechnung auf Celsius:
//CelsiusTemp=
CelsiusTemp=
((temp & 0xf000) | (temp>>4) )*10+((temp - (temp & 0xfff0))*10+8)/16;

??

von Björn H. (firefunk)


Lesenswert?

leluno schrieb:
> hast du die Umrechnung auf Celsius:
> //CelsiusTemp=
> CelsiusTemp=
> ((temp & 0xf000) | (temp>>4) )*10+((temp - (temp & 0xfff0))*10+8)/16;
>
> ??

Meinst du das so?
1
if(gbi(temp_S1_Luft,15))
2
{//negativ
3
temp_S1_Luft1=((temp_S1_Luft & 0xf000) | (temp_S1_Luft>>4) )*10-
4
(10-((temp_S1_Luft - (temp_S1_Luft & 0xfff0))*10+8)/16);
5
}
6
else
7
{//positiv
8
temp_S1_Luft1=((temp_S1_Luft & 0xf000) | (temp_S1_Luft>>4) )*10+((ttemp_S1_Luft - (temp_S1_Luft & 0xfff0))*10+8)/16;
9
}

: Bearbeitet durch User
von Praktikant (Gast)


Lesenswert?

@leluno

Wo soll er denn die Umrechnung einbauen? Die Funktionsbeschreibung sagt 
doch ganz klar, dass die Funktion die Temperatur als float mit einer 
Nachkommastelle zurückgibt.

Das Problem könnte wirklich im falschen Typen begründet liegen.
Laut Datenblatt arbeitet der S-Typ mit 9 Bit Auflösung.
Der B-Typ startet immer mit 12 Bit.

Wenn du den B-Typ mit der Funktion für den S-Typ ausliest, dann ist das 
wohl die Erklärung warum deine Temperaturwerte nicht passen.

von Karl K. (leluno)


Lesenswert?

lass den negativ-Teil erstmal weg.
aus dem Manual ergibt sich die Umrechnung des 16bit Integer-Werts in °C:
die ersten 12bits für den Vorkommawert die letzten 4bits für den 
Nachkommawert

lass den Nachkommawert auch weg.

Die Temperatur in °C ergibt sich dann, indem du deinen Wert
temp_S1_Luft um 4 Stellen nach rechts schiebst:

temp_S1_Luft = temp_S1_Luft>>4

Wenn das funktioniert kümmerst du dich als nächstes um die 
Nachkommastellen und die negativen Werte

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.