Forum: Mikrocontroller und Digitale Elektronik DS18B20 Problem


von georg (Gast)


Lesenswert?

Hallo,

ich weiß, über die DS1820 wurde schon viel geschieben. Auch ich habe ein 
Problem mit der Ansteuerung. Ich verwende einen Mega32 mit externem 4MHZ 
Quarz.

Der DS18B20 hängt an PD6. An PD5 habe ich eine PWM laufen. (macht das 
was?)
Ich möchte einfach nur die Temperatur auslesen.
Ich verwende nicht den Power-Parasite-Mode.

Hier die Funktionen:
1
void bus_o()
2
{
3
  DDRD |= (1<<PD6);
4
}
5
6
void bus_i()
7
{
8
  DDRD &= ~(1<<PD6);
9
}
10
11
void bus_write(uint32_t a)
12
{
13
  char data[20];
14
  itoa(a, data, 2);
15
  char *s;
16
  s=data;
17
18
  while(*s != '\0')
19
  {
20
    if(*s == '1')
21
    {
22
      bus_o();
23
      _delay_us(14);
24
      bus_i();
25
      _delay_us(70);
26
    }
27
28
    if(*s == '0')
29
    {
30
      bus_o();
31
      _delay_us(100);
32
      bus_i();
33
      _delay_us(2);
34
    }
35
36
    s++;
37
38
    _delay_us(2);
39
  }
40
}
41
42
int bus_read(int anz_bits)
43
{
44
  int t;
45
  char T[20];
46
  int i = 0;
47
48
  while(i < anz_bits)
49
  {
50
    bus_o();
51
    _delay_us(1.1);
52
    bus_i();
53
    _delay_us(10);
54
    
55
    if((PIND & 0b01000000) == 0)
56
    {
57
      T[i] = 0;
58
    }
59
60
    if((PIND & 0b01000000) == 1)
61
    {
62
      T[i] = 1;
63
    }
64
65
    while((PIND & 0b01000000) == 0)
66
    {
67
    }
68
69
    _delay_us(2);
70
71
    i++;
72
  }
73
74
  t = atoi(T);
75
76
  return t;
77
}
78
79
void temperature_get()
80
{
81
  //this function reads the temperature from the DS1820
82
83
  bus_i();
84
85
  //init...
86
  _delay_ms(1);
87
  bus_o();
88
  _delay_us(480);
89
  bus_i();
90
  _delay_ms(1);
91
92
  bus_write(0xCC);   //Skip-ROM, da ich nur einen 1-wire-device habe...
93
  _delay_ms(1);
94
  bus_write(0x44);  //Convert T
95
  _delay_ms(1);
96
  
97
  temperature = bus_read(9);
98
}

Die Funktion "temperature_get()" wird alle 3 sec. aufgerufen. Die 
Variabel "temperature" ist eine globale int.
Leider bleibt der Wert von "temperature" immer bei 0
Was mache ich falsch?

Gruß

georg

von holger (Gast)


Lesenswert?

>      T[i] = 0;
>      T[i] = 1;

0 ist nicht gleich '0'
1 ist nicht gleich '1'

>  t = atoi(T);

atoi macht aus "101" den Wert 101 und nicht 5.
Und itoa ist nicht für 32 bit Variablen geeignet.

von georg (Gast)


Lesenswert?

Hallo,

ich habe das Programm nochmals neu überarbeitet und das kam dabei raus:
1
void bus_o()
2
{
3
  DDRD |= (1<<PD6);
4
}
5
6
void bus_i()
7
{
8
  DDRD &= ~(1<<PD6);
9
}
10
11
void write_bit(int b)
12
{
13
  if(b == 1)
14
  {
15
    bus_o();
16
    _delay_us(3);
17
    bus_i();
18
    _delay_us(110);
19
  }
20
21
  if(b == 0)
22
  {
23
    bus_o();
24
    _delay_us(110);
25
    bus_i();
26
  }
27
28
  _delay_us(2);
29
}
30
31
double read_bit()
32
{
33
  double b;
34
35
  bus_o();
36
  _delay_us(2);
37
  bus_i();
38
  _delay_us(10);
39
40
  b = (PIND & 0b01000000);
41
42
  _delay_us(110);
43
44
  return b;
45
}
46
47
void bus_write(uint32_t a, int anz_bits)
48
{
49
  int maske = 1;
50
  int i = 0;
51
52
  while(i != anz_bits)
53
  {
54
    write_bit(a & maske);
55
    maske = maske * 2;
56
    i++;
57
  }
58
}
59
60
int bus_read(int anz_bits)
61
{
62
  int i = 1;
63
  double t = 0;
64
  double x = 1;
65
66
  while(i != anz_bits)
67
  {
68
    t = t + (read_bit() * x);
69
    i++;
70
    x = x * 2;
71
  }
72
73
  return t;
74
}
75
76
void temperature_get()
77
{
78
  //this function reads the temperature from the DS18B20
79
  bus_i();
80
81
  //init...
82
  _delay_ms(1);
83
  bus_o();
84
  _delay_us(490);
85
  bus_i();
86
87
  bus_write(0xCC, 8); //skip ROM
88
  bus_write(0x44, 7); //T Convert
89
  
90
  temperature = bus_read(16);
91
}

Jeodch erhalte ich immer 192 als Temperatur zurück... Was mache ich 
falsch?
Kann man überhaupt die _delay_us() verwenden oder ist das zu ungenau?

Gruß

georg

von Peter D. (peda)


Lesenswert?

georg schrieb:
> double read_bit()

Du traust der CPU wohl nicht, also speicherst Du ein einzelnes Bit in 
einem 64bit-Float Wert.


4MHz ist schon recht knapp, da sollte man besser nur uint8_t als 
Variablen nehmen für den Hardwarezugriff.

Und extra Funktionen fürs Bitsetzen könnte auch zu teuer werden.
Entweder Inline oder als Macro.


Peter

von georg (Gast)


Lesenswert?

Hallo,

Danke für den Hinweis!

ok, jetzt habe ich noch was verändert:
1
void write_bit(int b)
2
{
3
  if(b == 1)
4
  {
5
    DDRD |= (1<<PD6);
6
    _delay_us(3);
7
    DDRD &= ~(1<<PD6);
8
    _delay_us(110);
9
  }
10
11
  if(b == 0)
12
  {
13
    DDRD |= (1<<PD6);
14
    _delay_us(110);
15
    DDRD &= ~(1<<PD6);
16
  }
17
18
  _delay_us(2);
19
}
20
21
uint8_t read_bit()
22
{
23
  uint8_t b;
24
25
  DDRD |= (1<<PD6);
26
  _delay_us(2);
27
  DDRD &= ~(1<<PD6);
28
  _delay_us(10);
29
30
  b = (PIND & 0b01000000);
31
32
  _delay_us(110);
33
34
  return b;
35
}
36
37
void bus_write(uint32_t a, int anz_bits)
38
{
39
  int maske = 1;
40
  int i = 0;
41
42
  while(i != anz_bits)
43
  {
44
    write_bit(a & maske);
45
    maske = maske * 2;
46
    i++;
47
  }
48
}
49
50
int bus_read(int anz_bits)
51
{
52
  int i = 1;
53
  int t = 0;
54
  int x = 1;
55
56
  while(i != anz_bits)
57
  {
58
    t = t + (read_bit() * x);
59
    i++;
60
    x = x * 2;
61
  }
62
63
  return t;
64
}
65
66
void reset_bus()
67
{
68
  //init...
69
  _delay_ms(1);
70
  DDRD |= (1<<PD6);
71
  _delay_us(490);
72
  DDRD &= ~(1<<PD6);
73
}
74
75
void temperature_get()
76
{
77
  //this function reads the temperature from the DS18B20
78
  DDRD &= ~(1<<PD6);
79
  
80
  reset_bus();
81
  bus_write(0xCC, 8);
82
  bus_write(0x44, 7);
83
  _delay_ms(10);
84
  reset_bus();
85
  bus_write(0xCC, 8);
86
  bus_write(0xBE,8);
87
  
88
  temperature = bus_read(16);
89
90
  lcd_ausgabe(a);
91
}

Aber leider kommt weiterhin nur 192 als Temperatur zurück. Was mache ich 
denn sonst noch falsch? Ist wo ein Timing-Problem?

georg

von Sascha W. (sascha-w)


Lesenswert?

die Konvertierung dauert max 750ms - solange solltest du nach ConvT 
mind. warten.

Sascha

von georg (Gast)


Lesenswert?

Hallo,

Danke für den Hinweis, aber ich warte doch sogar 10ms nach 0x44!

habe ich sonst noch Fehler im Code?

Gruß
georg

von (prx) A. K. (prx)


Lesenswert?

georg schrieb:

> Danke für den Hinweis, aber ich warte doch sogar 10ms nach 0x44!

Und 10ms sind bekanntlich viel länger als 750ms.

von georg (Gast)


Lesenswert?

oh, mann, ich dachte grad 750us
ok, ich warte jetzt 4 * 200ms... geht aber trotzdem nicht :-(
Was nun???

georg

von (prx) A. K. (prx)


Lesenswert?

Nach dem Reset solltest du etwas grosszügiger sein und den Sensor nicht 
dabei stören, seine Präsenz bekanntzugeben.

von georg (Gast)


Lesenswert?

Hallo,

ok, danke für diesen Hinweis! Habe nun am Ende der reset_bus() - 
Funktion _delay_ms(1);

Es geht aber immer noch nicht. Was denn nun??? Ich komme einfach nicht 
drauf :-(

georg

von (prx) A. K. (prx)


Lesenswert?

Dein read_bit gibt für 0 zwar 0 zurück, aber für 1 nicht 1.

von georg (Gast)


Lesenswert?

Hallo,

ok, jetzt habe ich die read_bit Funktion so umgeändert:
1
uint8_t read_bit()
2
{
3
  uint8_t b;
4
5
  DDRD |= (1<<PD6);
6
  _delay_us(2);
7
  DDRD &= ~(1<<PD6);
8
  _delay_us(10);
9
10
  if((PIND & 0b01000000) == 0)
11
  b = 0;
12
  else
13
  b = 1;
14
15
  _delay_us(110);
16
17
  return b;
18
}

Jetzt erhalte ich aber als Temperatur immer 255 °C! Was nun?

georg

von georg (Gast)


Lesenswert?

Liegt das vielleicht daran, weil ich den DS18B20 habe?

georg

von (prx) A. K. (prx)


Lesenswert?

Dein write_bit kriegt für 0 zwar 0, aber für 1 nicht 1.

von georg (Gast)


Lesenswert?

Hallo,

ok, habe mein write_bit jetzt so umgeändert:
1
void write_bit(uint8_t b)
2
{
3
  if(b == 0)
4
  {
5
    DDRD |= (1<<PD6);
6
    _delay_us(120);
7
    DDRD &= ~(1<<PD6);
8
  }
9
  else
10
  {
11
    DDRD |= (1<<PD6);
12
    _delay_us(2);
13
    DDRD &= ~(1<<PD6);
14
    _delay_us(120);
15
  }
16
17
  _delay_us(2);
18
}

Aber es geht immernoch nicht... was nun? :-(

georg

von (prx) A. K. (prx)


Lesenswert?

bus_write(0x44, 7);

von georg (Gast)


Lesenswert?

Hallo,

jetzt habe ich immer eine Temperatur von 336, außer, wenn ich die Masse 
vom DS18B20 abklemme, dann habe ich eine Temperatur von 511...

Woran liegt das???

:-(

georg

von (prx) A. K. (prx)


Lesenswert?

Und was stört dich an den 336? Wie warm ist es denn bei dir?

von georg (Gast)


Lesenswert?

Hallo,

jetzt geht er!!! (jetzt ändert sich der Wert, wenn ich den DS18B20 
erwärme, aber die Werte stimmen nicht.)

Zuvor bei den Werten mit 336 z.B. blieb das konstant.

Seit ich bus_write(0x44, 7); in bus_write(0x44, 8); umgeändert habe, 
geht er... wieso das, frage ich mich???

Naja, mit "er geht" meine ich, dass ich endlich was auslesen kann. 
Jedoch zeigt er z.B. 168 an. Muss mal mit einem Termomenter vergleichen, 
aber ich glaube, das kommt nicht ganz hin.

was hat es denn beim DS18B20 mit der "THERMOMETER RESOLUTION 
CONFIGURATION" auf sich????

-georg

Danke für die Hilfe!

von (prx) A. K. (prx)


Lesenswert?

georg schrieb:

> Naja, mit "er geht" meine ich, dass ich endlich was auslesen kann.
> Jedoch zeigt er z.B. 168 an. Muss mal mit einem Termomenter vergleichen,
> aber ich glaube, das kommt nicht ganz hin.

Ab und zu mal eine Nacht mit 168 wär jetzt nicht übel, aber auf Dauer 
doch etwas zu frisch für Juli. Die 336 gefielen mir besser (als 
Ergebnis).

> was hat es denn beim DS18B20 mit der "THERMOMETER RESOLUTION
> CONFIGURATION" auf sich????

Für den Anfang erstmal garnix. Kannst damit zwischen langsam/genau und 
schnell/ungenau wählen.

von (prx) A. K. (prx)


Lesenswert?

PS: Ohne durchgeführte Messung muss nach dem Einschalten 0x550 kommen. 
Wenn nicht, dann ist immer noch was falsch.

von georg (Gast)


Lesenswert?

Hallo,

ah, ok, danke, aber wie bekomme ich da jetzt die korrekte Temperatur 
hin?
meine bus_read Funktion sieht jetzt so aus:
1
uint32_t bus_read(uint32_t anz_bits)
2
{
3
  uint16_t i = 1;
4
  uint16_t t = 0;
5
  uint8_t x = 1;
6
7
  while(i != anz_bits)
8
  {
9
    t = t + (read_bit() * x);
10
    i++;
11
    x = x * 2;
12
  }
13
14
  return t;
15
}

liegt da der Fehler?

georg

von georg (Gast)


Lesenswert?

ok, ohne Messung kommt bei mir leider 80, also 0x50... Was nun???

georg

von (prx) A. K. (prx)


Lesenswert?

Die obige Version von bus_read gefiel mir besser. Das war glaube ich die 
einzige Funktion ohne Fehler ;-). Ein Zähler der 4 Mrd Bits lesen kann, 
aber für's Ergebnis nur 8 zulässt - nö.

von (prx) A. K. (prx)


Lesenswert?

georg schrieb:

> ok, ohne Messung kommt bei mir leider 80, also 0x50... Was nun???

Perfekt. Jetzt musst du nur bus_read wieder vom Kopf auf die Füsse 
stellen.

von georg (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ok, wenn ich die bus_read Funktion so habe:
1
int bus_read(int anz_bits)
2
{
3
  int i = 1;
4
  int t = 0;
5
  int x = 1;
6
7
  while(i != anz_bits)
8
  {
9
    t = t + (read_bit() * x);
10
    i++;
11
    x = x * 2;
12
  }
13
14
  return t;
15
}
Dann kommt 1360, also 0x550. Als Temperatur zeigt er aber leider z.B. 
bei Raumtemperatur 433 an... Muss ich den das noch durch 16 teilen, weil 
im Datenblatt die Tabelle 2: (im Anhang...)

georg

von (prx) A. K. (prx)


Lesenswert?

georg schrieb:

> bei Raumtemperatur 433 an... Muss ich den das noch durch 16 teilen, weil

Yep, du musst.

von georg (Gast)


Lesenswert?

Cool, danke!

Jetzt zeigt er auch 26°C an!!! und mein analog-Tchibo Thermometer 
auch!!!
und, wenn ich den Finger drann halte, dann geht er auf ca. 30!!!

Scheint also zu gehen!! freu Und danke nochmals für die tolle Hilfe!

Eine Frage habe ich aber noch: Ich habe jetzt ja einen DS18 B 20 
drann. Darum muss ich auch die Temperatur noch durch 16 teilen. Wie ist 
das aber, wenn ich einen DS18 S 20 drann hab??? Durch 2????

georg

von (prx) A. K. (prx)


Lesenswert?

georg schrieb:

> das aber, wenn ich einen DS18 S 20 drann hab??? Durch 2????

Richtig.

von georg (Gast)


Lesenswert?

ok, dann wars das - vielen Dank nochmals!

Gruß
georg17

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.