Bei dem DS18x20  ( Datenblatt DS18S20 / Datenblatt DS18B20Beschreibung [PDF] ) von Dallas/Maxim handelt es sich um ein Baustein der 1-Wire Familie. Der DS18x20 ist ein einfach anzusprechender Temperatursensor, der mit einer Auflösung von 12 bzw. 9 Bit arbeitet. Er kann im Bereich von -55 °C bis +125 °C eingesetzt werden und liefert hierbei eine Genauigkeit / maximalen Fehler von +/- 0,5 °C. Die Umwandlung einer Temperatur benötigt maximal 750 ms. Eine weitere Besonderheit des DS18x20 ist die Alarmfunktion, welche ich aber noch nicht ausprobiert habe. Für den Anschluss an den PIC benötigt man lediglich eine Datenleitung (IO eines Controllers). Selbstverständlich benötigt der Sensor auch eine Versorgungsspannung. Es gibt die Möglichkeit auch die 5 V bzw. 3,3 V Verbindung wegzulassen indem man den Sensor über die selbe Leitung versorgt, über welche man mit ihm kommuniziert. Dieser Mode heißt: Parasitärer Modus. Als Anfänger ist hiervon allerdings abzuraten. In jedem Fall müsst ihr einen I/O Pin des Mikrocontrollers einplanen. Der größte Vorteil des DS18x20 ist aber, dass man beliebig viele Sensoren an einen Bus legen kann, da die Sensoren jeweils eine einmalige 64 Bit lange Adresse haben wodurch sie eine Verwechslung ausschließen lässt. Ich beschreibe hier allerdings vorerst nur wie man arbeitet, wenn ein einzelner Sensor am Bus angeschlossen ist. Das ist für den Einstieg einfacher. Wenn ihr weitere Sensoren an eurem Bus betreiben möchtet habt ihr dann schon mal das Prinzip verstanden und könnt selbstständig weiter arbeiten.

Unterschied zwischen DS18S20 und DS18B20

Es gibt zwei verschiedene Versionen des hier beschriebenen 1-Wire Sensors. Diese unterscheiden sich rein optisch lediglich durch einen Buchstaben in der Produktbezeichnung. Es gibt des DS18S20 und den DS18B20. Der einzige Unterschied zwischen den beiden Varianten ist die Auflösung des Messwertes, den ihr aus dem Sensor auslesen könnt:

• DS18S20 --> 9 bit Auflösung  
• DS18B20 --> 12 bit Auflösung (wahlweise 9 bit)

Die Routinen, die ich in diesem Artikel vorstelle, sind für beide Varianten nutzbar. Man muss lediglich beim Auswerten der Daten aufpassen. Je nachdem von welchem Typen die Messdaten stammen, kann sich die Umrechnung des Temperaturwertes leicht unterscheiden. Hierzu möchte ich auf das oben verlinkte PDF (siehe “Beschreibung”) verweisen.

Schaltplan / Anschluss an den PIC

Nun, bei nur einer Datenleitung ist das Anschließen an den PIC nicht sonderlich kompliziert. Hier seht ihr, wie ihr den DS18x20 anschließen müsst:

Der DS18x20 kann an einen ganz gewöhnlichen I/O Port des PIC angeschlossen werden, da der Bus über einen Pull Widerstand auf 5 oder 3,3 Volt / High Zustand gezogen wird. Der Portpin an dem der Bus angeschlossen ist wird als Ausgang (TRIS Bit 0) geschaltet und das entsprechende Zustandsbit wird auf 0 gesetzt. Somit zieht der PIC das Potential am Bus auf Masse. Wenn der PIC den Bus wieder freigeben soll wird einfach der Portpin als Eingang geschaltet (TRIS Bit 1). Der Portpin ist nun hochohmig und der Zustand wird entweder vom DS18x20 oder vom Pullup beeinflusst.

Ansteuerung

Die Routinen vertragen keine Interrupts! Während der Kommunikation mit dem DS18x20 müsst Ihr alle Interrupts verbieten. Tut Ihr das nicht, kann es zu Fehlern bei der Kommunikation führen. Folgendes Array wird für die aufgeführten Routinen benötigt:

uint8_t ds18x20[9];

Außerdem ist folgende Headerdatei zu erstellen:

#ifndef DS18X20_H
#define DS18X20_H

#include <stdint.h>

/*** define *******************************************************************/

#define LAT_DQ          LATAbits.LA7
#define DQ              PORTAbits.RA7
#define TRIS_DQ         TRISAbits.TRISA7

/*** extern *******************************************************************/

extern uint8_t ds18x20 [9];

/*** prototypes ***************************************************************/

uint8_t ow_mri (void);
uint8_t ow_rd_bit (void);
uint8_t ow_rd_byte (void);
void ow_wr_bit (uint8_t val);
void ow_wr_byte (uint8_t val);
void ow_skip_rom (void);

#endif

Master Reset Impuls (Start)

Jede Kommunikation mit dem DS18x20 beginnt mit einem so genannten Master Reset Impuls. Diese Sequenz wird vom Master des Busses also dem PIC gestartet. Zunächst einmal wird der Pegel des Busses durch den Mikrocontroller für eine Dauer von mindestens 480 µs auf Low gezogen. Das ist die Zeitdauer in der der Sensor registriert, dass etwas auf dem Bus passiert und er eventuell angesprochen wird. Nach dieser Zeit lässt der PIC den Bus wieder los und wird durch den angeschlossenen Pull-up Widerstand wieder auf High gezogen. Der DS18x20 wartet nun noch eine Zeit von 15-60 µs ab um seine Antwort zu geben. Wenn die 15-60 µs verstrichen sind, zieht der DS18x20 seinerseits den Bus auf Low und hält ihn dort für etwa 60-240 µs. In dieser Phase muss der PIC nun den Zustand des Busses einlesen. Ist der Bus jetzt auf Low weiß er, dass sich mindestens ein Sensor am Bus befindet. Ist der eingelesene Zustand hingegen High, so ist kein Sensor angeschlossen. Ihr merkt schon die Timimgs sind nicht sonderlich kritisch 🙂 Wenn die 60-240 µs vorbei sind lässt der Sensor den Bus wieder los, so dass er erneut durch den Pull-up Widerstand auf High angehoben wird.

Hier ist das Verhalten des Master Reset Impulses noch einmal grafisch zusammen gefasst:

Die gängige Routine für einen Master Reset Impuls mit dem PIC18F4550:

/*******************************************************************************
One_Wire_Master-Reset-Impuls
--------------------------------------------------------------------------------
This function will release the master reset impuls and checks if there is at
least one 1-wire-component connected to the bus (0) or not (1).
*******************************************************************************/

uint8_t ow_mri (void)
{
    uint8_t rec;

    LAT_DQ = 0;             // set the (I)O to low level
    TRIS_DQ = 0;            // config the DQ-IO as output (-> low)
    __delay_us(490);        // delay of >480 us
    TRIS_DQ = 1;            // config the  DQ-IO as input (high-z -> pull up)
    __delay_us(40);
    rec = DQ;               // read the level (if low, slave available)
    __delay_us(450);        // wait for end of slot

    return (rec);
}

Skip Rom (alle Sensoren ansprechen)

Ich habe weiter oben bereits erwähnt, dass in diesem Tutorial nur die Ansteuerung mit einem (1x) DS18x20 am Bus beschrieben wird. Daher ist es nicht erforderlich die Adresse des DS18x20 auszulesen. Wir können statt dessen einfach “jeden” Sensor am Bus ansprechen. Dafür gibt es den Skip Rom Befehl. Nachdem wir diesen Befehl gesendet haben, werden sich alle Sensoren (in unserem Fall nur der eine angeschlossene) am Bus angesprochen fühlen und werden daher alle auf den nachfolgenden Befehl ansprechen. Nützlich ist dies wenn sich mehrere Sensoren am Bus befinden und eine Temperaturabfrage aller Sensoren durchgeführt werden soll. So  wird lediglich einmal die Befehlsfolge für das Ausführen einer Temperaturmessung/Umwandlung nötig. Im Anschluss müssen dann natürlich  alle Sensoren nacheinander ausgelesen werden. Aber zurück zu unserem Spezialfall: Wir haben nun durch den Master Reset Impuls (MRI) deutlich gemacht, dass etwas auf dem Bus passieren soll. Unser Sensor wartet nun darauf, dass eine Adresse oder eben der Skip Rom Befehl gesendet wird. Wir senden den Skip Rom Befehl aus und unser einzelner Sensor am Bus fühlt sich in Folge dessen angesprochen.

OW_S_Rom();		// simply calls all slaves instead of an specific address call

Befehle

Nachdem wir den Bus gestartet (MRI) und “den” Sensor angesprochen haben (Skip Rom), müssen wir nun einen Befehl an den Sensor senden, damit der angesprochene Sensor weiß was er tun soll. Nachfolgend ist aufgelistet, welche Befehle der DS18x20 interpretieren kann:

Befehl Beschreibung Code
Convert T Leitet die Temperaturmessung ein 0x44
Read Scratchpad Liest das Scratchpad inklusive des CRC Bytes aus 0xBE
Write Scratchpad Schreibt Daten in das Scratchpad (Byte 2 und 3 <-> TH und TL) 0x4E
Copy Scratchpad Kopiert TH und TL aus dem EEPROM zum Scratchpad 0x48
Recall E Startet einen Rückruf von TH und TL vom EEPROM zum Scratchpad 0xB8
Read Power Supply Signalisiert den Versorgungszustand zum PIC 0xB4

Senden und Empfangen

Damit wir mit dem DS18x20 kommunizieren können brauchen wir Funktionen zum Senden und Empfangen von Informationen zu und von dem Sensor. Wir werden die folgenden grundlegenden Funktionen besprechen:

  • Senden eines Bit
  • Empfangen eines Bit
  • Senden eines Byte
  • Empfangen eines Byte

Zunächst eine Grafik, welche veranschaulichen soll wie die Kommunikation mit dem Sensor funktioniert:

Senden eines Bit

Es beginnt damit, dass der Controller den Bus auf Low zieht (Start of Slot). Nach Ablauf von mindestens 1 µs und höchstens (!) 15 µs …

  • zieht der Controller das Potential wieder auf High, wenn er eine 1 senden möchte oder
  • lässt der PIC das Potential auf 0V, wenn er eine 0 senden möchte.

Den jeweiligen Zustand hält der Controller nun für weitere 60-120 µs bei (Ende des Slots). Die Übertragung von einem einzelnen Bit ist damit abgeschlossen. Wenn weitere Bits übertragen werden sollen muss der Controller im Anschluss mindestens 1 µs warten bis er erneut mit einer Übertragung eines neuen Bits startet (Start of Slot).

Empfangen eines Bit

Genau wie beim Senden eines Bit, beginnt auch beim Empfangen eines Bit der Master mit dem Start of Slot: Der Master zieht den Bus auf Low und hält diesen Pegel für etwa 1 µs. Im Anschluss gibt der Master den Bus wieder frei. Jetzt kommt der Sensor ins Spiel. Je nachdem ob er eine 1 oder 0 senden möchte, zieht er ebenfalls den Pegel des Busses auf Low (für eine 0) oder er lässt den Pegel über den Pull-up Widerstand auf High ziehen. Nachdem der Master also den Start of Slot eingeleitet und im Anschluss den Bus wieder freigegeben hat, kann er dann nach etwa 15 µs den Pegel auf dem Bus einlesen und somit das vom Sensor gesendete Bit empfangen. Der gesamte “Master read slot” ist nach eine Gesamtzeit (ab Start of Slot) von min. 60 bis max. 120 µs abgeschlossen. Nun gilt wie beim Schreiben eines Bits, dass mindestens 1 µs gewartet werden muss, bevor der nächste Start of Slot folgt.

Senden und Empfangen eines Byte

Das Senden/Empfangen von Bytes ist nun vergleichsweise einfach. Wir können nun einfach acht mal in Folge die Funktionen für das Senden/Empfangen eines einzelnen Bits ausführen 😉 Hier aufgeführt die einzelnen Funktionen:

/*******************************************************************************
 One_Wire_Write_Bit
 -------------------------------------------------------------------------------
 This function will write one single bit on the bus.
 *******************************************************************************/

void ow_wr_bit (uint8_t val)
{
    LAT_DQ = 0;            // set the (I)O to low level
    TRIS_DQ = 0;           // config the DQ-IO as output (-> low)

    if(val)                // if the bit to transfer is a "1"
    {
        __delay_us(1);     // wait 1 us and..
        TRIS_DQ = 1;       // ..config the DQ-IO as input (high-z -> pull up)
    }

    __delay_us(100);       // wait for end of slot
    TRIS_DQ = 1;           // config the DQ-IO as input (high-z -> pull up)
 }

/*******************************************************************************
 One_Wire_Write_Byte
 -------------------------------------------------------------------------------
 This function will write a complete byte on the bus.
 *******************************************************************************/

void ow_wr_byte (uint8_t val)
{
    uint8_t i, mask = 1;

    // write the byte by sending eight bits (LSB first)
    for (i=0; i<8; i++)
    {
        ow_wr_bit(val & mask);
        mask = (mask << 1);
    }
}

/*******************************************************************************
 One_Wire_Read_Bit
 -------------------------------------------------------------------------------
 This function will read one single bit from the bus.
 *******************************************************************************/

uint8_t ow_rd_bit (void)
{
    uint8_t rec;           // perform a very short low impuls

    TRIS_DQ = 0;           // config the DQ-IO as output (-> low)
    TRIS_DQ = 1;           // config the DQ-IO as input (high-z -> pull up)
    __delay_us(15);
    rec = DQ;              // read the level on DQ (this is the read bit)
    __delay_us(105);       // wait for end of slot

    return(rec);
}

/*******************************************************************************
 One_Wire_Read_Byte
 --------------------------------------------------------------------------------
 This function will read a complete byte from the bus.
 *******************************************************************************/

uint8_t ow_rd_byte (void)
{
    uint8_t value = 0 , i;

    // read the byte by reading eight bits (LSB first)
    for(i=0; i<8; i++)
    {
        if ( ow_rd_bit() )
        {
            value |= 0x01 << i;
        }
    }

    return(value);
}

Convert T (Temperaturmessung)

Nachdem wir nun also alle Vorkehrungen getroffen haben um dem DS18x20 einen Befehl senden zu können, sagen wir ihm, dass er eine Temperaturmessung bzw. eine Umwandlung vornehmen soll. Dazu wird der Convert T (0x44) Befehl benutzt. Jetzt muss beachtet werden, dass die Umwandlung der Temperatur bis zu 750 ms dauern kann. Diese Zeit muss dem Sensor gewährt werden – Der Sensor darf vorher ausgelesen werden!

OW_W_Byte(0x44);	// Temperaturmessung ausführen

Jetzt müsst Ihr mindestens 750 ms warten! Der DS18x20 benötigt diese Zeit um die Umwandlung durchzuführen. Im Anschluss kann das Scratchpad (also das Ergebnis) ausgelesen werden.

Auslesen des Ergebnisses

Nachdem die 750 ms vergangen sind, kann das Ergebnis der Temperaturmessung/Umwandlung aus dem Scratchpad ausgelesen werden. Nicht vergessen vor dem Ansprechen des DS18x20 muss zunächst wieder der MRI und der Skip Rom Befehl ausgeführt werden.

OW_W_Byte(0xBE);	// Befehl für Auslesen des Ergebnisses

Der DS18x20 antwortet nun mit einer 9 Byte großen Antwort am dem Bus welche wir wie folgt einlesen:

for (i=0; i<9; i++)	// Antwort einlesen: 9 Byte große Scratch Pad-Inhalt einlesen
{
    DS18S20[i] = OW_R_Byte();
}

Umrechnen der Temperatur

Schaut hierfür einfach in das PDF Dokument, welches ganz oben auf dieser Seite verlinkt ist, auf der Seite 79 unter der Überschrift “Die Umrechnung der Messwerte” nach. Da ist beschrieben wie ihr die empfangenen Daten umwandeln könnt. Falls ihr dabei Probleme habt, könnt ihr euch im Forum melden und um Hilfe bitten.

Warteschleifen

Die Wartezeiten für die Einzelnen Routinen müsst ihr selbstverständlich auf euer System anpassen. Wie das funktioniert seht ihr hier. Die Funktionen, wie sie hier zur Verfügung stehen sind für den XC8 Compiler geschrieben. Um die Routinen an euer System anzupassen müsst ihr lediglich das Makro für den Takt anpassen. Das wars! Bitte nicht vergessen: Während der Routinen, darf kein Interrupt aktiv sein!

MCC18 Konvertierung

Damit ihr die Routinen auch mit dem C18 Compiler von Microchip nutzen könnt müsst ihr lediglich die Warteschleifen anpassen, da diese beim C18 anders geschrieben werden als beim XC8. Danach funktionieren die Routinen auch mit dem C18 Compiler.

Download

Die in diesem Artikel beschriebenen Routinen zum Download Version 1.5 vom 10.08.2017

4 Responses

Leave a Comment