Forum: Mikrocontroller und Digitale Elektronik DS18B20 gibt keine Daten her


von Frustrierter (Gast)


Lesenswert?

Liebes Forum,

ich sitze jetzt schon knapp zwei Wochen an dem Problem, dass ich keine 
Daten vom Temperatursensor DS18B20 erhalte.

Hardware-mäßig sollte alles passen (versorgt an Vcc, GND- Verbindung 
vorhanden, und an Datenleitung Pull-Up-Widerstand mit 4,7kOhm).

Am Bus hängt auch nur ein solcher Temp-Sensor!

Den Code habe ich im Internet gefunden, welcher laut anderen Usern auch 
funktionieren sollte. Bei mir jedenfalls leider nicht.

Nach einem Reset-Pulse vom uC antwortet mir der Temp-Sensor mit einem 
Presence-Pulse.
Nachdem ich den Skip-Rom und anschließend den Convert-T Befehl schicke, 
warte ich 750ms.
Danach schicke ich den Skip-Rom mit anschließendem Scratchpad Befehl.
Aber leider schickt mir der Sensor nichts zurück.
Ich weiß echt nicht, was ich falsch mache...

Bitte um Hilfe!

Hier der C-Code:

1
int DS18B20_one_wire_bus(void) {
2
    //unsigned temp;
3
    unsigned short tempL, tempH, th_reg, tl_reg, config, byte_five, byte_six, byte_seven, crc;
4
    unsigned int i = 0; // declare a variable to store 
5
    // ensure all the hardware port in zero initially
6
    
7
8
    while (1) // create an infinite loop
9
    {
10
        if (!reset()) 
11
        {
12
            /* Master is making all DS18B20 on the bus performing simultaneous temperature conversions
13
             * by issuing a Skip ROM command followed by a Convert T command
14
             */
15
            write(0xCC);    //Skip_ROM
16
            write(0x44);   //Convert_T
17
            delay_ms(750);      //t-conversion should be done after 750ms
18
            
19
20
           
21
            /* There is only one Slave on the bus: No need to send the device's
22
             * 64-bit ROM code -> Read Scratchpad command can be send just after
23
             * the Skip ROM command
24
             */
25
            reset();    
26
            write(0xCC);    //Skip_ROM
27
            write(0xBE); //Read_scratchpad                       
28
                
29
            tempL = read();     //read low temp value
30
            tempH = read();     //read high temp value
31
            th_reg = read();    //th register or user byte 1
32
            tl_reg = read();    //tl register or user byte 2
33
            config = read();    //configuration register
34
            byte_five = read(); // reserved (FFh)
35
            byte_six = read();  //reserved 
36
            byte_seven = read(); //reserved (10h)
37
            crc = read();       // CRC
38
            i = ((unsigned int) tempH << 8) + (unsigned int) tempL; //put both value in one variable
39
            i = (float) i * 6.25; //calcuation from the table provided 
40
        }
41
    }
42
    while (1) continue; // infinite loop to prevent PIC from reset if there is no more program  
43
44
    return 0;
45
}
46
47
unsigned char reset() 
48
{
49
    //Initialization Procedure - Reset and Presence Pulse
50
    Tx_one_wire_bus; // Tris = 0 (output)
51
    Port_one_wire_bus = 0; // set pin# to low (0)
52
    delay_us(480); // 1 wire require time delay
53
    Rx_one_wire_bus; // Tris = 1 (input)
54
    delay_us(60); // 1 wire require time delay
55
56
    if (Port_one_wire_bus == 0) // if there is a presence pluse
57
    {
58
        delay_us(480);
59
        return 0; // return 0 ( 1-wire is presence)
60
    } else {
61
        delay_us(480);
62
        return 1; // return 1 ( 1-wire is NOT presence)
63
    }
64
}
65
66
void write(char WRT) 
67
{
68
    //See the "Write Time Slots"-section of the DS18B20-Datasheet for information
69
    char i, Cmd;
70
    Cmd = WRT;
71
    //Rx_one_wire_bus; // set pin# to input (1)
72
73
    for (i = 0; i < 8; i++) 
74
    {
75
        delay_us(10);
76
        if ((Cmd & (1 << i)) != 0) 
77
        {
78
            // write 1
79
            Tx_one_wire_bus; // set pin# to output (0)
80
            Port_one_wire_bus = 0; // set pin# to low (0)
81
            delay_us(1); // 1 wire require time delay
82
            Rx_one_wire_bus; // set pin# to input (release the bus)
83
            delay_us(80); // 1 wire require time delay
84
        } else 
85
        {
86
            //write 0
87
            Tx_one_wire_bus; // set pin# to output (0)
88
            Port_one_wire_bus = 0; // set pin# to low (0)
89
            delay_us(80); // 1 wire require time delay
90
            Rx_one_wire_bus; // set pin# to input (release the bus)
91
        }
92
    }
93
}
94
95
unsigned char read() {
96
    char i, result = 0;
97
    //Rx_one_wire_bus; // TRIS is input(1)
98
    for (i = 0; i < 8; i++) 
99
    {
100
        //delay_us(8);
101
        Tx_one_wire_bus; // TRIS is output(0)
102
        Port_one_wire_bus = 0; // genarate low pluse for 2us
103
        delay_us(2);
104
        Rx_one_wire_bus; // TRIS is input(1) release the bus
105
        Nop();
106
        if (Port_one_wire_bus != 0)
107
            result |= 1 << i;
108
        delay_us(60); // wait for recovery time
109
    }
110
    return result;
111
}

von Frank D. (Firma: Spezialeinheit) (feuerstein7)


Lesenswert?


von Wolfgang (Gast)


Lesenswert?

Frustrierter schrieb:
> ... warte ich 750ms.

Hast du das nachgemessen oder steht das nur so im Programm?
Kennt dein Compiler die tatsächliche Taktfrequenz deines µC?

von Frustrierter (Gast)


Lesenswert?

Fred F. schrieb:
> Vieleicht das hier?
> Beitrag "China Schrott - NPN Transistor als DS18B20 verkauft"

Nein, habe den Sensor bei RS bestellt!!
Außerdem kommt nach einem Reset-Puls vom uC ein Response-Puls vom 
Sensor. Also gehe ich stark davon aus, dass es wirklich ein DS18B20 
ist!!



Wolfgang schrieb:
> Frustrierter schrieb:
>> ... warte ich 750ms.
>
> Hast du das nachgemessen oder steht das nur so im Programm?
> Kennt dein Compiler die tatsächliche Taktfrequenz deines µC?

Das passt. Habe ich nachgemessen!

von Wilhelm M. (wimalopaan)


Lesenswert?

Was liest Du denn vom Bus? Nur 1-en? Also 255 als uint8_t. Wenn ja, 
deutet das daraufhin, dass der Sensor noch busy ist. Check mal die 750ms 
... bzw. schau mal mit nem Oszi was passiert.

von Zeno (Gast)


Lesenswert?

Lies Dir das 
http://pic-projekte.de/wordpress/wp-content/uploads/2015/09/1-Wire-Projekt-V1_3.pdf 
mal durch. Ich habe das als Basis genommen und das hat auch 
funktioniert.

Was mir auffällt sind die von Dir benutzten Datentypen. DEine Variablen 
die die rückgegebenen Bytes des Scratchpad aufnehmen sollen hast Du als
1
unsigned short //(16 Bit)
 definiert. Bytes werden aber eigentlich als
1
unsigned char //(8Bit)
 definiert. Ich schreibe die 9 Byte des Scratchpad in  ein char-Array. 
Für die Temperatur werte ich das das erste Byte aus (entspricht Deinem 
tempL  allerdings als unsigned char definiert). Das zweite Byte gibt nur 
das Vorzeichen aus. Ist Byte 2 0 dann ist es eine positive Temperatur 
und man erhält den Temperaturwert mit folgendem Code:
1
 unsigned char tempL
2
float T = tempL/2.0
Bei negativen Temperaturen ist es etwas aufwändiger. Byte 2 ist dann 1 
und die Temperatur errechnet sich über das 2'er Komplement von Byte 0
1
 float T = -1*(~tempL + 1)/2.0

Ist alles im genannten PDF beschrieben.


Zeno

von eProfi (Gast)


Lesenswert?

Das passt auch nicht zusammen:
unsigned int i = 0; // declare a variable to store

 i = (float) i * 6.25; //calcuation from the table provided

welche Table?            calcuLation


zu den 750ms:  warte halt mal länger, z.B. 1500ms

Ich vermute, die Abfrage des Presence-Pulses funktioniert so nicht:
    if (Port_one_wire_bus == 0) // if there is a presence pluse

Fragst Du den ganzen Port ab oder nur ein Pin / Bit?
Evtl ausmaskieren.



> Aber leider schickt mir der Sensor nichts zurück.
Hast Du das mit dem Oszi kontrolliert?

von eProfi (Gast)


Lesenswert?

nicht nur in der Reset-Abfrage, sondern auch in der read:

if (Port_one_wire_bus != 0)

Wenn da noch andere Bits high sind, ist das immer true.

von eProfi (Gast)


Lesenswert?

Und das gibt eine Shift-Orgie:
        if ((Cmd & (1 << i)) != 0)

Schiebe lieber das Cmd nach jeder Abfrage einmal nach rechts.

Oder verwende das i gleich als Schleifen"zähler":

uint8_t i=1;
do{
  if(Cmd & i){send 1}
  else       {send 0}
  }while(i <<= 1); // nach dem 8. Mal ist i == 0, also false

von Zeno (Gast)


Lesenswert?

eProfi schrieb:
> zu den 750ms:  warte halt mal länger, z.B. 1500ms

Ist nicht nötig. 800ms reichen locker, wenn es denn wirklich 800ms sind

von Zeno (Gast)


Lesenswert?

eProfi schrieb:
> Ich vermute, die Abfrage des Presence-Pulses funktioniert so nicht:
>     if (Port_one_wire_bus == 0) // if there is a presence pluse

So wie es im Gesamtkontext da steht, also mit den 60ms delay davor 
funktioniert das schon. Allerdings sind die 60ms die unterste Grenze. 
Ich würde mindestens 65ms nehmen.

Er soll mal das von mir verlinkte PDF durcharbeiten. Dort ist das 
Signalspiel detailiert beschrieben und wenn man sich daran hält dann 
funktioniert das. Das entscheidente bei 1-Wire ist halt das Timing, 
welches man schon gut einhalten sollte. Das ganze steht und fällt halt 
mit der Güte des Delays. An dieser Stelle schreibt man sich am besten 
selbst etwas.

Ach ja: Während eines kompletten 1-Wire-Zykluses sollten keine Interupts 
aktiv sein.

Zeno

von eProfi (Gast)


Lesenswert?

http://www.microchip.com/forums/m851710.aspx:

// ensure all the hardware port in zero initially
 PORTA=0b00000000; //port a off
 PORTB=0b00000000; //port b off
 TRISA=0b11111111; //a as inputs
 TRISB=0b00000000; //b as outputs

nicht nur den Kommentar (mit Tippfehler in --> is) kopieren,
sondern auch die Befehle danach.
In diesem Fall war es aber lehrreich, denn das hätte den eigentlichen 
Fehler (dass das Bit herausmaskiert werden muss) verdeckt.

Im o.g. Link machen sie das z.B. so:
 if(PORTBbits.RB7==1)

Bitte immer den gesamten Code angeben, es fehlen einige Definitionen.

von Vorn N. (eprofi)


Lesenswert?

> So wie es im Gesamtkontext da steht, also mit den 60ms
> delay davor funktioniert das schon.
60ms --> 60µs
Nein, das funktioniert nicht, da undefiniert ist, wie die anderen 7 Bits 
des Ports stehen.

> Ach ja: Während eines kompletten 1-Wire-Zykluses sollten keine
> Interupts aktiv sein.
Interupts --> Interrupts   Zykluses --> Zyklusses
Nein, das ist nicht nötig. Nur innerhalb eines Bits müssen die Zeiten 
genau eingehalten werden.

Bitte mal alle generell mehr auf korrekte Rechtschreibung achten.
Wenn ich das so lese, wundert mich auch nicht, dass der Code nicht 
funktioniert. Einfach vor dem Posten nochmal konzentriert durchlesen.

von Zeno (Gast)


Lesenswert?

Vorn N. schrieb:
> 60ms --> 60µs

OK das µ habe ich überlesen. Es ist dennoch der untere Grenzwert und man 
sollte aus diesem Grund schon einen etwas höheren Wert wählen.

Vorn N. schrieb:
> Nein, das funktioniert nicht, da undefiniert ist, wie die anderen 7 Bits
> des Ports stehen.

Das funktioniert schon. Du weist doch gar nicht wie er seine Variablen 
deklariert hat, da er dies nicht gepostet hat. Wenn sie so deklariert 
sind, das damit der Pin, also das entsprechende Bit des Ports, direkt 
angesprochen wird dann funktioniert es.

Vorn N. schrieb:
>> Ach ja: Während eines kompletten 1-Wire-Zykluses sollten keine
>> Interupts aktiv sein.
> Interupts --> Interrupts   Zykluses --> Zyklusses

OK Du hast 2 Rechtschreibfehler gefunden, Du darfst sie gern behalten. 
Die Welt wird sich auch mit selbigen weiter drehen.

Vorn N. schrieb:
> Nein, das ist nicht nötig. Nur innerhalb eines Bits müssen die Zeiten
> genau eingehalten werden.

Hää? Zeiten innerhalb eines Bits einhalten? Interrupts kümmern sich 
einen Scheißdreck darum was Du gerade in Deinem Programm machst. Die 
hauen da einfach rein und unterbrechen das laufende Programm - ist ja 
auch Sinn und Zweck eines Interrupt's. Wenn der Interrupt an einer 
zeitkritischen Stelle dazwischen haut, dann war's das. Empfehle Dir 
ebenfalls mal dies 
http://pic-projekte.de/wordpress/wp-content/uploads/2015/09/1-Wire-Projekt-V1_3.pdf 
zu lesen. Zitat aus genannter Quelle:
1
Während der Kommunikation über den 1-Wire-Bus darf der Mikrocontroller durch KEINE INTERRUPTS gestört
2
werden, alle Interrupts müssen also während der Kommunikation disabled sein !
3
Erst nach Beendigung der Kommunikation (eines kompletten Kommunikationszyklusses) sind Interrupts wieder zugelassen !
Ich habe mich daran gehalten und im Gegensatz zum TO funktioniert es bei 
mir, sogar mit mehreren 1-Wire Devices. Bei aktiven Interrupts kommt es 
immer wieder mal zu Fehlern.

Zeno

von Wilhelm M. (wimalopaan)


Lesenswert?

Zeno schrieb:
>
> Hää? Zeiten innerhalb eines Bits einhalten? Interrupts kümmern sich
> einen Scheißdreck darum was Du gerade in Deinem Programm machst. Die
> hauen da einfach rein und unterbrechen das laufende Programm - ist ja
> auch Sinn und Zweck eines Interrupt's. Wenn der Interrupt an einer
> zeitkritischen Stelle dazwischen haut, dann war's das. Empfehle Dir

Gemeint war wohl, dass die 1-bit Sequenz (write oder read) nicht durch 
eine ISR unterbrochen werden darf. Zwischen den Bit-Sequenzen darf 
beliebig viel Zeit verstreichen.

von Zeno (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Zeno schrieb:
>>
>> Hää? Zeiten innerhalb eines Bits einhalten? Interrupts kümmern sich
>> einen Scheißdreck darum was Du gerade in Deinem Programm machst. Die
>> hauen da einfach rein und unterbrechen das laufende Programm - ist ja
>> auch Sinn und Zweck eines Interrupt's. Wenn der Interrupt an einer
>> zeitkritischen Stelle dazwischen haut, dann war's das. Empfehle Dir
>
> Gemeint war wohl, dass die 1-bit Sequenz (write oder read) nicht durch
> eine ISR unterbrochen werden darf. Zwischen den Bit-Sequenzen darf
> beliebig viel Zeit verstreichen.

Die Frage ist halt was man als Bitsequenz definiert. Wenn damit der 
Gesamtzyklus, also vom 1.Masterreset bis zum Auslesen des letzten Bits 
des Scratchpad gemeint ist, dann das richtig.
Zwischen den einzelnen write und read macht das keinen Sinn, weil 
einfach die Zeiten zu knapp sind. Zwischen den Timeslots, also der Zeit 
wo wirklich was passiert liegen ca. 15µs, da macht es keinen Sinn 
irgendwelche Interrupts einzuschalten.
Das einzige Zeitintervall wo Zeit wären evtl. die minimal 750ms 
Wandlerzeit beim DS1820. Ich habe es aber nicht ausprobiert.
Glaube mir es ist in jedem Fall besser die Interrupts während des 
gesamten Zyklusses abzuschalten. Gerade wenn es noch nicht läuft ist das 
die beste Lösung. Wenn es dann mal funktionieren sollte kann man ja 
austesten an welchen Punkten Interrupts zugelassen werden könnten.

Zeno

von Falk B. (falk)


Lesenswert?

@  Zeno (Gast)

>> Gemeint war wohl, dass die 1-bit Sequenz (write oder read) nicht durch
>> eine ISR unterbrochen werden darf. Zwischen den Bit-Sequenzen darf
>> beliebig viel Zeit verstreichen.

Eben.

>Die Frage ist halt was man als Bitsequenz definiert.

Das ist bei OneWire recht eindeutig. Der Schreib- oder Lesevorgang eines 
einzigen Bits.

>>Wenn damit der
>Gesamtzyklus, also vom 1.Masterreset bis zum Auslesen des letzten Bits
>des Scratchpad gemeint ist, dann das richtig.

Nein.

>Zwischen den einzelnen write und read macht das keinen Sinn, weil
>einfach die Zeiten zu knapp sind.

Nö.

> Zwischen den Timeslots, also der Zeit
>wo wirklich was passiert liegen ca. 15µs, da macht es keinen Sinn
>irgendwelche Interrupts einzuschalten.

Falsch. Genau anders herum wird ein Schuh draus. Eben WEIL zwischen dein 
einzelnen Bits beliebig viel zeit liegen darf, MUSS man nahezu die 
Interrupt zwischen den Bits freischalten, damit diese ggf. bedient 
werden können, ohne ewig ausgebremst zu werden.

>Glaube mir es ist in jedem Fall besser die Interrupts während des
>gesamten Zyklusses abzuschalten.

Nö. Damit legt man sich die CPU für mehrere Millisekunden lahm. Für ein 
Trivialprogramm ist das OK, in einer echten Anwendung ist das meist 
fatal.

von Wilhelm M. (wimalopaan)


Lesenswert?

Zeno schrieb:
> Die Frage ist halt was man als Bitsequenz definiert. Wenn damit der
> Gesamtzyklus, also vom 1.Masterreset bis zum Auslesen des letzten Bits
> des Scratchpad gemeint ist, dann das richtig.

Sag ich doch (s.o. 1-Bit-Sequenz)

> Zwischen den einzelnen write und read macht das keinen Sinn, weil
> einfach die Zeiten zu knapp sind.

Du meinst das low zum Initiieren einer 1-Bit-Sequenz und dem 
anschließenden Sample für das read? Ja, hier muss das Timing stimmen. 
Und dies ist eine 1-Bit-Sequenz

> Glaube mir es ist in jedem Fall besser die Interrupts während des
> gesamten Zyklusses abzuschalten. Gerade wenn es noch nicht läuft ist das
> die beste Lösung. Wenn es dann mal funktionieren sollte kann man ja
> austesten an welchen Punkten Interrupts zugelassen werden könnten.

Nee, während des gesamten Zyklus (> 480ms wegen Reset) will / muss ich 
doch noch was anderes machen ...

von Zeno (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Nee, während des gesamten Zyklus (> 480ms wegen Reset) will / muss ich
> doch noch was anderes machen ...

Der Resetimpuls ist 480µs lang. Danach kommen min. 15µs Wartezeit, dann 
sollten die Slaves mit dem Presenseimpuls (max. 240µs) antworten. Dann 
kann es losgehen. Slave wählen (wenn mehrere dran sind), Befehl senden 
(1Byte = 8 Timeslots á 60s = 480µs + ca. 2µs Erholzeit zwischen den 
Bits), wenn's ein Befehl mit Parametern war Parameter senden, Antwort 
der Slaves abwarten und deren gesendete Bytes einlesen.
Beim Einlesen eines Bytes vom Slave bleibt zwischen den einzelnen Bits 
definitiv keine Zeit groß was Anderes zu machen.
Es macht eigentlich nur beim DS1820 während der Converterzeit von min. 
750ms Sinn etwas anderes zu machen, da würde ich mit gehen.

Wenn es auf die Verfügbarkeit des µC's ankommt, dann würde ich das Ganze 
eh nicht mit Software machen, sondern einen Interfacechip, z.B. DS2482 
benutzen. Dem sage ich per I2C was ich will und der macht dann die ganze 
Kommunikation mit den 1-Wire-Slaves.

Ich bin mit dem Abschalten der Interrupts während des 1-Wire-Zugriffs 
bisher gut gefahren und wenn der µC während der Zeit mal nichts macht 
geht bei mir die Welt auch nicht unter zumal die Zugriffe auf den 
1-Wire-Bus bei mir nur minimal nur alle 3 Minuten zur Messwertabfrage 
erfolgen und da kommt es mir auf 750ms Convertertime definitiv nicht an.
Das kann ja in anderen Fällen durchaus anders sein, dann muß ich halt 
eine andere Lösung finden. Dann sollte ich aber schon überlegen ob ich 
es nicht doch besser mit Hardware oder sogar einen 2.µC mache.

Wenn ich wie der TO erst mal was aufsetze, dann versuche ich schon 
Störeinflüsse so gering wie möglich zu halten. Wenn's dann läuft kann 
ich immer noch optimieren oder auch mal mit Interrupts testen. Aber eben 
erst wenn es sich sicher funktioniert, was ja beim TO nicht der Fall zu 
sein scheint.

Zeno

von Wilhelm M. (wimalopaan)


Lesenswert?

Zeno schrieb:

> Beim Einlesen eines Bytes vom Slave bleibt zwischen den einzelnen Bits
> definitiv keine Zeit groß was Anderes zu machen.

Doch, denn man kann jedes Bit mit einer beliebigen Zeit dazwischen 
schreiben/lesen. Und nochmal: nur für die 1-Bit-Sequenz muss das Timing 
ziemlich genau eingehalten werden (inkl. recovery time).

Man kann also den 1-wire auch gut mit variabler Rate bedienen.

von Wolle G. (wolleg)


Lesenswert?

Man könnte auch mittels I2C über einen DS2482 den DS18B20 betreiben. 
Damit braucht man sich nicht um die Einhaltung von Zeiten kümmern (außer 
750ms)

von Zeno (Gast)


Lesenswert?

wolle g. schrieb:
> Man könnte auch mittels I2C über einen DS2482 den DS18B20 betreiben.
> Damit braucht man sich nicht um die Einhaltung von Zeiten kümmern (außer
> 750ms)

Habe ich doch schon gesagt.

von Falk B. (falk)


Lesenswert?

@wolle g. (wolleg)

>Man könnte auch mittels I2C über einen DS2482 den DS18B20 betreiben.
>Damit braucht man sich nicht um die Einhaltung von Zeiten kümmern (außer
>750ms)

Man kann auch mit Fahrradhelm in den Supermarkt gehen . . .

von Peter (Gast)


Lesenswert?

Bin ganz neu im one wire undeill das Protokoll selbst programmieren. An 
deinem Code ist mir aufgefallen das die Low0 60-120us und Low1 1-15us 
nicht passt. Habe ich eben im Datenblatt gesehen. Könnte es damit 
zusammen hängen?

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.