Bei dem DS18x20 ( Datenblatt DS18S20 / Datenblatt DS18B20 / Beschreibung [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 Scratchpad zum EEPROM. | 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
Moin Nico,
macht der Befehl “Copy Scratchpad” nicht genau den umgekehrten Vorgang wie du Ihn beschrieben hast? Also er kopiert TH und TL aus dem Scratchpad zum EEPROM.
Korrigiere mich, wenn ich falsch liege.
Und wenn ich schon beim schreiben bin: Ich versuche das ganze ein wenig OldSchool auf einer 7-Seg-Anzeige wiederzugeben. Hast du einen Ansatz wie ich das realisieren kann?
Trotzdem super Seite. Danke.
L.V.B.
Moin,
ne, die Beschreibung passt schon so 🙂 Wirf mal einen Blick in das Datenblatt, da findest du die Beschreibung auch nochmal.
Bzgl deines Vorhabens: Am besten du meldest dich mal im Forum. Da ist das besser aufgehoben.
Viele Grüße
Nico
So, ich muss mich korrigieren. Du hast völlig Recht. Ich habe es selbst beim nochmaligen Lesen verdreht.
Ich habe die Beschreibung bereits korrigiert, danke für den Hinweis!
Hallo, mit den Hinweisen von Nico funktioniert es jetzt. Weis nur nicht was vorher genau der Fehler war.
Weil ein “Main()” für die Funktionen hier gewünscht wurde hier meine Version, die LCD Ansteuerung ist allerdings natürlich individuell, aber der Rest sollte passen:
“`c
/*******************************************************************************
* File: ds18b20_ready.c
* Keine Interrups => ausschalten !
* nach https://pic-projekte.de/blog/ds18s20/ from Nico
*
******************************************************************************/
#include
#include “main.h”
//Befehle
#define Convert_T 0x44 //Leitet die Temperaturmessung ein
#define Read_scratchpad 0xBE //Liest das Scratchpad inklusive des CRC Bytes aus
#define Write_scratchpad 0x4E //Schreibt 3 Byte in das Scratchpad (Byte1 -> TH, Byte2 -> TL, Byte3 Config)
#define Copy_scratchpad 0x48 //Kopiert TH und TL aus dem EEPROM zum Scratchpad
//#define Recall_E 0xB8 //Startet einen Rückruf von TH und TL vom EEPROM zum Scratchpad
//#define Read_Power_Supply 0xB4 //Signalisiert den Versorgungszustand zum PIC
#define Resolution_11bit 0x5F //9bit 375ms wait!
#define Resolution_12bit 0x7F //12bit 750ms wait! Config-Reg. Bit 6,5 = 11 s. Figure 10 https://www.maximintegrated.com/en/ds/DS18B20.pdf
#define Skip_ROM 0xCC //Alle Sensoren am Bus ansprechen
#define Read_ROM 0x33
#define Match_ROM 0x55
#define Alarm_Search 0xEC
#define DI PORTBbits.RB4 //PIC Eingang!
#define LAT_DQ LATBbits.LATB4 //PIC Ausgang!
#define TRIS_DQ TRISB4
volatile uint8_t tempL, tempH;
volatile float tempC = 0; // declare a variable to store
uint8_t ow_mri(void); //Reset
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);
/*******************************************************************************
* DS18B20 FUNCTION *
*******************************************************************************/
int ds18b20(void)
{
uns16 w_counter = 0;
PEIE = 0; //0 für Timer INT aus
GIE = 0; //alle INT aus
lcd_1602_clear();
lcd_1602_string(“* DS18B0: *”); //LCD display for the starting part
while(w_counter 0
{
/*
ow_wr_byte(Write_scratchpad);
ow_wr_byte(0); //TH Reg.
ow_wr_byte(0); //TL reg.
ow_wr_byte(Resolution_11bit); // Auflösung = 12bit Standard
//Reset for Temp.
ow_mri();
*/
ow_wr_byte(Skip_ROM);
ow_wr_byte(Convert_T);
//_delay_ms(375 ); //warten auf Temp. auslesen, 11bit
_delay_ms(750 ); //warten auf Temp. auslesen, 12bit
//Temp auslesen über Scratchpad
ow_mri(); //Master Reset Impuls
ow_wr_byte(Skip_ROM);
ow_wr_byte(Read_scratchpad);
tempL = ow_rd_byte(); //read low temp value
tempH = ow_rd_byte(); //read high temp value
//Testwerte
// tempH = 0xFF; //-10,1°C
// tempL = 0x5E;
// tempH = 0x01;
// tempL = 0x91; //+25,1°C
//Anzeigen
lcd_1602_setcursor(2, 0);
lcd_1602_hex(tempH);
lcd_1602_hex(tempL);
lcd_1602_string(“h “);
_delay_ms(1000);
tempC = ((uns16)tempH << 8) + (uns16)tempL; //put both value in one variable
uns16 t, t2 = 0;
if((tempH & 0x80) != 0) //negative Temp.
{
//2er Kompliment umrechnen
t = tempH; // Store tempH value in t = 1111 1111 .
t <>= 4; // t = 0000 0000 0000 1010.
t = t * 100; // t = 10 * 100 = 1000.
t2 = tempL; //Store tempL value = 0101 1110.
t2 = t2 – 1; // t2= 0101 1101
t2 = ~t2; //t2 = 1010 0010
t2 = t2 & 0x0f; // t2 = 1010 0010 | 0000 1111 = 0000 0010
t2 = (uns16)(t2 * 6.25); // 0000 00010 = 2 x 6.25 = 12.50
tempC = ((unsigned int)t) + (unsigned int)t2; //put both value in one variable 1000 + 12.5 = 1012.5
}
else //pos. Temp
{
//12bit LSB je °C = 0.0625, 11bit = 0.125 mit nur 375ms Conversion Times
tempC = (uns16)(tempC * 6.25); ////calculations used from the table provided in the data sheet of ds18b20
}
//Anzeigen
lcd_1602_setcursor(2, 0);
lcd_1602_bcd(1, w_counter);
lcd_1602_string(“.Temp:”);
if(tempH & 0x80)
lcd_1602_string(“-“);
else
lcd_1602_string(“+”);
//
tempC /= 10;
//lcd_float(tempC);
lcd_1602_bcddez((uns16)tempC); //234 => 23.4°C
lcd_1602_string(” “);
lcd_1602_data(DEF_GRAD); //”°”
lcd_1602_string(“C”);
} //Reset
w_counter++;
}
}
“`
Freut mich, dass es jetzt klappt 🙂
Hallo Nico,
die Reihenfolge ist für mich nur logisch falsch, es funktioniert natürlich auch so, das weiß ich schon. Eigentlich setzt man ja aber erst den Ausgangtyp (TRIS) und dann den Wert. Auch das man durch das DQ gleich als Eingang schalten den Ausgang hier beim 18B20 wegen der 5k auf 1 setzt, ohne den Ausgang mit 1 extra zu setzen, habe ich schon soweit verstanden.
Ich kämpfe aber seit Tagen damit, das zum laufen zu bringen und es tut einfach nicht. Noch nicht einmal eine Temp. erhalten, nur entweder `FFFFh` wenn was nicht tut oder `0550h`. Im Datenblatt habe ich auch die 750ms (nicht µs!) wegen der 12bit inzwischen in der Tabelle gefunden, da hat der andere Schreiber Unrecht. Kommt einen aber erstmal sehr lang vor. Ich bekomme immer nur die `0550h` vom 18B20, also 80°C was einfach aber Zimmertemp. mit um die FE60h sein müsste. Auch im Datenblatt stehen die `0550h` als Vorgabewert bei “DS18B20 MEMORY MAP bei byte0 und byte1. Warum bekomme ich da nicht einen anderen Wert? Das macht mich wahnsinnig, irgendwas stimmt da nicht, die Schreibe- und Lesefunktionen funktionieren anscheinend, auch das Reset, da ich eine 0 vom Sensor bekomme. Der Pegel bei DQ ist auch okay, bei diversen Breakpoints gemessen. Habe auch bei https://circuitdigest.com/microcontroller-projects/pic16f877a-digital-thermometer-using-ds18b20 alles mit meinen Code verglichen, müsste passen. Von dort auch Anzeige für neg. Werte übernommen und mit den Werten aus Datenblatt von -55 – 80°C simuliert, LCD Ausgabe passt. Auch meine Zeit mit `__delay_us()` und `__delay_ms()` stimmen, Test Blink LED und das Signal auf Oszi sind exakt richtig.
Was kann das noch sein, das ich immer die `0550h` ausgelesen bekomme? Auch mit 3 Sensoren probiert, alle defekt? Danke für einen ev. Tipp.
Steffen
Wo wird nochmal `uint8_t ds18x20[9];` benötigt?
Un die Reihenfolge
“`c
LAT_DQ = 0; // set the (I)O to low level
TRIS_DQ = 0; // config the DQ-IO as output (-> low)
“`
ist u.a. wohl auch falsch.
Bei mir funktioniert jedenfalls nichts. Habe auch 3 versch. Sensoren probiert, um HW Fehler zu meiden und mit Oszi die Signale und Zeiten überprüft.
Gibt es schon eine korrigierte lauffähige Version? Auch wegen der 750ms oder µs? Kann da im Datenblatt leider nichts finden.
Danke
Steffen
Warum sollte die Reihenfolge falsch sein? Verstehst du überhaupt was da gemacht wird? Klar, wenn es bei dir nicht funktioniert (bei anderen übrigens schon), dann muss natürlich der Code und nicht etwa deine eigene Umsetzung das Problem sein …
Steffen ganz im Ernst überdenke doch vielleicht nochmal deine Herangehensweise. So wirst du nicht weit kommen.
Hallo, leider läuft das bei mir überhaupt nicht. Verwende einen PIC18F26K22 und habe auch mit 750ms und mit 750 µs getestet. Aufrufende Funktion so:
“`c
int ds18x20_nico(void)
{
PEIE = 0; //0 für Timer INT aus
GIE = 0; //alle INT aus
if(!ow_mri()) //Master Reset Impuls, 1-wire connected = 0
{
ow_skip_rom(); //OW_S_Rom();
ow_wr_bit(Convert_T);
_delay_us(750); //warten auf Temp. auslesen, µs nicht ms!
ow_mri(); //Master Reset Impuls
ow_wr_byte(Skip_ROM);
ow_wr_byte(Read_scratchpad);
//DS18x20 antwortet mit 9Byte
for(int i = 0; i < 9; i++) // Antwort einlesen: 9 Byte große Scratch Pad-Inhalt einlesen
{
ds18x20[i] = ow_rd_byte();
}
“`
In `ds18x20[]` ist da leider nichts im Debugger MPLAB-X v4.15 zu sehen. Wo soll das sein? Deswegen Umrechnung noch nicht weiter gemacht. Aber wo "Seite 79 unter der Überschrift “Die Umrechnung der Messwerte” ??? Die Links oben verweisen nur auf die Datenblätter und die haben nur 20 und nicht 79 Seiten! Auch die unterschiedliche Schreibweise der Funktionen und des Array ist erst etwas verwirrend. Leider nicht unbedingt sehr sorgfältig erstellt und das lässt halt auch prinzipielle Fehler im Code vermuten, weswegen das so nicht geht.
Ein anderes gefundenes Example für PIC16F877A , was aber auch nicht geht (andere Zeiten?), berechnet so
“`c
//Umrechnung der Messwerte
tempL = read(); //read low temp value
tempH = read(); //read high temp value
Temp = ((uns16)tempH << 8) + (uns16)tempL; //put both value in one variable
Temp = (uns16)((float)Temp * 6.25); //calcuation from the table provided
“`
also irgendwie ganz andere Empfangsdaten. Mit
“`c
unsigned char read()
{
char i, result = 0;
Rx_18B20; // TRIS is input(1)
for (i = 0; i < 8; i++)
{
Tx_18B20; // TRIS is output(0)
PortTx_18B20 = 0; // genarate low pluse for 2us
_delay_us(2);
Rx_18B20; // TRIS is input(1) release the bus
if (PortRx_18B20 != 0)
result |= 1 << i;
_delay_us(60); // wait for recovery time
}
return result;
}
“`
Alles sehr verwirrend. Leider kann ich aus dem Datenblatt auch nichts genaueres deuten. Könnte man nicht Bitte einmal ein komplettes funktionierendes Programm hier ablegen?
Mit Arduino Uno Examples und dazu passender Bibliothek natürlich alles kein Problem, wie üblich.
Hallo Steffen,
zunächst einmal: Es ist keine gute Strategie die (für dich kostenlose Arbeit) anderer auf diese Weise, wie du es tust, zu kritisieren und im selben Atemzug um Hilfe zu bitten.
Warum? Überall (natürlich auch im Datenblatt) ist deutlich ausgewiesen, dass `750` ms für eine Konvertierung benötigt werden. Demzufolge ist diese Zeile schon mal falsch:
“`c
_delay_us(750); //warten auf Temp. auslesen, µs nicht ms!
“`
Ist das eine von dir selber geschriebene Funktion? Die offiziell verfügbaren Bibliotheksfunktionen fangen mit `__` an, nicht mit `_`.
Weiter geht es hier:
“`c
ow_wr_bit(Convert_T);
“`
Das muss dann auch schon `ow_wr_byte` und nicht `ow_wr_bit` sein. Die direkt darauffolgende Zeile mit der falschen Wartezeit habe ich eingangs schon angesprochen. Btw.: Mindestens `750`ms. Sprich, nimm einfach `800`ms, dann bist du hier schon mal auf der sicheren Seite. Verkleinern kannst du diese Zeit dann immer noch, wenn es erstmal funktioniert.
Im ersten Satz des Artikels sind drei PDF’s verlinkt (1. Datenblatt zum DS18S20 2. Datenblatt zum DS18B20 und 3. Ein allg. PDF mit Beschreibung der Algorithmen). Dann habe ich zum Thema Umrechnen der Temperatur geschrieben:
So und nun wirst du es schaffen in einem der drei PDFs die Seite 79 zu finden? Falls nicht, hier der Link.
Meine erstellen Funktionen haben alle samt die identische Schreibweise mit folgendem Präfix `ow_` und nachfolgender Beschreibung der Funktion z.B.: `wr_byte`. Du verwendest in deinem Code hingegen Defines wie `Convert_T` und `Skip_ROM` (Hinweis: Makros werden allg. üblich / guter Programmier-Stil in Uppercase geschrieben. So und du behauptest, dass mein Code unterschiedliche Schreibweise bei Funktionen aufweist? Ja ne ist klar 😉
Desweiteren: Im von mir abgenoteten Sourcecode gibt es ein einziges Array `uint8_t ds18x20 [9]`. Was genau ist daran jetzt “verwirrend”?
Viele Grüße,
Nico
Hallo,
die Wartezeit = 750ms (MILLIsekunden!) – falsche Massbezeichnung! . Muss in MIKROsekunden angegeben werden.
Ansonsten: Ein guter Artikel, verständlich, klar formuliert, hat sogar mir geholfen die DS18S20-Routine in Assembler zu programmieren.
Weiter so! Mit besten Grüssen
Ottmar
Hallo Ottmar,
vielen Dank für deinen Kommentar.
Kannst Du bitte etwas präziser werden? Wo genau soll ein Fehler sein?
Die Zeit, die der Sensor zur Konvertierung benötigt beträgt `750` ms (nicht µs), siehe Auszug aus dem Datenblatt:
Viele Grüße
Nico
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).
Viele Grüße, Nico