Ich habe eine 16bit Variable "receivebuffer" und will mit dieser
folgende Berechung durchführen.
A=(receivebuffer*200)/2047
Der maximale Wert für A ist also 200 und belegt somit nur ein Byte. Bei
der multiplikation mit 200 übersteigt der sich in diesem Fall ergebene
Zwischenwert die 16Bit. Ist das für den verwendeten IAR C/C++ Compiler
kritisch? Gehen mir dabei Werte verloren? Oder muss ich für A zuerst
mehr als 16bit reservieren? Kann ich ja später wieder auf 8Bit
maskieren.
Gruß
Maddin
Maddin schrieb:> Der maximale Wert für A ist also 200 und belegt somit nur ein Byte
uninteressant
> Bei> der multiplikation mit 200 übersteigt der sich in diesem Fall ergebene> Zwischenwert die 16Bit.
Das ist ein Problem
> Ist das für den verwendeten IAR C/C++ Compiler> kritisch?
Nicht nur für den.
> Gehen mir dabei Werte verloren?
Ja
> Oder muss ich für A zuerst> mehr als 16bit reservieren?
Das spielt keine Rolle.
Bei der Wahl der Operation spielt es keine Rolle was mit dem Ergebnis
weiter passiert. Einzig die beteiligten Operanden bestimmen wie die
Operation durchgeführt wird.
receivebuffer ist ein int
200 ist ein int
also wird da eine int*int Multiplikation durchgeführt. Und die sollte
besser nicht überlaufen.
http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen
A=((long)receivebuffer*200)/2047
sollte funktionieren. Die Berechnung wird mit long gemacht,
anschliessend auf char zugewiesen.
Gibt ne Warnung, aber wenn du dir sicher bist...
Karl heinz Buchegger schrieb:>> Oder muss ich für A zuerst>> mehr als 16bit reservieren?>> Das spielt keine Rolle.
Und wenn ich vorher receivebuffer als Datentyp long festlege? Dann hauts
doch hin oder?
Oder gleich so wie Herr Seifert meinte.
Lass mich mal orakeln:
Das ist ne Berechnung für einen ADC. Der Wert A kommt von nem 11bit
Wandler und du willst die Größe normieren?
Stimmts? Wenn ja, behaupte ich mal, das statt der 2047 eine 2048 hin
muss.
Matthias Lipinsky schrieb:> Das ist ne Berechnung für einen ADC. Der Wert A kommt von nem 11bit> Wandler und du willst die Größe normieren?
nöö
> Stimmts? Wenn ja, behaupte ich mal, das statt der 2047 eine 2048 hin> muss.
nöö
Willst weiter raten oder soll ich dich aufklären? ;)
Es handelt sich dabei um den TSIC306. Ein genauer Temperatursensor mit
einer Auflösung von 0.1°C. Dieser gibt die Temperatur (je nach Modell)
per 11Bit Wert aus. Das Protokoll ist relativ einfach aufgebaut.
2Packete mit je 8Bit und Parität. Du hast also nicht ganz unrecht mit
ADC. Schließlich wird da irgendwo etwas analog-dital gewandelt.
Motivation wars für mich endlich mal eine vertrauenswürdige
Temperaturangabe zu erhalten. Auf meine, Schreibtisch steht son
noname-Wecker mit Temp-anzeige. Der interne ADC mit Temp-Sensor des
MSP430 stimmte mich auch nie zufrieden, deshalb hab ich mir den
arschteuren TSIC306 angeschafft.
Das beste ist aber die breits erwähnte Auflösung von 0.1°C. Und nachdem
ich es nun geschafft habe die nachkommastelle bei der Berechnung zu
retten und diese ber UART sicher (dank eurer Hilfe) mit HTERM
auszulesen, freuh ich mich wie Bolle.
Gruß
Maddin
Matthias Lipinsky schrieb:> also wird wohl doch eine 2048 da hin gehören...
Gibt es zu diesem Thema immer noch keinen Eintrag in der µc.net-FAQ?
Wird glaube ich Zeit, am besten mit kompletter Threadliste, in denen das
schon durchgekaut wurde... ;-)
Ach ja, laut diesem pdf, stimmt 2047...
Beitrag "Re: Temperatursensor TSIC 306 TO92"
... ... ... schrieb:> Ach ja, laut diesem pdf, stimmt 2047...> Beitrag "Re: Temperatursensor TSIC 306 TO92"
Nich ohne Grund sag ichs die ganze Zeit. Aber wenn jemand begründeter
Weise das Datenblatt kritisiert....
Das heisst nicht viel.
Auch Datenblätter sind in diesem Punkt schon falsch gewesen.
Höchst wahrscheinlich ist 2048 tatsächlich richtig :-)
Die Begründung ist analog zu der hier
http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC#Ein_paar_ADC-Grundlagen
und der SChlüssel zum Verständnis besteht darin, zu akzeptieren, dass
dir der ADC nicht mitteilt: die SPannung ist so und so hoch.
Sondern er teilt dir mit: Die Messspannung ist größer gleich dem Wert x
und sie ist kleiner gleich dem Wert y. Der ADC sagt dir also in welchem
Bereich sich die Spannung bewegt. Und mit 11 Bit gibt es nun mal 2048
Bereiche, in denen sich die Spannung bewegen kann.
Mit kleineren Zahlen (zb einem 3 Bit ADC) wird es besser ersichtlich,
warum man eigentlich duch 2 hoch n dividieren müsste, warum man statt
dessen aber auch mit 2 hoch (n-1) dividieren kann und was die
Unterschiede dabei sind.
Und ich rede jetzt nicht davon, dass sich ein µC bei einer Division
durch 2048 leichter tut als bei einer Div. durch 2047.
Es sieht nun einmal Scheisse aus, wenn auf deinem Messgerät mit einem
3Bit ADC und einer Referenzspannung von 8V beim Anlegen von 8V auf der
Anzeige 7V steht. Auch wenn es technisch korrekt ist, denn der ADC hat
dir korrekterweise gesagt, dass die zu messende Spannung sich im Bereich
7V bis 8V bewegt.
Ja das ist ja eigentlich alles klar Herr Buchegger, aber was ist wenn
bei der Umrechnung in eine entsprechende Temperatur ein derartiger Drift
vorliegt, dass dieser von Seiten der Entwickler durch eine Änderung der
Übertragungsfunktion (Anstieg) korrigiert wird.
Es geht ja hier nicht um die Frage in welchem Bereich der Temperatur ADC
eine Spannung misst sondern inwievern Temperaturänderungen sich auf den
gemessenen Wert auswirken.
Sie nehmen ja stillschweigend an die Messung einer Temperatur geschieht
genauso wie das anlegen einer Spannung. Irgendwo muss ja noch etwas
zwischen Temperaturgröße und ADC-Inputgröße sein. Sowas wie ein
Kaltleiter oder Heißleiter.
Oder?
Gruß
Maddin
Maddin schrieb:
Ich seh jetzt ehrlich den Zusammenhang nicht.
Es geht doch schlicht darum, dass ein Wert von 2047 (also das Maximum)
eben nicht bedeutet, dass die zu messende Größe exakt auf dem Maximum
ist. Sondern es geht darum, dass dir dieser Messwert nur mitteilt, dass
sich die Messgröße irgendwo im letzten Messintervall befindet.
In der Praxis ist das bei genügend großer Auflösung ziemlich irrelevent,
geb ich schon zu. Da wird der Messfehler schon höher sein, bzw. wir
reden hier bei einem einem Deltamesswert von 1 um eine
Temperaturdifferenz von ein paar Hunderstel (wenn überhaupt) Grad.
Wenn es aber sowieso irrelevant ist, dann kann man auch richtigerweise
durch 2048 dividieren.
Also Folge davon kann mann dann die Umrechnung
Wert * 200 / 2048
kürzen auf
Wert * 50 / 512
und kommt plötzlich mit int Rechnerei über die Runde :-)
Karl heinz Buchegger schrieb:> Sondern es geht darum, dass dir dieser Messwert nur mitteilt, dass> sich die Messgröße irgendwo im letzten Messintervall befindet.
Bestreitet ja auch niemand. Ich würde gern nur bestätigt haben (und das
ist schwierig), ob sich nun die 2074 anstatt der 2048 auf Grund der
Unwissenheit der Autoren in die Doku geschlichen haben ODER ob
vielleicht mit voller Absicht 2047 anstatt 2048 verwendet werden um
Fehler/Nichtlinearitäten in der Übertragungsfunktion Temperatur -
Messwert des ADC - digitaler Wert auszugleichen... ??
Karl heinz Buchegger schrieb:> Das heisst nicht viel.> Auch Datenblätter sind in diesem Punkt schon falsch gewesen.> Höchst wahrscheinlich ist 2048 tatsächlich richtig
Ich finde 2048 auch logischer, gibt ja auch genug Datenblätter wo 2048
drinsteht bzw. damals waren es 4096. Es ist mir nur aufgefallen. ;-)
Hier kann man Maddin also nicht soviel vorwerfen, außer vielleicht der
Ton. ;-)
Maddin schrieb:> vielleicht mit voller Absicht 2047 anstatt 2048 verwendet werden um> Fehler/Nichtlinearitäten in der Übertragungsfunktion Temperatur -> Messwert des ADC - digitaler Wert auszugleichen... ??
Wie willst du denn da Nichtlinearitäten ausgleichen?
Ob 2047 oder 2048, die Umrechnung ist und bleibt eine lineare Gleichung.
Wenn Nichtlinearitäten ausgeglichen werden müssen, dann hat man es immer
mit einer nicht-linearen-Gleichung zu tun.
Die Kurve, die die Abhängigkeit des tatsächlichen Messwerts von der zu
messenden Größe beschreibt ist dann keine Gerade sondern irgendwie
gebogen. Die Formel wird dann so gewählt, dass die sie diesen Bogen
wieder geradebiegt.
Karl heinz Buchegger schrieb:> Die Formel wird dann so gewählt, dass die sie diesen Bogen> wieder geradebiegt.
Ja und ich frage, ob es dies mit 2047 vielleicht besser als mit 2048
tut....
Du hörst nicht zu.
Mit einer linearen Gleichung kann man keinen gebogenen Funktionsgraphen
geradebiegen. Daher kann 2047 versus 2048 nichts mit einer Begradigung
einer Funktion (vulgo Linearisieren eines nichtlinearen Zusammenhangs)
zu tun haben. Warum? Weil das nur ein Parameter in einer linearen
Umrechnung ist. Wenn es um das Bereigen von Nichtlinearitäten gehen
würde, dann müsste die Umrechnungsformel komplett anders aussehen.
Nein das verstehe ich wirklich nicht. Man nehme eine gebogene Funktion
und nähere sie mit einer linearen Funktion an 2 Punkten an. Wo ist da
das Problem? Für den linearen Teil der gebogenen Funktion wird das dann
doch sehr gut hinhauen.
Des Weiteren Sie sagten, es liege hier eine gebogene Funktion vor. Laut
Datenblatt wird die Temperatur mit Hilfe einer linearen Funktion
berechnet. Nach ihrem letzten Post ist aber gerade dies unmöglich.
Das verstehe ich wirklich nicht.
Gruß
Maddin
Maddin schrieb:> Nein das verstehe ich wirklich nicht. Man nehme eine gebogene Funktion> und nähere sie mit einer linearen Funktion an 2 Punkten an.
Das hat dann aber nichts mehr mit Linearisieren einer Nichtlinearen
Funktion zu tun.
Das ist einfach nur lineare Interpolation.
> Des Weiteren Sie sagten,
meinst du mich?
Wenns recht ist, sind wir per Du.
> es liege hier eine gebogene Funktion vor.
Ich sagte das nicht.
Du sagtest, ob die 2047 wohl aus irgendwelchen
Linearisierungsbestrebungen resultieren würden? Und ich hab argumentiert
warum das nicht sein kann.
> Laut> Datenblatt wird die Temperatur mit Hilfe einer linearen Funktion> berechnet.
Dann ist es ja gut.
> Nach ihrem letzten Post ist aber gerade dies unmöglich.
Nicht wirklich.
Ich habe eine Hypothese getroffen:
Unter der Annahme, dass der Zusammenhang eben keine Gerade wäre sondern
irgendeine gebogene Funktion .... könnten dann die 2047 (anstelle der
2048) daher rühren, dass man diese gebogene Funktion gerade biegen
möchte.
Und die Antwort darauf ist: nein.
Ob 2047 oder 2048 macht keinen Unterschied in dieser Beziehung. Nur
durch ändern dieses Zahlenwertes kann man nicht eine gebogene Funktion
begradigen. Das würde nur dann gehen, wenn der Hersteller etwas anderes
als einen lineare Formel zur Umrechnung vorschreibt. Da er das aber
nicht tut, gibt es da auch keinen Zusammenhang mit den 2047
Jetzt klarer?
Karl heinz Buchegger schrieb:> Ich habe eine Hypothese getroffen:
Ja sorry, das hatte ich in der Schnelle überlesen.
> Jetzt klarer?
Was die Linearisierung angeht schon. Nur immer noch unbefriedigt was die
2048 angeht. Da prallen wohl Welten aufeinander. Und so lange sich der
Autor des Datenblattes hier nicht über die 2047 rechtfertigen kann nehem
ich die mal so an.
Trotzdem stimmt der Sachverhalt natürlich, dass man beim Berechnen der
Bereichspannung immer 1 zum Maximalwert des digitalen Wertes addiert.
Gruß
Maddin
Maddin schrieb:> Karl heinz Buchegger schrieb:>> Ich habe eine Hypothese getroffen:>> Ja sorry, das hatte ich in der Schnelle überlesen.>>> Jetzt klarer?>> Was die Linearisierung angeht schon. Nur immer noch unbefriedigt was die> 2048 angeht. Da prallen wohl Welten aufeinander. Und so lange sich der> Autor des Datenblattes hier nicht über die 2047 rechtfertigen kann nehem> ich die mal so an.
Kannst du auch.
Denn: In der Praxis ist das eine akademische Frage :-)
probiers mit kleineren Werten aus. Du wirst (fast) dieselben Werte
erhalten. Bei 2047 versus 2048 und einem Zielbereich 0..200 sowieso. Da
ist der Unterschied irgendwo in der 3. Nachkommastelle und damit völlig
uninteressant (solange er nicht dazu führt, dass aus 2.99 auf der
Anzeige eine glatte 3.0 wird und damit bei Anzeige von nur dem
ganzzahligen Anteil in dem einen Fall eine 2 und im anderen Fall eine 3
auf der Anzeige steht)
Was jedoch nicht akademisch ist:
Um durch 2047 dividieren zu können, muss eine echte Division
durchgeführt werden. Bei 2048 reicht Bitschieben.
Und in deinem speziellen Fall natürlich auch noch, dass du durch die
2048 im Bruch Kürzungsmöglichkeiten bekommst, die dir die ganze
Berechnung aus dem Zahlenraum long in den Zahlenraum int drücken.
Gut, bei einem Thermometer ist auch das wahrscheinlich nicht das große
Problem.
Karl heinz Buchegger schrieb:> Da> ist der Unterschied irgendwo in der 3. Nachkommastelle und damit völlig> uninteressant
Warscheinlich hat der Sensor auch ein Error von 1 LSB, somit ist das
eigentlich egal, oder?
Karl heinz Buchegger schrieb:> kürzen auf>> Wert * 50 / 512
2047 kann man aber nicht kürzen (wobei 2048 auch kein Problem sein
sollte, siehe erster Absatz).
Aber nur aus interesse.. kann man nicht
A = (Wert / 2047) * 200
schreiben???
mit float-Zahlen wäre das kein Problem, mit Integer-Berechnung verlierst
du damit jede Menge Genauigkeit.
Durchdenke es mal, oder kloppe es mal in Excel ein :-)
max schrieb:>> kürzen auf>>>> Wert * 50 / 512>> 2047 kann man aber nicht kürzen
Eben.
Aber mit 2048 kann man kürzen :-)
Man kann sogar noch weiter kürzen Wert * 25 / 256
Was dann (ja nach Compiler) noch besser ist, weil hier noch
nicht mal geschoben werden braucht, sondern einfach nur das LSB
weggeschmissen wird und das HSB zum Ergebnis erklärt wird.
> Aber nur aus interesse.. kann man nicht>> A = (Wert / 2047) * 200>> schreiben???
können tut man schon.
:-)
'Wert' kann welche Werte annehmen?
'Wert' hat welchen Datentyp
Was ergibt daher Wert / 2047
(immer 0; es sei denn Wert ist 2047, dann kommt 1 raus)
tempCn=((uint32)receivebuffer*200);//erster Schritt für Nachkommastelle
3
while(tempCn/2047)tempCn=tempCn-2047;//ziehe solange 2047 ab bis 2047 nicht mehr vollständig in den Wert passt (die Division durch 2047 also 0), Vorkommstellen fliegen somit raus
4
5
tempCn=(tempCn*10)/2047;//Nachkommastelle berechnen, tempCn nun zwischen 0 und 9
6
7
ausgabevontempCvundtempCn
Ist das gut so? Lässt sich die Laufzeit verkürzen?
Wenn du hier
tempCv = (((uint32)receivebuffer*200)/2047) - 50; //Vorkommstellen
sowieso auf 32 Bit Arithmetik ausweichst, dann kanst du auch gleich
1
uint32_tDegrees=(receivebuffer*2000UL)/2047;
2
3
tempCv=Degrees/10;
4
tempCn=Degrees%10;
rechnen.
Ist einfacher und bei dem was du da rumrechnest wahrscheinlich auch
nicht langsamer.
Edit: Es ist mit Sicherheit nicht langsamer. So langsam kann der gcc 32
Bit Divisionen gar nicht implementieren.
Hallo,
dieses
1/(K-1) = 1/K +1/K^2+1/K^3+...
Messwert/(K-1) = m*(1/K +1/K^2+1/K^3+..1/K^n)
mit K=2048 und Messwert = 2047
2047/2047 ~ 2047/2048+ 2047/2048 /2048
1 ~ 0,99511718+0,000488042=0,999999761
Dann ist die Abweichung im Bereich von 1/2048^2 < 1e-6
Also würde ich den Messwert*200 / 2048= Messwert*25 / 256
teilen/schieben
Also nur *25, diesen Intwert kopieren um 3 bit(=11-8 ) nach rechts
schieben.
Darauf dann 4 zum runden addieren
Hallo,
wohl Unsigned Long 32-Bit Wert von 0..4,2 Milliarden.
Aber oben mein Codegeschnipsel kommt ohne dies aus.
Sieht nach mehr aus, aber der versteckte Code für die 32-Bit Division
ist auch nicht zu verachten.
Karl heinz Buchegger schrieb:> Soll ich wirklich noch den Hinweis auf ein C-Buch bringen?
Nönö, aber diese Suffix-Schreibweise hab ich echt noch nie gesehen. Naja
gut zu wissen, ech praktisch.
Mal abgesehen davon dass ich keinen AVR programmieren sondern MSP, hab
ich diese Schreibweise trotzdem noch nie gesehen (oder nie bewusst
Gedanken drüber gemacht). Ich kam zwar ganz gut ohne aus, gefällt mir
jetzt aber ganz gut und werde ich auch verwenden.
Danke dafür.
> Der maximale Wert für A ist also 200 und belegt somit nur ein Byte.> Bei der multiplikation mit 200 übersteigt der sich in diesem Fall> ergebene Zwischenwert die 16Bit.
Häää?????
200*200=40000 passt in 16 Bits (zumindest unsigned)
Das Ausgeben von ADC- oder sonstigen Werten hatten wir doch schon 1024
mal:
Beitrag "Re: 16-Bit-Zahl ausgeben, nur wie?"Beitrag "Re: 1023 auf 100% umformen"
Nimm 2048, ist einfacher und tut der Genauigkeit keinen Abbruch.
eProfi schrieb:>> Der maximale Wert für A ist also 200 und belegt somit nur ein Byte.>> Bei der multiplikation mit 200 übersteigt der sich in diesem Fall>> ergebene Zwischenwert die 16Bit.>> Häää?????> 200*200=40000 passt in 16 Bits (zumindest unsigned)
200 ist sein Ergebnis, welches maximal 200 sein kann.
Ausgansgpunkt der Rechnung ist ein ADC Wert, welcher bis 2047 hoch gehen
kann.
eProfi schrieb:> Häää?????> 200*200=40000 passt in 16 Bits (zumindest unsigned)>> Das Ausgeben von ADC- oder sonstigen Werten hatten wir doch schon 1024> mal:
Nein. Habe Wert der maximal 11bit von 16bit belegt. Nimmt man den Wert
mal 200 übersteigt er die 16Bit. Mit der Ausgabe hat das hier nichts zu
tun. Sondern mit der Berechnung.
Dennoch nochmal vielen Dank allen, für die zahlreichen Links und
Gedanken.
Gruß
Maddin
Hallo,
anbei ein Programm, das es mal im Simulator ( ATmega8 ) vorführen kann.
Es braucht nur 250 Takte für eine Umwandlung des Tsic306-Wertes in eine
Zeichenkette.
Es wird kein UL32 oder ähnliches benötigt.Stattdessen Fixpoint U8.8 mit
seperatem Vorzeichen.
Natürlich sind 3 Nachkommastellen albern, man kann ja auch weniger
ausgeben lassen.