Bei dem DS18S20 ( Datenblatt – Beschreibung ) von Dallas/Maxim handelt es sich um ein Baustein der 1-Wire Familie. Der DS18S20 handelt es sich um ein Temperatursensor, welcher mit einer Auflösung von 9 Bit arbeitet. Er kann im Bereich von -55°C bis +125°C eingesetzt werden und liefert hierbei eine Genauigkeit von +/- 0,5°C.
Die Umwandlung einer Temperatur benötigt maximal 750 ms. Eine weitere Besonderheit des DS18S20 ist die Alarmfunktion, welche ich aber noch nicht ausprobiert habe. Für den Anschluss an den PIC benötigt man wirklich nur eine Leitung. Selbstverständlich benötigt der Sensor auch eine Versorgungsspannung. Es gibt die Möglichkeit auch die +5V 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 DS18S20 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 Verwechslungsgefahr 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.
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 DS18S20 anschließen müsst:
Der DS18S20 kann an einen ganz gewöhnlichen I/O Port des PIC angeschlossen werden, da der Bus über einen Pull Widerstand auf 5 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 DS18S20 oder vom Pullup beeinflusst. |
Ansteuerung
Die Routinen vertragen keine Interrupts! Während der Kommunikation mit dem DS18S20 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:
/************************************************ DS18S20 Routinen von Nicolas Meyertoens PIC-Projekte.de ************************************************/ unsigned char DS18S20 [9];
Außerdem ist folgende Headerdatei zu erstellen:
/************************************************ * File: ds1820.h * Project: -- * Author: Nicolas Meyertöns * Version: -- * Web: PIC-Projekte.de * ************************************************/ #ifndef DS1820 #define DS1820 #include /*Makros*/ #define LAT_DQ LATAbits.LA4 #define DQ PORTAbits.RA4 #define TRIS_DQ TRISAbits.TRISA4 /*Taktfrequenz in Hz*/ #define _XTAL_FREQ 4000000 /*Bekannmachen globaler Variablen*/ extern uint8_t DS18S20 [9]; /*Prototypen*/ unsigned char OW_MRI (void); void OW_W_Bit (unsigned char Bit); void OW_W_Byte (unsigned char Byte); unsigned char OW_R_Bit (void); unsigned char OW_R_Byte (void); void OW_S_Rom(void); #endif /* DS1820.H */
Master Reset Impuls (Start)
Jede Kommunikation mit dem DS18S20 beginnt mit einem so genannten Master Reset Impuls. Diese Sequenz wird vom Master des Busses also dem PIC gestartet. Zunächst einmal wird der Bus 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 er wird durch den Pull up Widerstand wieder auf 5V gebracht. Der DS18S20 wartet nun noch eine Zeit von 15-60µs ab um seine Antwort zu geben. Wenn die 15-60µs verstrichen sind zieht der DS18S20 seinerseits den Bus auf Masse (0V) und hält in dort für etwa 60-240µs. In dieser Phase muss der PIC nun den Zustand des Busses einlesen. Ist der Bus jetzt wirklich auf Low weiß er, dass sich mindestens ein Sensor am Bus befindet und er kann weiter arbeiten. 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 und er wird erneut durch den Pull up Widerstand auf 5 Volt angehoben.
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 ------------------- Diese Funktion gibt den MR-Impuls aus und wertet aus, ob sich mind. 1 Slave am 1-Wire-Bus befindet. Rueckgabewert = 1 bedeutet kein Slave 0 bedeutet mind. 1 Slave ************************************************/ unsigned char OW_MRI (void) { unsigned char Erkennung; //Fuer den Rueckgabewert TRIS_DQ=0; //Der DQ-IO ist ein Ausgang __delay_us(490); TRIS_DQ=1; //Der DQ-IO ist ein Eingang (DQ=High (Pull-up)) __delay_us(40); Erkennung=DQ; //Pegel einlesen __delay_us(450); //490µs warten (Ende) return (Erkennung); //Erkennungsbit zurueck geben }
Skip Rom (alle Sensoren ansprechen)
Ich habe weiter oben bereits erwähnt, dass in diesem Tutorial nur die Ansteuerung mit einem DS18S20 am Bus erläutert wird. Daher ist es nicht erforderlich die Adresse des DS18S20 auszulesen. Wir können statt dessen einfach jeden Sensor am Bus ansprechen und jeder bedeutet in unserem Fall den einen, welchen wir angeschlossen haben. Dafür gibt es den Skip Rom Befehl. Nachdem wir diesen Befehl gesendet haben, werden sich alle Sensoren am Bus angesprochen fühlen und werden daher alle auf den nachfolgenden Befehl ansprechen. Nützlich ist dies wenn mehrere Sensoren am Bus sind und sie möchten eine Temperaturabfrage aller Sensoren durchführen. So benötigen sie lediglich einmal die Befehlsfolgen für das Ausführen einer Temperaturmessung/Umwandlung anzuweisen und im nach hinein alle Sensoren nacheinander auszulesen. Aber zurück zu unserem Fall. Wir haben nun durch den Master Reset Impuls (MRI) deutlich gemacht, dass etwas auf dem Bus passieren soll, die Sensoren warten 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 angesprochen.
OW_S_Rom(); // Alle 1-Wire-Slaves ansprechen // Auf den nun gesendeten Befehl reagieren alle Slaves // d.h. alle Slaves beginnen jetzt gleichzeitig mit der // Temperaturmessung: (habe nur 1 angeschlossen)
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 er weiß was er tun soll. Nachfolgend aufgelistet welche Befehle der DS18S20 interpretieren kann:
Befehl | Beschreibung | Code |
---|---|---|
Convert T | Leitet die Temperaturmessung ein | Hex: 0x44 |
Read Scratchpad | Liest das Scratchpad inklusive des CRC Bytes aus | Hex: 0xBE |
Write Scratchpad | Schreibt Daten in das Scratchpad (Byte 2 und 3 <-> TH und TL) | Hex: 0x4E |
Copy Scratchpad | Kopiert TH und TL aus dem EEPROM zum Scratchpad | Hex: 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 DS18S20 kommunizieren können brauchen wir Funktionen zum Senden und Empfangen von Informationen zu und von dem Sensor. Hier sind folgende Funktionen in C aufgeführt:
- 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 PIC den Bus auf Low setzt (Start of Slot). Nach Ablauf von mindestens 1µs und höchstens(!) 15µs:
- Zieht der PIC das Potential wieder auf 5V, wenn er eine 1 senden möchte.
- Lässt der PIC das Potential auf 0V, wenn er eine 0 senden möchte.
Diesen Zustand hält der PIC nun für weitere 60-120µs bei (Ende des Slots). Die Kommunikation von einem Bit ist abgeschlossen. Wenn weitere Bits übertragen werden sollen muss der PIC mindestens 1µs warten bis er erneut mit einer Übertragung startet (Start of Slot).
Empfangen eines Bit
Der Master (PIC) startet indem er den Datenbus für mindestens 480 µs auf 0V zieht (MRI). Im Anschluss gibt er den Bus wieder frei (das TRIS Bit wird auf 1 gesetzt der Portpin ist hochohmig und Pullup/DS18S20 bestimmen über das Potential). Nach einer Wartezeit von 15-60 µs wird der DS18S20 den Bus übernehmen; Je nachdem ob er eine 1 oder 0 an den PIC sendet, wird der Bus das entsprechende Potential zu diesem Zeitpunkt aufweisen, welches vom PIC nun eingelesen werden kann. Der Slave (DS18S20) wird diesen Zustand nun für etwa 6-240 µs halten und den Bus seinerseits wieder frei geben. Jetzt muss noch die Zeit von 480µs (beginnend ab der steigenden Flanke nach dem MRI) ist der gesamte Vorgang abgeschlossen.
Senden und Empfangen eines Byte
Das ist jetzt verglichen sehr einfach. Hierfür wird nun einfach 8 mal in Folge die Funktionen für das Senden/Empfangen eines Bits aufgerufen.
Hier aufgeführt die einzelnen Funktionen:
/************************************************ One_Wire_Write_Bit ------------------- Diese Funktion überträgt 1 Bit (schreibend) ************************************************/ void OW_W_Bit (unsigned char Bit) { TRIS_DQ=0; //Der DQ-IO ist ein Ausgang if(Bit) //Wenn das zu übertragende Bit eine 1 ist, { //dann die DQ Leitung sofort wieder auf high ziehen TRIS_DQ=1; } Delay100TCYx(12); //100µs warten (Ende) TRIS_DQ=1; //Den DQ(IO) wieder auf Eingang und somit //die DQ Leitung auf High (Pull-up) } /************************************************ One_Wire_Write_Byte ------------------- Diese Funktion überträgt 1 Byte (schreibend) ************************************************/ void OW_W_Byte (unsigned char Byte) { unsigned char i; unsigned char Maske=1; //Ein Byte übertragen und mit dem LSB anfangen for (i=0;i<8;i++) { if (Byte & Maske) OW_W_Bit(1); else OW_W_Bit(0); Maske=Maske*2; } } /************************************************ One_Wire_Read_Bit ------------------- Diese Funktion überträgt 1 Bit (lesend) ************************************************/ unsigned char OW_R_Bit (void) { unsigned char Erkennung; unsigned char i; TRIS_DQ=0; TRIS_DQ = 1; // DQ sofort wieder High Delay10TCYx(18); // 15µs warten Erkennung = DQ; // DQ einlesen u. speichern Delay10TCYx(126); // noch 105 us warten // bis Ende Time Slot return(Erkennung); // Rückgabe von DQ } /************************************************ One_Wire_Read_Byte ------------------- Diese Funktion überträgt 1 Byte (lesend) ************************************************/ unsigned char OW_R_Byte (void) { unsigned char Wert; unsigned char i; // 8 Bits hintereinander einlesen, LSB zuerst for(i=0; i<8; i++) { if (OW_R_Bit()) Wert |=0x01 << i; } return(Wert); // Rückgabe von DQ }
Convert T (Temperaturmessung)
Nachdem wir nun also alle Vorkehrungen getroffen haben um dem DS18S20 nun endlich 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 750ms dauern kann. Diese Zeit muss dem Sensor gewährt werden. Sprich vorher kann der Sensor nicht ausgelesen werden!!
OW_W_Byte(0x44); // Temperaturmessung ausführen
Jetzt müsst Ihr mindestens 750 ms warten! Der DS18S20 benötigt diese Zeit um die Umwandlung durchzuführen. Im Anschluss kann das Scratchpad (also das Ergebnis) ausgelesen werden.
Auslesen des Ergebnisses
Nachdem die 750ms vergangen sind kann das Ergebnis der Temperaturmessung/Umwandlung aus dem Scratchpad ausgelesen werden. Nicht vergessen vor dem Ansprechen des DS18S20 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 DS18S20 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 war’s! 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.4
Sehr geehrtes PIC-Projekte Team,
Danke für das Grundgerüst! Jedoch fehlt mir noch die “Main” Funktion im Programm. Ich habe einen DS18s20 Temperatursensor. Ich müsste die Temperatur auf einem Display ausgeben. Brauchen Sie noch weitere Informationen?
lg. Killian Preh
Hallo Killian,
wenn Du den Artikel und/oder das PDF aufmerksam gelesen hast, dann weißt Du bereits wie die Kommunikation aufgebaut werden muss. Die Situation vereinfacht sich, wenn sich nur ein Sensor am Bus befindet (was zu Beginn zwangsweise so sein muss).
Um nun mit diesem Sensor Kontakt aufzunehmen wird als erstes ein Master-Reset-Impuls ausgelöst. Wenn der Rückgabewert der Funktion ‘0’ ist, dann weißt Du, dass sich mindestens ein Slave am Bus befindet und Du kannst fortfahren. Wenn jedoch eine ‘1’ zurück kommt, dann ist irgendwas im Aufbau schief gelaufen.
Wie gesagt, wir gehen davon aus, dass sich nur ein Sensor am Bus befindet, daher brauchen wir keine Ansprache via Adresse durchzuführen, sondern können mit dem Skip-ROM-Befehl “alle” Sensoren am Bus ansprechen (in unserem Fall also der eine, der angeschlossen ist).
Jetzt wird als nächstes der soeben angesprochene Sensor zur Temperaturmessung aufgefordert, indem wir den Befehl Convert T an den Sensor schicken (0x44).
Wichtig: Jetzt musst Du mindestens 750 ms warten, bis Du die Temperatur auslesen kannst… Wenn die 750 ms vorüber sind, wird der Sensor mit dem Befehl ‘0xBE’ aufgefordert das Messergebnis auf den Bus auszugeben. Das Auslesen des Messergebnisses erfolgt dann in einer for-Schleife (siehe Artikel).
So jetzt hast Du die Rohdaten schon mal im Controller und musst sie “nur” noch verarbeiten. Ich habe in diesem Artikel noch ein zusätzliches PDF verlinkt, in dem auch beschrieben wird, wie man die Daten letztendlich auswertet (ist relativ einfach).
PS: Ich werde mal zusehen in naher Zukunft eine Art “Beispiel-Main” hier im Artikel mit aufzunehmen, hoffe aber, dass es jetzt evtl. schon etwas klarer geworden ist.
PPS: Hier kannst Du auch noch mal reinschauen 😉
Viele Grüße, Nico