www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik DS18B20 Problem


Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void bus_o()
{
  DDRD |= (1<<PD6);
}

void bus_i()
{
  DDRD &= ~(1<<PD6);
}

void bus_write(uint32_t a)
{
  char data[20];
  itoa(a, data, 2);
  char *s;
  s=data;

  while(*s != '\0')
  {
    if(*s == '1')
    {
      bus_o();
      _delay_us(14);
      bus_i();
      _delay_us(70);
    }

    if(*s == '0')
    {
      bus_o();
      _delay_us(100);
      bus_i();
      _delay_us(2);
    }

    s++;

    _delay_us(2);
  }
}

int bus_read(int anz_bits)
{
  int t;
  char T[20];
  int i = 0;

  while(i < anz_bits)
  {
    bus_o();
    _delay_us(1.1);
    bus_i();
    _delay_us(10);
    
    if((PIND & 0b01000000) == 0)
    {
      T[i] = 0;
    }

    if((PIND & 0b01000000) == 1)
    {
      T[i] = 1;
    }

    while((PIND & 0b01000000) == 0)
    {
    }

    _delay_us(2);

    i++;
  }

  t = atoi(T);

  return t;
}

void temperature_get()
{
  //this function reads the temperature from the DS1820

  bus_i();

  //init...
  _delay_ms(1);
  bus_o();
  _delay_us(480);
  bus_i();
  _delay_ms(1);

  bus_write(0xCC);   //Skip-ROM, da ich nur einen 1-wire-device habe...
  _delay_ms(1);
  bus_write(0x44);  //Convert T
  _delay_ms(1);
  
  temperature = bus_read(9);
}

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

Autor: holger (Gast)
Datum:

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

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe das Programm nochmals neu überarbeitet und das kam dabei raus:
void bus_o()
{
  DDRD |= (1<<PD6);
}

void bus_i()
{
  DDRD &= ~(1<<PD6);
}

void write_bit(int b)
{
  if(b == 1)
  {
    bus_o();
    _delay_us(3);
    bus_i();
    _delay_us(110);
  }

  if(b == 0)
  {
    bus_o();
    _delay_us(110);
    bus_i();
  }

  _delay_us(2);
}

double read_bit()
{
  double b;

  bus_o();
  _delay_us(2);
  bus_i();
  _delay_us(10);

  b = (PIND & 0b01000000);

  _delay_us(110);

  return b;
}

void bus_write(uint32_t a, int anz_bits)
{
  int maske = 1;
  int i = 0;

  while(i != anz_bits)
  {
    write_bit(a & maske);
    maske = maske * 2;
    i++;
  }
}

int bus_read(int anz_bits)
{
  int i = 1;
  double t = 0;
  double x = 1;

  while(i != anz_bits)
  {
    t = t + (read_bit() * x);
    i++;
    x = x * 2;
  }

  return t;
}

void temperature_get()
{
  //this function reads the temperature from the DS18B20
  bus_i();

  //init...
  _delay_ms(1);
  bus_o();
  _delay_us(490);
  bus_i();

  bus_write(0xCC, 8); //skip ROM
  bus_write(0x44, 7); //T Convert
  
  temperature = bus_read(16);
}

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Danke für den Hinweis!

ok, jetzt habe ich noch was verändert:
void write_bit(int b)
{
  if(b == 1)
  {
    DDRD |= (1<<PD6);
    _delay_us(3);
    DDRD &= ~(1<<PD6);
    _delay_us(110);
  }

  if(b == 0)
  {
    DDRD |= (1<<PD6);
    _delay_us(110);
    DDRD &= ~(1<<PD6);
  }

  _delay_us(2);
}

uint8_t read_bit()
{
  uint8_t b;

  DDRD |= (1<<PD6);
  _delay_us(2);
  DDRD &= ~(1<<PD6);
  _delay_us(10);

  b = (PIND & 0b01000000);

  _delay_us(110);

  return b;
}

void bus_write(uint32_t a, int anz_bits)
{
  int maske = 1;
  int i = 0;

  while(i != anz_bits)
  {
    write_bit(a & maske);
    maske = maske * 2;
    i++;
  }
}

int bus_read(int anz_bits)
{
  int i = 1;
  int t = 0;
  int x = 1;

  while(i != anz_bits)
  {
    t = t + (read_bit() * x);
    i++;
    x = x * 2;
  }

  return t;
}

void reset_bus()
{
  //init...
  _delay_ms(1);
  DDRD |= (1<<PD6);
  _delay_us(490);
  DDRD &= ~(1<<PD6);
}

void temperature_get()
{
  //this function reads the temperature from the DS18B20
  DDRD &= ~(1<<PD6);
  
  reset_bus();
  bus_write(0xCC, 8);
  bus_write(0x44, 7);
  _delay_ms(10);
  reset_bus();
  bus_write(0xCC, 8);
  bus_write(0xBE,8);
  
  temperature = bus_read(16);

  lcd_ausgabe(a);
}

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

georg

Autor: Sascha Weber (sascha-w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die Konvertierung dauert max 750ms - solange solltest du nach ConvT 
mind. warten.

Sascha

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

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

habe ich sonst noch Fehler im Code?

Gruß
georg

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:

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

georg

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:

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

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ok, jetzt habe ich die read_bit Funktion so umgeändert:
uint8_t read_bit()
{
  uint8_t b;

  DDRD |= (1<<PD6);
  _delay_us(2);
  DDRD &= ~(1<<PD6);
  _delay_us(10);

  if((PIND & 0b01000000) == 0)
  b = 0;
  else
  b = 1;

  _delay_us(110);

  return b;
}

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

georg

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Liegt das vielleicht daran, weil ich den DS18B20 habe?

georg

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ok, habe mein write_bit jetzt so umgeändert:
void write_bit(uint8_t b)
{
  if(b == 0)
  {
    DDRD |= (1<<PD6);
    _delay_us(120);
    DDRD &= ~(1<<PD6);
  }
  else
  {
    DDRD |= (1<<PD6);
    _delay_us(2);
    DDRD &= ~(1<<PD6);
    _delay_us(120);
  }

  _delay_us(2);
}

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

georg

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bus_write(0x44, 7);

Autor: georg (Gast)
Datum:

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

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:

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

Autor: A. K. (prx)
Datum:

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

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ah, ok, danke, aber wie bekomme ich da jetzt die korrekte Temperatur 
hin?
meine bus_read Funktion sieht jetzt so aus:
uint32_t bus_read(uint32_t anz_bits)
{
  uint16_t i = 1;
  uint16_t t = 0;
  uint8_t x = 1;

  while(i != anz_bits)
  {
    t = t + (read_bit() * x);
    i++;
    x = x * 2;
  }

  return t;
}

liegt da der Fehler?

georg

Autor: georg (Gast)
Datum:

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

georg

Autor: A. K. (prx)
Datum:

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

Autor: A. K. (prx)
Datum:

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

Autor: georg (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ok, wenn ich die bus_read Funktion so habe:
int bus_read(int anz_bits)
{
  int i = 1;
  int t = 0;
  int x = 1;

  while(i != anz_bits)
  {
    t = t + (read_bit() * x);
    i++;
    x = x * 2;
  }

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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
georg schrieb:

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

Yep, du musst.

Autor: georg (Gast)
Datum:

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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
georg schrieb:

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

Richtig.

Autor: georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, dann wars das - vielen Dank nochmals!

Gruß
georg17

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.