Forum: Compiler & IDEs Mehrere DS18B20 mittels Multiplexer an ATmega32


von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hi!

Zuerst möchte ich allen hier Frohe Weihnachten und schöne Feiertage 
wünschen!


Ich bastle seit längerer Zeit an einem Programm, um max. 16Stück DS18B20 
welche an 2 analog Multiplexer(CD4051BE) hängen, auslesen zu können.


Die analogen Multiplexer besitzen 8 Kanäle und werden über jeweils 3 
Adressleitungen angesprochen.
Die Adressleitungen der beiden Multiplexer hängen parallel.
So ergeben sich 5 benötigte Leitungen bzw. Pins am Controller.


Der momentane Testaufbau:
-------------------------

Der Sensor hängt DIREKT am Controller. Also ohne Multiplexer als 
"Vermittler".

Pin 1: GND

Pin 2: DQ mittles 4k7 auf +5V und an Pin PC6

Pin 3: +5V (keine parasitäre Versorgung)

PC7 hängt mittels 4k7 ohne Sensor auf +5V.


Das Problem:
------------

Es wird definitif fehlerhaft vom Sensor gelesen.
Weder die Temparatur noch das Config-Byte werden richtig gelesen.
Die 9 Byte des Scratchpad´s werden per UART ausgegeben (HTerm) und 
können kontroliert werden.

Ich find einfach keinen Fehler mehr?
Kann es sein, daß die paar Zentimeter ungeschirmter Draht eine 
Kommunikation unmöglich machen?

Ich wäre sehr dankbar, wenn jemand von euch meinen Code anschauen 
könnte, vielleicht findet ja wer doch noch einen Fehler.

Die 2 Versionen der Datenblätter, das App.Note 162 den Code von Peter 
unter anderen hab ich mir schon angeschaut.

Grüsse Rick

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hier ein Bild vom Testaufbau.

von Peter D. (peda)


Lesenswert?

Naja, die CD4000-er sind bei 5V nicht gerade der Renner.
Ich glaub, die haben so etwa 1kOhm, das ist schon heftig.
Die sollte man daher nur wirklich bei 12..18V nehmen.

Bei 5V nimm besser den 74HC4051.


Peter

von Rick M. (rick00)


Lesenswert?

Peter Dannegger wrote:
> Naja, die CD4000-er sind bei 5V nicht gerade der Renner.
> Ich glaub, die haben so etwa 1kOhm, das ist schon heftig.
> Die sollte man daher nur wirklich bei 12..18V nehmen.

lt. Datenblatt 100 bis 500 ohm, aber daß sich der Widerstand bei 
sinkender Betreibsspannung ändert? hab ich nicht gewußt. Danke für den 
Tipp!

>
> Bei 5V nimm besser den 74HC4051.

Ich lese mir das Datenblatt durch.


Aber beim Testaufbau habe ich die Multiplexer vorerst weggelassen, denn 
wenns ohne Multiplexer ned funktioniert, dann mit ihnen schon gar nicht.


Bin mittlerweile mit dem Ding echt kurz vor dem Explodieren.
Gestern in der Nacht, wäre der ganze Krempl fast aus dem Fenster 
geflogen.

Gruß Rick

von Falk B. (falk)


Lesenswert?

@ Erik M. (rick00)

>Aber beim Testaufbau habe ich die Multiplexer vorerst weggelassen, denn
>wenns ohne Multiplexer ned funktioniert, dann mit ihnen schon gar nicht.

Wozu überhaut der MUX? Das ist doch ein 1-Wire Bus.

>Bin mittlerweile mit dem Ding echt kurz vor dem Explodieren.
>Gestern in der Nacht, wäre der ganze Krempl fast aus dem Fenster
>geflogen.

Ich schmeiss die Scheisse ausm Fenster naus!
200 Buls hab isch. BALD! Duuuuuu!

;-)

http://www.jokenet.de/sw_detail.asp?id=2049

MFG
Falk

von Rick M. (rick00)


Lesenswert?

Falk Brunner wrote:
> @ Erik M. (rick00)
>
>>Aber beim Testaufbau habe ich die Multiplexer vorerst weggelassen, denn
>>wenns ohne Multiplexer ned funktioniert, dann mit ihnen schon gar nicht.
>
> Wozu überhaut der MUX? Das ist doch ein 1-Wire Bus.
>
1.) sehr einfache Zuordnung Temperatur <-> Mess-Stelle

2.) Bei Kurzschluß oder Sensordefekt, fällt nur 1 Sensor aus und nicht 
der ganze Bus.

3.) Länge der Zuleitungen addieren sich nicht, da ja immer nur 1 Sensor 
dran hängt (beiläufiger Vorteil)


>>Bin mittlerweile mit dem Ding echt kurz vor dem Explodieren.
>>Gestern in der Nacht, wäre der ganze Krempl fast aus dem Fenster
>>geflogen.
>
> Ich schmeiss die Scheisse ausm Fenster naus!
> 200 Buls hab isch. BALD! Duuuuuu!
>
> ;-)
>
> http://www.jokenet.de/sw_detail.asp?id=2049

jo genau so isches ....ich hau die Scheisse ausn Fenster....ich find 
auch nicht den ON-Knopf...und zurückgebn kaun ih des blede Ding ah nimma 
mehr ;-)

MFG Rick

von Rick M. (rick00)


Lesenswert?

Hi!

Ich verstehe die Funktionen  zum Senden und Empfangen von Peter 
Dannegger einfach nicht. Die sind für mich einfach zu komplex 
verschachtelt.
Ich habe Peters Code getestet und er funktioniert tadellos.
Mein Code hingegen streikt?

Könnte mir jemand sagen, ob ich die Sende- und Empfangsfkt. von Peter in 
meinem Programm richtig interpretiert habe.

Grüsse Rick

von Rick M. (rick00)


Lesenswert?

Hi!

Ich lese immer nur 1sen aus und weiß einfach nicht warum.

meine Fkt. reset_1wire() funktioniert und den Presence Puls empfange ich 
auch.
Wenn es aber darum geht, die Temparatur aus zu lesen, empfange ich immer 
nur für jedes Byte 255???
Ich halt mich genau an die Timings im Datenblatt, aber diese Sensoren 
reden anscheinend nicht mit jeden :-(

Hat jemand vielleicht debugging Tips für mich?

Gruß Rick

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hier das File:

von Jürgen S. (jsachs)


Lesenswert?

Ich bin jetzt nicht der 1wire Experte.
Aber mir fällt auf, das du für das Timing des Reset eine andere Delay 
Funktion nimmst als für die schreib und lese Funktionen (delay_ms() vs. 
delay_us() ). Eventuell liegt hier ja ein Fehler vor ?
- Hast Du mal deine Timings mit einem Osci kontrolliert ?
- lässt dein Multiplexer (leider geht nicht genau hervor ob Du Ihn jetzt 
schon in Betrieb hast) überhaupt den "lesepuls" durch ?

mehr sehe ich auf Anhieb leider auch nicht. Und meine DS18S20 sind nicht 
rechtzeitig zum Fest geliefert worden :-(

Gruss
Juergen

von Rick M. (rick00)


Lesenswert?

Hi Jürgen!

Jürgen Sachs wrote:
> Ich bin jetzt nicht der 1wire Experte.
> Aber mir fällt auf, das du für das Timing des Reset eine andere Delay
> Funktion nimmst als für die schreib und lese Funktionen (delay_ms() vs.
> delay_us() ). Eventuell liegt hier ja ein Fehler vor ?

_delay_us() ist genauer als _delay_ms() weshalb der Fehler, so glaub ich 
hier nicht liegt.
Aber ich werd es probieren.
Mittlerweile bin ich wirklich für jeden Tipp dankbar, denn ich weiß echt 
nicht mehr weiter.
Entweder hab ich ein Compilerproblem, oder ich schau schon zum 1000sten 
Mal über den Fehler drüber.

> - Hast Du mal deine Timings mit einem Osci kontrolliert ?

Oszi, nein.
Ich hab ein altes analoges Oszi, welches ich aber zuerst reparieren 
müsste.

> - lässt dein Multiplexer (leider geht nicht genau hervor ob Du Ihn jetzt
> schon in Betrieb hast) überhaupt den "lesepuls" durch ?

Nein, der Multiplexer liegt noch in der Schublade. Den hol ich erst 
hervor, wenns mit der Direktverbindung klappt.
>
> mehr sehe ich auf Anhieb leider auch nicht. Und meine DS18S20 sind nicht
> rechtzeitig zum Fest geliefert worden :-(

Meine DS18B20 sind zum Glück noch im letzten Augenblick vor Weihnachten 
gekommen.

Gruß Rick

von Rick M. (rick00)


Lesenswert?

Hi!

Also die Delay-Routinen sind es nicht.

Gruß Rick

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hi!

Konnte mein Oszi wieder zusammenflicken :-) ..zum Glück wars nur ne 
Kleinigkeit.

Habe nun folgende Fkt.en gemessen:

1.) reset_1wire();

2.) write_byte_1wire(0x00);

3.) write_byte_1wire(0xFF);

----------------------------------------

ad 1:

gemessen                                        programmiert
------------------------------------------------------------------------ 
---
reset pulse: 500usec                            500usec

DS18B20 waits: 30usec                           65usec warten anschl
                                                 Presence Puls abfragen
Presence Puls: 115usec

Rest: 360 usec                                  435 usec warten
---------------- 
------------------------------
ges.: 1005usec                                 1000usec

Hier ist alles in Ordnung. Hat auch von Anfang an funktioniert.

______________________________________________________________________ 
_

ad 2:

gemessen                                     programmiert
------------------------------------------------------------------------ 
--

68usec low                                  66usec

ca. 5usec bis 7usec high                    1usec recovery time
(starkes Nachleuchten am Oszi)


Hier ergibt sich doch eine relativ große Abweichung? Bei 16Mhz sollte 
das eigentlich schneller gehen.
______________________________________________________________________ 
_

ad 3:

gemessen                                    programmiert
------------------------------------------------------------------------ 
--

5 bis 7usec low                           1usec low

68usec high                               65usec high
                                           1usec recovery time

Hier ergibt sich ebenfalls eine relativ große Abweichung.
Ist aber noch in der Toleranz von 15usec.


Wie ich die Sensorantworten lesen soll, weiß ich nicht. Hat jemand einen 
Tipp?

Anzeige immer noch 0,0°C da ich immer noch nur 1sen lese?

Gruß Rick

von Jürgen S. (jsachs)


Lesenswert?

Erik M. wrote:
>
> Hier ergibt sich ebenfalls eine relativ große Abweichung.
> Ist aber noch in der Toleranz von 15usec.
>

Da würde ich mir mal keine Gedanken machen, mehr Recovery Zeit wirkt 
sich ja nur auf die Datenübertragung aus, macht Sie langsammer. Bei 16 
MHz sind eben nur Max. 16 Befehle pro us Möglich. Funktionsaufruf, 
Rücksprung usw... Ich würde sagen ein Blick ins lss sollte sagen was da 
solangen Dauert (Stichwort Taktzyklen zählen). Aber wie Du shcon sagtest 
ist ja unkritisch.

>
> Wie ich die Sensorantworten lesen soll, weiß ich nicht. Hat jemand einen
> Tipp?
>
> Anzeige immer noch 0,0°C da ich immer noch nur 1sen lese?
>
> Gruß Rick

Also ich würde meine Funktionen (read_bit_1wire) als nächstes testen, ob 
die Fehlerhaft sind. Dazu würde ich den 1 Wire mit einem Widerstand von 
ca  100-200 Ohm (Schutz des Pin vor Zerstörung), Kurzschließen. Dann 
MUSS deine lesefunktion lauter Nullen lesen.  Funktioniert das, würde 
ich vermuten das es nur noch ein Timingproblem sein kann, oder Du 
bekommst keine Antwort. Wodurch auch die ganzen Einsen entstehen durch 
den 1wire Aufbau.
So weis man ob es am Code oder an der Hardware liegt. Den Fehler eben in 
kontrollierten Häppchen eingrenzen.

Mehr fällt mir dazu erst mal nicht mehr ein.
Eventuell hat ein 1Wire Experte hier im Forum noch eine Idee.

Gruss
Juergen

von Rick M. (rick00)


Lesenswert?

Hi Jürgen!

Also ich hab mal weitere Messungen vorgenommen:

Messung 1:
------------

Fkt. write_bit_1wire(1);

programmiert / gemessen

DQ low
2usec warten / gut 2usec
DQ high / Widerstand braucht ca 4usec für pull-up
67usec warte / 67usec

______________________________________________________________________ 
__

Messung 2:
----------

Fkt. write_bit_1wire(0);

programmiert / gemessen

DQ low
67 usec warten / 67,4usec
DQ high
2usec recovery / 2,6usec

______________________________________________________________________ 
__

Messung 3:
----------

Fkt. read_bit_1wire('a');

programmiert / gemessen

DQ low
2usec warten / 2usec low
DQ high / Wiederstand braucht 2,8usec für pull-up
11 usec warten
abfragen
54 usec warten / 66usec (soll = 11+54=65usec)

______________________________________________________________________ 
__


Wenn ich aber die Fkt.en write_byte_1wire messen möchte, bei denen 8bit 
hintereinander folgen, so streikt mein Osci.
Ich kann keine klaren Zeiten mehr ablesen, weil ich nur noch 
Mehrfacherscheinungen habe und auch die fallenden Flanken nicht mehr 
richtig erkennen kann.

Die Bit-Funktionen stimmen von den Zeiten her aber tadellos!



Ich probier jetz noch den pull-down, nach Deinem Vorschlag und schau 
mal, ob ich 0en lese.

Gruß Rick

von Rick M. (rick00)


Lesenswert?

Hi!

Wenn ich mit einem 560 Ohm widerstand einen pull-down mache so lese ich 
lauter nullen => jedes Byte hat den Wert null.

Jetzt kann ich noch einen Fehler in der Fkt. write_byte_1wire haben 
und/oder ein Timing-Problem, weil mir der Sensor nicht antwortet.

Grüsse Rick

von Falk B. (falk)


Lesenswert?

@ Erik M. (rick00)

>Wenn ich mit einem 560 Ohm widerstand einen pull-down mache so lese ich
>lauter nullen => jedes Byte hat den Wert null.

???
Was soll denn der Unsinn? 1-Wire ist ein OpenDrain Bus, ähnlich I2C. Da 
hat ein Pull Down nichts zu suchen.

MFG
Falk

von Rick M. (rick00)


Lesenswert?

Hi Falk!

Falk Brunner wrote:
> @ Erik M. (rick00)
>
>>Wenn ich mit einem 560 Ohm widerstand einen pull-down mache so lese ich
>>lauter nullen => jedes Byte hat den Wert null.
>
> ???
> Was soll denn der Unsinn? 1-Wire ist ein OpenDrain Bus, ähnlich I2C. Da
> hat ein Pull Down nichts zu suchen.

Das stimmt schon so! Ich wollte ja nur testen, ob meine Lesefunktion 
überhaupt 0en lesen kann und habe einen Sensor-Pull-Down simuliert.

______________________________________________________________________ 
__

Bin jetzt einen Schritt weiter gekommen und kann wenigstens vom Sensor, 
welcher statt Multiplexer A am Controller hängt korrekt das Scratchpad 
auslesen.

Die Wertigkeiten der Bytes sind wie folgt:

119  LSB Temp
1    MSB Temp
0
0
127  Config Register
255
9
16
151  CRC

Temp zusammengesetzt: 375
________________________________________________
alles richtig.


jetzt rechne ich:

int16_t temp=0, temp1=0;

// temp ist die zusammengesetzte Temparatur (LSB + MSB)
temp1 = ((temp * 325) / 1000);
return temp1;

temp1 ist vollkommen falsch berechnet (-27)? Hat der Controller da einen 
Overflow?

Was ist an meiner Rechnung falsch? Rauskommen müsste: (375*625) /1000 = 
234
was einer Temparatur von 23,4°C entspricht.

Grüsse Rick

von Jürgen S. (jsachs)


Lesenswert?

Erik M. wrote:
>> ???
>> Was soll denn der Unsinn? 1-Wire ist ein OpenDrain Bus, ähnlich I2C. Da
>> hat ein Pull Down nichts zu suchen.
>
> Das stimmt schon so! Ich wollte ja nur testen, ob meine Lesefunktion
> überhaupt 0en lesen kann und habe einen Sensor-Pull-Down simuliert.
Richtig, das war nur ein Test ob die Funktion Funktioniert. Hätte er 
jetzt wieder nur 1en gelesen wäre die Funktion fehlerhaft. Jetzt weis 
man das Sie Funktioniert.
______________________________________________________________________ 
__
>
> Bin jetzt einen Schritt weiter gekommen und kann wenigstens vom Sensor,
> welcher statt Multiplexer A am Controller hängt korrekt das Scratchpad
> auslesen.
>

Ahja, woran lag es ? Dann wüsste ich welchen Fehler ich nicht machen 
darf :-)

> jetzt rechne ich:
>
> int16_t temp=0, temp1=0;
>
> // temp ist die zusammengesetzte Temparatur (LSB + MSB)
> temp1 = ((temp * 325) / 1000);
> return temp1;
>
> temp1 ist vollkommen falsch berechnet (-27)? Hat der Controller da einen
> Overflow?
>
> Was ist an meiner Rechnung falsch? Rauskommen müsste: (375*625) /1000 =
> 234
> was einer Temperatur von 23,4°C entspricht.

Vielleicht ist es nur ein Tippfehler, aber in deiner Formel oben steht 
325, unten rechnest du mit 375 ?

Gruss
Juergen

von Jürgen S. (jsachs)


Lesenswert?

Erik M. wrote:

> int16_t temp=0, temp1=0;
>
> // temp ist die zusammengesetzte Temparatur (LSB + MSB)
> temp1 = ((temp * 325) / 1000);
> return temp1;
>
> temp1 ist vollkommen falsch berechnet (-27)? Hat der Controller da einen
> Overflow?
>
> Was ist an meiner Rechnung falsch? Rauskommen müsste: (375*625) /1000 =
> 234
> was einer Temparatur von 23,4°C entspricht.

Ja, du bekommst einen Überlauf. 375*625 = 121875. in einen in16 passen 
aber max 32768. Also für temp1 eine uint32 nehmen oder die Berechnung 
auf uint32 casten und das Ergebnis wieder uint16.

etwa so:
temp1 = (uint16_t)((uint32_t)((temp * 325) / 1000));
ich habe aber keine Ahnung ob das geht und ob das der gcc weg optimiert 
!

Juergen

von holger (Gast)


Lesenswert?

> temp1 = ((temp * 325) / 1000);

Mach mal folgendes

temp1 = ((temp * 325UL) / 1000);

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Jürgen Sachs wrote:
> Erik M. wrote:
>>> ???
>>> Was soll denn der Unsinn? 1-Wire ist ein OpenDrain Bus, ähnlich I2C. Da
>>> hat ein Pull Down nichts zu suchen.
>>
>> Das stimmt schon so! Ich wollte ja nur testen, ob meine Lesefunktion
>> überhaupt 0en lesen kann und habe einen Sensor-Pull-Down simuliert.
> Richtig, das war nur ein Test ob die Funktion Funktioniert. Hätte er
> jetzt wieder nur 1en gelesen wäre die Funktion fehlerhaft. Jetzt weis
> man das Sie Funktioniert.
> ______________________________________________________________________ ____
>>
>> Bin jetzt einen Schritt weiter gekommen und kann wenigstens vom Sensor,
>> welcher statt Multiplexer A am Controller hängt korrekt das Scratchpad
>> auslesen.
>>
>
> Ahja, woran lag es ? Dann wüsste ich welchen Fehler ich nicht machen
> darf :-)

Ich benutze jetzt eine Hilfsvariable (sende_bit) in der Fkt. 
write_byte_1wire.


>
>> jetzt rechne ich:
>>
>> int16_t temp=0, temp1=0;
>>
>> // temp ist die zusammengesetzte Temparatur (LSB + MSB)
>> temp1 = ((temp * 325) / 1000);
>> return temp1;
>>
>> temp1 ist vollkommen falsch berechnet (-27)? Hat der Controller da einen
>> Overflow?
>>
>> Was ist an meiner Rechnung falsch? Rauskommen müsste: (375*625) /1000 =
>> 234
>> was einer Temperatur von 23,4°C entspricht.
>
> Vielleicht ist es nur ein Tippfehler, aber in deiner Formel oben steht
> 325, unten rechnest du mit 375 ?

Sorry ist ein Tippfehler!
temp1 = ((temp * 625) / 1000); !!! ist richtig !!!

Wenn ich temp mit 625 multipliziere so überschreite ich den int16_t 
Zahlenbereich. Kann man dem Controller ihrgenwie sagen, daß er zum 
Berechnen temporär eine 32bit Variable benutzen soll und das Ergebnis in 
die 16bit Varible temp1 schreibt.

Ich habs folgendermaßen probiert, was in die Hose ging:

int16_t temp=0, temp1=0;
int32_t temp3;

// temp ist die zusammengesetzte Temparatur (LSB + MSB)
temp3 = (temp * 625);
temp1 = (temp3 / 1000);

Grüsse Rick

von Rick M. (rick00)


Angehängte Dateien:

Lesenswert?

Hi!

Habs nun endlich geschafft!
Jetzt funktionierts endlich mal OHNE Multiplexer.

2 Sensoren direkt an den Controller angeschlossen.

Die Berechnung der Temparatur mag einem am Anfang erschrecken, ist aber 
getestet und funktioniert. (auch bei neg. Temparatur!)
Ist an das Beispiel von Karl Heinz Buchegger angelehnt.
Wie ich die Berechnung per Festkommaarithmetik hinbekomme ohne einen 
Overflow zu verursachen weiß ich nicht.

Gruß Rick

von Jürgen S. (jsachs)


Lesenswert?

Hast Du die Lösung von Holger probiert ?
temp1 = ((temp * 325UL) / 1000);

durch das "UL" wird der Compiler angewiesen den Wert als 32 Bit unsigned 
zu betrachten und führt daher die Berechnung als solche durch.
Die Negativen Werte werden dadurch vermutlich nicht abgedeckt.

Gruss
Juergen

PS:  Ich hoffe meine DS18S20 kommen bald. Wieso müssen die auch 
ausgerechnet bei mir falsch geliefert werden :-(

von Rick M. (rick00)


Lesenswert?

Jürgen Sachs wrote:
> Hast Du die Lösung von Holger probiert ?
> temp1 = ((temp * 325UL) / 1000);
>
> durch das "UL" wird der Compiler angewiesen den Wert als 32 Bit unsigned
> zu betrachten und führt daher die Berechnung als solche durch.
> Die Negativen Werte werden dadurch vermutlich nicht abgedeckt.

Sorry hab ich total übersehen!

UL heißt ja unsigned long und passt daher nicht.
Ich kann LONG nehmen?

.... 325 ist falsch 625 ist richtig!!!



>temp1 = (uint16_t)((uint32_t)((temp * 325) / 1000));

uint kann ich nicht nehmen, ich rechne ja Vorzeichenbehaftet!

Ich probiers mal so:

temp1 = (int16_t)((int32_t)((temp * 325) / 1000));

Grüsse Rick

von holger (Gast)


Lesenswert?

>UL heißt ja unsigned long und passt daher nicht.
>Ich kann LONG nehmen?

Ja, lass das 'U' weg.

temp1 = ((temp * 625L) / 1000);

von Rick M. (rick00)


Lesenswert?

holger wrote:
>>UL heißt ja unsigned long und passt daher nicht.
>>Ich kann LONG nehmen?
>
> Ja, lass das 'U' weg.
>
> temp1 = ((temp * 625L) / 1000);

funktioniert !

______________________________________________________________________
temp1 = (int16_t) ((int32_t)(temp * 625) / 1000);

funktioniert nicht
______________________________________________________________________

temp1 = ((int32_t)(temp * 625) / 1000);

funktioniert nicht
______________________________________________________________________

temp1 = (int32_t) ((temp * 625) / 1000);

funktioniert nicht
____________________________________________________________________

Hab alles mal durchprobiert, auch im neg. Zahlenbereich.
Warum der Compiler die "Anweisung" (int32_t) ignoriert weiß ich nicht.


Mit temp1 = ((temp * 625L) / 1000); funktionierts aber.

ThanX Holger

Grüsse Rick

von Simon K. (simon) Benutzerseite


Lesenswert?

Erik M. wrote:
> ________________________________________________________________________
> temp1 = (int16_t) ((int32_t)(temp * 625) / 1000);
>
> funktioniert nicht
> ________________________________________________________________________
>
> temp1 = ((int32_t)(temp * 625) / 1000);
>
> funktioniert nicht
> ________________________________________________________________________
>
> temp1 = (int32_t) ((temp * 625) / 1000);
>
> funktioniert nicht
> ______________________________________________________________________

Ja, natürlich nicht. Schließlich castest du ja erst nach der 
Multiplikation..

von Rick M. (rick00)


Lesenswert?

Simon K. wrote:
> Erik M. wrote:
>> ________________________________________________________________________
>> temp1 = (int16_t) ((int32_t)(temp * 625) / 1000);
>>
>> funktioniert nicht
>> ________________________________________________________________________
>>
>> temp1 = ((int32_t)(temp * 625) / 1000);
>>
>> funktioniert nicht
>> ________________________________________________________________________
>>
>> temp1 = (int32_t) ((temp * 625) / 1000);
>>
>> funktioniert nicht
>> ______________________________________________________________________
>
> Ja, natürlich nicht. Schließlich castest du ja erst nach der
> Multiplikation..

Könntest Du bitte ein paar mehr Worte darüber verlieren....ggg....
Eine Richtigstellung mit ein paar Infos vielleicht?

Grüsse Rick

von Matthias Larisch (Gast)


Lesenswert?

Ich kann mal drauf eingehen:

> temp1 = (int16_t) ((int32_t)(temp * 625) / 1000);

das int32_t castet das Ergebnis von temp*625 in einen 32 bit integer, 
aber eben erst das Ergebnis, nachdem in 16 bit gerechnet wurde... Die / 
1000 Division wird also mit 32 Bit variablen durchgeführt :-)

Das 625L wandelt die 625 halt in ein long (long = 32 bit auf dem AVR) 
um, sodass die komplette Rechnung in 32 Bit durchgeführt wird. Der 
korrekte Typecast würde temp1 = ((int16_t)((int32_t)temp * 625) / 1000); 
lauten. Das (int16_t) ist überflüssig, dürfte aber zu einem 
Performancegewinn führen, da die Division somit nur als 16 und nicht als 
32 Bit Rechnung durchgeführt wird.

Es gibt allerdings keine Gründe, die gegen den Einsatz von temp * 625L 
sprechen, außer eventuell eine leicht verlorene Übersicht, da ein 
int32_t besser ins Auge springt als ein L.

Matthias

von Falk B. (falk)


Lesenswert?

@ Erik M. (rick00)

>Könntest Du bitte ein paar mehr Worte darüber verlieren....ggg....
>Eine Richtigstellung mit ein paar Infos vielleicht?

[c]
 temp1 = ((temp * 625L) / 1000);   // funktioniert !
[c]

Hier wird der Compiler angewiesen, 625 als 32 Bit (L = long) Konstante 
aufzufassen (ohne Endung ist es eine INT Konstante, welche je nach 
Compiler 16 oder 32 Bit sein kann). Die Multiplikation mit temp muss 
also als 32x32 Bit Multiplikation durchgeführt werden, weil eine 
Operation IMMER nur mit Operatoren gleichen Typs ausgeführt werden kann. 
Kleine Operatoren werden auf grosse erweitert. Die Division ist dann 
auch eine 32 / 32 Bit Division. Alles paletti.


[c]
temp1 = (int16_t) ((int32_t)(temp * 625) / 1000);
[c]

Hier wirds komplizierter. zunächst wird temp*625 bearbeitet, sethe ja in 
Klammern. 625 wir hier als INT aufgefasst (keine Endung) und ist bei 
WINAVR 16 Bit. temp ist ebenfalls als 16 Bit Variable definiert, somit 
wird die Multiplikation als 16x16 Bit durchgeführt und erzeugt einen 
Überlauf. Mööööp! Das Casten nach 32 Bit erfolgt DANACH. Zu spät.


[c]
temp1 = ((int32_t)(temp * 625) / 1000);
[c]

Das selbe in Grün.

[c]
temp1 = (int32_t) ((temp * 625) / 1000);
[c]

Dito.

[c]
temp1 =  ((int32_t)temp * 625) / 1000;
[c]

So sollte es auch gehen. 32 Bit Cast VOR der Multiplikation.

MfG
Falk

von Rick M. (rick00)


Lesenswert?

Hi!

Danke für eure Antworten, jetzt wird mir einiges klar.

temp1 = ( ( (int32_t) temp * 625 ) / 1000 );

funktioniert bestens


temp1 = ( (int16_t) ((int32_t)temp * 625) / 1000 );

bringt keinen Performancegewinn sondern funzt NICHT.


Grüsse Rick

von Jürgen S. (jsachs)


Lesenswert?

Erik M. wrote:
> Hi!
>
> Danke für eure Antworten, jetzt wird mir einiges klar.
>
> temp1 = ( ( (int32_t) temp * 625 ) / 1000 );
>
> funktioniert bestens
>
>
> temp1 = ( (int16_t) ((int32_t)temp * 625) / 1000 );
>
> bringt keinen Performancegewinn sondern funzt NICHT.
>

Was für mich relativ klar ist. Der Compiler macht die Berechnung mit 32 
Bit, "(int32_t)temp * 625)" und das Ergenbnis wird dann als 16 Bit 
gecastet . Hierdurch gehen ja wieder Informationen über 32768 verloren. 
Die weitere Berechnung erfolgt ja wieder mit 16 Bit, da alle Zahlen 
16Bit sind.
Ein Verschieben der ersten Klammer sollte das lösen:
temp1 = (int16_t)(((int32_t)temp * 625) / 1000 );
Hier wird jetzt erst das Ergebnis gecastet, sofern ich richtig liege.

Funktioniert die Berechnung so auch für den Negativen Bereich ? Dann 
bräuchte ich mir keinen Kopf mehr drüber zu zerbrechen und könnte das so 
übernehmen :-)

Ich danke im Übrigen Matthias Larisch und Falk Brunner für die 
Richtigstellung meines Castfehlers. Manchmal hat man einfach ein Brett 
vor dem Kopf. Ich glaube mit Java ruiniere ich mir langsam meine 
C-Kenntnisse :-)

Gruss
Juergen

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.