Hallo zusammen,
ich programmiere eine STM32F0 und war bisher von seiner Geschwindigkeit
begeistert. Bis jetzt. Allerdings glaube ich auch, dass das Proble vor
dem Controller sitzt.
Ich taste mit dem ADC alle 10 µS eine Spannung(Buffer[0]) und
Vref(Buffer[1]) ab. Mit diesen Werten möchte ich auf die Spannung
zurückrechnen mit folgender Formel:
Spannung=((Buffer[0]*3300.0*vrefint_cal)/(Buffer[1]*4095));
Allerdings benötige ich für diese Rechnung ca 55µs was ja viel zu
langsam ist.
Ich weiß, dass eine Division sehr lange dauert, allerdings kann ich
diese nicht umgehen.
Die Datentypen sind:
uint16_t Buffer[2];
vrefint_cal= *((uint16_t*) VREFINT_CAL_ADDR);
float Spannung=0;
Hat jemand eine Idee wie ich die Rechnung optimieren kann, um schneller
zu rechnen?
Matthias H. schrieb:> Hat jemand eine Idee wie ich die Rechnung optimieren kann, um schneller> zu rechnen?
Mit 32 Bit Integer rechnen.
Oder einen Prozessor verwenden der eine FPU drin hat.
Matthias H. schrieb:> Spannung=((Buffer[0]*3300.0*vrefint_cal)/(Buffer[1]*4095));
Du benutzt hier eine Konstante vom Typ Double, versuch es mal mit
> Spannung=((Buffer[0]*3300.0f*vrefint_cal)/(Buffer[1]*4095));
Gerhard
Gerhard schrieb:> Du benutzt hier eine Konstante vom Typ Double, versuch es mal mit>> Spannung=((Buffer[0]*3300.0f*vrefint_cal)/(Buffer[1]*4095));
Danke, 25µs eingespart:)
Allerdings immernoch zu lange...
Matthias H. schrieb:> Spannung=((Buffer[0]*3300.0*vrefint_cal)/(Buffer[1]*4095));
Damit rechnest du die Spannung auf 100µV Auflösung aus.Faktisch hast du
aber nur eine Auflösung von ~800µV. Also, mach aus der Spannung einen
int und rechne fixed point und gut ist.
P.S. Ich frage mich, warum du dich an den 55µs störst, wenn du eh nur
alle 10s misst :D
Ingo Less schrieb:> und rechne fixed point und gut ist
was bedeutet fixed point rechnen?
Ingo Less schrieb:> P.S. Ich frage mich, warum du dich an den 55µs störst, wenn du eh nur> alle 10s misst :D
habe mich verschrieben, meinte 10µS
Die Multiplikation also mit 3300L als long int durchführen und das
Ergebnis in float konvertieren, damit die anschließende Division nicht
zu einem Integer-Wert verkümmert.
Alternativ könnte man noch den Teil links (vor der Division) auch noch
mit 100 oder 1000 multiplizieren und dann eine reine Integerdivision
durchführen. Dann geht das noch wesentlich flotter und hat halt das
hundert- oder tausendfache des Ergebnisses. Damit kann man dann evtl.
die Ausgabe entsprechend formatieren. Zu den möglichen Wertebereichen
und der gewünschten Genauigkeit wurde leider nichts gesagt.
Frank M. schrieb:> Die Multiplikation also mit 3300L als long int durchführen und das> Ergebnis in float konvertieren, damit die anschließende Division nicht> zu einem Integer-Wert verkümmert.
Da "verkümmert" nichts. Es kann also komplett auf float/double
verzichtet werden...
Ingo Less schrieb:> Da "verkümmert" nichts. Es kann also komplett auf float/double> verzichtet werden...
Würde ich nicht so sagen, schau mal, was unter dem Bruchstrich steht.
Beispiel:
Buffer[0] = 300;
Buffer[1] = 300;
vrefint_cal = 1
Dann:
Deshalb sagte ich ja: Je nach gewünschter Genauigkeit kann man den
ersten Teil ja auch mit 100 oder 1000 multiplizieren. Dann kommt auch
bei der Integer-Division etwas sinnvolles raus.
Ingo Less schrieb:> Im Übrigen ist das ein 32Bitter, dort hat der int 32 Bit. Ein long ist> nicht nötig...
Doch, es werden 64bit benötigt, weil Buffer[0]*3300L*vrefint_cal zu groß
für 32bit sein kann (3 12bit Typen => 36 bit).
Wird das Ergebnis unbedingt in Volt gebraucht? Wenn du lediglich die
Kalibration berücksichtigst:
erhältst du das kalibrierte Ergebnis, aber eben nicht in Volt sondern in
3,3/4095 V Schritten.
Da du einen F0 verwendest vermute ich dass du keine extrem schnelle
Logging-Anwendung baust die in Volt loggen soll, und da du so schnell
ohnehin nichts anzeigen kannst ist die Einheit wohl eher egal.
Musst du die Referenzspannung unbedingt explizit messen und mit dem
eigentlichen Messwert verrechnen? Hat der STM keinen Anschluss für eine
externe Referenz? Falls doch und falls der Spannungsbereich des
Referenzanschlusses für deine Anwendung passend ist, könntest du sowohl
die Messung der Referenzspannung als auch die Division einsparen, da
dann der ADC den Messwert bereits fertig auf die Referenzspannung
skaliert liefert.
Yalu X. schrieb:> Musst du die Referenzspannung unbedingt explizit messen und mit> dem> eigentlichen Messwert verrechnen?
Leider ja.
Yalu X. schrieb:> Hat der STM keinen Anschluss für eine externe Referenz?
Nö. Man könnte lediglich Vdda stabilisiert erzeugen aber das ist auch
nicht so einfach:
"The V_DDA voltage level must be always greater or equal to the V_DD
voltage level and must be provided first."
Dr. Sommer schrieb:> Yalu X. schrieb:>> Hat der STM keinen Anschluss für eine externe Referenz?> Nö.
Ok, dann der nächste Versuch:
Ändert sich die Referenzspannung mit jeder Messung, oder bleibt sie über
einen längeren Zeitraum konstant? Dann müsstest du die Division immer
nur dann ausführen, wenn sich die Referenzspannung gerade geändert hat.
Ändert sie sich nicht, wird mit dem zuvor berechneten skalierten
Kehrwert multipliziert, was deutlich weniger Zeit in Anspruch nimmt.
Yalu X. schrieb:> Ändert sich die Referenzspannung mit jeder Messung, oder bleibt sie über> einen längeren Zeitraum konstant?
Im Idealfall bleibt sie konstant, aber wenn die Versorgung des
Controllers schwankt (insb. Vdda) ändert sie sich. Um genau das
auszugleichen macht man ja die ganze Rechnung. Man könnte sie lediglich
seltener messen o.ä.
Yalu X. schrieb:> Ändert sich die Referenzspannung mit jeder Messung, oder bleibt sie über> einen längeren Zeitraum konstant? Dann müsstest du die Division immer> nur dann ausführen, wenn sich die Referenzspannung gerade geändert hat.> Ändert sie sich nicht, wird mit dem zuvor berechneten skalierten> Kehrwert multipliziert, was deutlich weniger Zeit in Anspruch nimmt.
Ja das habe ich mittlerweile eingebaut. Vref wird nur in seltenen Fällen
gemessen und der Kehrwert multipliziert.
Irgendwie mache ich mist und bringe die Datentypen durcheinander
typische Werte sind:
Buffer 0..4095
Vrefint_cal=1525
Ich habe volt=unsigned long int.
Bei Buffer=2792,1606 bekomme ich mit 3300000 als Ergebnis mit dem
Taschenrechner 2136484 heraus.
Meint Compiler gibt mir aber 216 aus??
Ich brauche die Werte sehr genau. Ich taste 0-3.3 V mit 12bit
genauigkeit ab.
Matthias H. schrieb:> Ich taste mit dem ADC alle 10 µS eine Spannung(Buffer[0]) und> Vref(Buffer[1]) ab.
Die Preisfrage ist, was machst Du mit so vielen Meßwerten?
In der Regel ist es dem MC wurscht, ob eine Zahl in V oder sonstwas ist.
D.h. man kann alle Konstantenrechnungen meistens komplett rausziehen.
Z.B. für eine PID-Regelung, einen Schwellwertvergleich, eine
Verbrauchsmessung usw..
Peter D. schrieb:> Die Preisfrage ist, was machst Du mit so vielen Meßwerten
Ich regel die Spannung mit einem PI-Regler und gebe die Spannung nach
dem regler mit dem DAC aus
Ich würde anstelle der 'sehr' genauen Umrechnung mit dem 12bit ADC
direkt rechnen. Dann sparst du dir die ganzen Takte komplett. Musst halt
deine Regelung ggf. anpassen.
Matthias H. schrieb:> Ich regel die Spannung mit einem PI-Regler und gebe die Spannung nach> dem regler mit dem DAC aus
Und wofür brauchst Du die Spannung dann in Volt? Das ist doch nur eine
willkürliche Einheit, um Messwerte für den Menschen verständlicher zu
machen. Der DAC braucht einen Wert zwische 0 und X - aber schon gar
nicht in der Einheit Volt. Damit kannst Du die Konstanten alle
rauswerfen und durch eine geeignete (oder gar keine)
Umrechnungskonstante ersetzen.
Nico W. schrieb:> Ich würde anstelle der 'sehr' genauen Umrechnung mit dem 12bit ADC> direkt rechnen. Dann sparst du dir die ganzen Takte komplett. Musst halt> deine Regelung ggf. anpassen.
Richtig, aber "Volt" sind für Einsteiger manchmal halt einfacher als
abstrakte Werte.
Bei 12-Bit-Werten und davon geschätzt max. 10-Bit werthaltig ist das
ganze aber eigentlich kein Thema. (4096 > vrefint_cal > 1000)
(Buffer[0]*vrefint_cal*256)/Buffer[1] als 32 Bit UInt rechnen
Wenn es Volt (und Float) sein sollen: danach mit
0.00314789377f
multiplizieren.
Frank M. schrieb:> Und wofür brauchst Du die Spannung dann in Volt?
Ich muss die Spannung in Volt ausgeben um zu vergleichen. Daher brauche
ich die Werte in Volt
Matthias H. schrieb:> Ich muss die Spannung in Volt ausgeben um zu vergleichen.
Ausgeben... Du meinst, um diese mit dem Auge anzuschauen?
- Wenn ja: Alle 10µs? Dann hast Du eine schnelle Auffassungsgabe.
In diesem Fall sollte eine Umrechnung in Volt jede Sekunde reichen.
- Wenn nein: Dann vergleichst also der µC und nicht der Mensch.
Warum müssen dann die Vergleichswerte in Volt sein?
Frank M. schrieb:> - Wenn nein: Dann vergleichst also der µC und nicht der Mensch.> Warum müssen dann die Vergleichswerte in Volt sein?
Nein, ein Komparator vergleicht die Spannung vom DAC mit einer anderen
Spannung.
Sorry ich verstehe einfach nicht wie ich meine Regelung nur mit
Digitalwerten auslegen kann
Matthias H. schrieb:> Ich muss die Spannung in Volt ausgeben um zu vergleichen. Daher brauche> ich die Werte in Volt
Nur, weil du den Spannungswert dann besser lesen kannst, musst du noch
lange nicht damit rechnen.
Wenn man (zwei) konstante Größen in einer Formel hat, und nur Ergebnisse
dieser Formel miteinander vergleicht, kann man sich die Verrechnung mit
den konstanten Größen auch sparen (man sollte aber die Grundlagen der
Mathematik beachten...).
Wenn irgendwas ausgebenen werden muss, damit ein Mensch es lesen und mit
anderen Werten aus der realen Welt vergleichen kann, dann muss man es
auch umrechnen. Das kann man sich i.d.R. für den internen Gebrauch aber
sparen.
Hast Du mal das Gesamtkonzept überdacht?
Die Macht der Gewohnheit bewirkt, dass man sehr oft - und unnötig - in
Volt rechnet. Natürlich, das ist relativ gut nachvollziehbar und lässt
sich auch gut überprüfen.
...aber dabei fallen sehr viele Umrechnungen, Anpassungen und
Skalierungen an.
In fast allen Fällen kann man auch die Rohwerte vergleichen, addieren
oder mitteln. Die einzige Maxime in diesem Spiel ist die: Wenn DU ES
TATSÄCHLICH LESEN (sehen) WILLST, dann sollte man die (internen) Werte
"umskalieren".
Ich habe nicht ganz verstanden, was da mit was verglichen werden soll,
aber oft kann man so einen Vergleich dadurch vereinfachen, dass man
einfach die zugrundeliegende Ungleichung etwas umstellt. Beispiel:
1
v1*c1/v2 > v3*c2
v1, v2 und v3 sind dabei Variablen, die sich ständig ändern, c1 und c2
Konstanten. Durch Umstellen kann man die beiden Multiplikationen zu
einer einzelnen zusammenfassen und die Division durch eine weitere
Multiplikation ersetzen:
1
v1 > v3*v2*(c2/c1)
2
———————
3
const
(Voraussetzung: c1 und v2 sind nichtnegativ, sonst müsste man ggf. das
Größerzeichen umdrehen)
Und was soll so eine Umrechnung ueberhaupt ? Ich profezeihe mal, dass
sie voellig unnoetig ist. Es ist ja nur eine Skalierung. mV ist
genausogut wie Bit. Ein Konzept des Kopfes.
Anstelle von mV rechne in ADC bits. Fuer eine Regelung zB rechne aus dem
Sollwert die ACD Bits, und regle auf diese.
Die Frage ist aber auch, was muß so sauschnell innerhalb 10µs geregelt
werden?
Auch hast Du eh nie 12Bit Auflösung, da Du das ja erst mit der
Referenzmessung wichten mußt.
Um die vollen 12Bit zu erreichen, braucht Du einen MC mit interner oder
externer Referenz, d.h. AD-Wandlung unabhängig von VCC.
Hi,
Vref messen ist doch Murks. Ich messe mit einem ARM eine Reihe von
Spannungen mit 14 Bit Auflösung. Der hat auch keinen Seperaten Pin für
Vref. Mit einer anständigen Referenz an VDDa
(Prazisions-Spannungsrefezenz) mit 10µ/100n Kapazität schwankt da nix.
Der VDDa-Eingang zieht nur 0,1-0,3mA.
Die Restwelligkeit meiner Referenz ist <0,001V, also 0,03%.
Mit Software lausige HW ausgleichen ist immer eine schlechte Idee.
Bau dir eine Anständige Referenz, dann sparst du dir die division
komplett.
Yalu X. schrieb:> Musst du die Referenzspannung unbedingt explizit messen und mit dem> eigentlichen Messwert verrechnen? Hat der STM keinen Anschluss für eine> externe Referenz? Falls doch und falls der Spannungsbereich des> Referenzanschlusses für deine Anwendung passend ist, könntest du sowohl> die Messung der Referenzspannung als auch die Division einsparen, da> dann der ADC den Messwert bereits fertig auf die Referenzspannung> skaliert liefert.
Wie mißt man eigentlich eine Referenz ohne eine weitere Referenz? Und
warum der Umweg über 2 Referenzen?
Ich werde es versuchen in ADC-Bits zu rechnen und berichte hier.
Ich bin es eben gewohnt als Eingangsgröße des Reglers ein Wert von z.B
-2V..2V zu haben und nicht 2000...4000. Ich werde es aber mal versuchen.
Danke an alle, dass hier so eine rege Diskussion herrschte
Pefu schrieb:
> Yalu X. schrieb:>> Musst du die Referenzspannung unbedingt explizit messen und mit dem>> eigentlichen Messwert verrechnen? Hat der STM keinen Anschluss für>> eine externe Referenz?
Die meisten STM32 haben nur auf dem Papier einen, VDDA muss gleich
(±0.05V abs.max.) VDD sein. Beim STM32F205 heisst es gnädigerweise noch:
1
It is recommended to power VDD and VDDA from the same source.
2
A maximum difference of 300 mV between VDD and VDDA can be tolerated
3
during power-up and power-down operation.
Ich riskiere es, für VDDA eine 3.3V-Referenz und für VDD einen guten
3.3V-LDO zu nehmen; beide aus den gleichen 5V versorgt. Aber genau
genommen darf man nur VDD filtern.
> Wie mißt man eigentlich eine Referenz ohne eine weitere Referenz?> Und warum der Umweg über 2 Referenzen?
Die STM32 haben einen internen Spannungsregler, der liefert eine
"Embedded reference voltage" mit ca. 1.2V, die kann der ADC messen. Die
eigentliche ADC-Referenz ist aber immer VDDA, s.o.
eagle user schrieb:> Ich riskiere es, für VDDA eine 3.3V-Referenz und für VDD einen guten> 3.3V-LDO zu nehmen; beide aus den gleichen 5V versorgt. Aber genau> genommen darf man nur VDD filtern.
Wenn die ADCs des STM32 derart eigenartig sind, ist's vielleicht auch
einfach der falsche µC für den Job.
Auch bei einer gefilterten gemeinsamen Quelle können VDDa und VDD
kurzfristig deutlich mehr als 0,3V abweichen, wenn der µC plötzlich viel
Strom zieht (z.b. über Dig-IO)
Der Weg über gemeinsame 5V und dann übre Seperate 3,3V Regler müsste auf
alle Fälle gehen. Linearspannungsregler aus der gleichen Charge weichen
eigentlich die nennenswert von einander ab.
Sowas ist mir auch beim LPC2292 von NXP sauer aufgestoßen, daß die
Referenz gleichzeitig auch VDDA ist.
Wenigstens gab es bei dem aber keine Restriktionen bezogen auf VDD, so
daß ich dort eine 3,0V Referenz angeklemmt habe.
Wenn es so exakt sein soll, dann müsste man noch Offset-Fehler,
Gain-Fehler, INL und DNL des ADC berücksichtigen.
Wieso also nicht eine Kalibrier-Tabelle nutzen?
1
u16IstWert=au16Tabelle[u16ADCWert];
Die Tabelle müsste man halt mit einer genauen Spannungsquelle
aufzeichnen. Und wenn du unbedingt einen (völlig unnötigen)
Spannungs-Wert willst, kannst du den Wert beim langsamen Kalibrieren ja
berechnen. Der Arrayzugriff wird am Schluss schneller als jede Rechnung
sein.
Matthias H. schrieb:> Ich bin es eben gewohnt als Eingangsgröße des Reglers ein Wert von z.B> -2V..2V zu haben und nicht 2000...4000. Ich werde es aber mal versuchen.
Ist nur eine Darstellungs-Frage. Versuch doch als Gedankenspiel den
Regler in einem FPGA umzusetzen. Um Ressourcen zu sparen wird ja
möglichst auf jede Skalierung verzichtet...
Matthias H. schrieb:> 4095
Darüber könnten wir aber diskutieren. Für mich ist das 1. ein Fehler in
der Steigung, und 2. ineffizient, weil dann die Division niemals per
Shift ersetzt werden kann.
Korrekt wäre hier 4096.
S. schrieb:> Richtig, aber "Volt" sind für Einsteiger manchmal halt einfacher als> abstrakte Werte.
Dann darf man aber auch nicht an Mikrosekunden herummäkeln. Wenn ich im
Metzgerladen genau 5 Unzen Fleischwurst will, dann darf ich das nicht
auch gleichzeitig noch schnell wollen. Denn es dauert halt ein wenig,
bis die Fleischereifachwarenherausgeberin meinen Wunsch von Unzen in
Gramm umgerechnet hat.
Hallo,
Ich verstehe nicht, was das mit der internen Referenz soll bzw was man
damit anfangen kann. Im Manual steht, dass das eine Bandgap Referenz
sei.
Angenommen, ich kompensiere Offset und gain Fehler über Temperatur mit
einer Tabelle oder was auch immer, würde mir die Benutzung der internen
Referenz noch was bringen, zb gegen verrauschte VDDA Spannung?
Dankeschön!
Jan schrieb:> Angenommen, ich kompensiere Offset und gain Fehler über Temperatur mit> einer Tabelle oder was auch immer, würde mir die Benutzung der internen> Referenz noch was bringen, zb gegen verrauschte VDDA Spannung?
Die Vdda wird meist mit einem normalen Spannungsregler erzeugt. Der ist
nicht so genau wie die interne Referenz. Jetzt misst Du die interne
Referenz gegen Vdda. Da Du den exakten Wert der internen Referenz
kennst, kannst Du Verschiebungen von Vdda erkennen und damit dann eine
Offsetkorrektur machen.
Wenn natürlich Dein Spannungsregler für Vdda irgendeine superduper
Referenz wie z.B. ne LM399, LTC6655 etc. als Basis verwendet, ist dieses
Vorgehen natürlich nicht mehr sinnvoll und Du nimmst besser direkt den
gegen Vdda gemessenen Wert als Ergebnis.
> S. schrieb:>> Richtig, aber "Volt" sind für Einsteiger manchmal halt einfacher als>> abstrakte Werte.> Dann darf man aber auch nicht an Mikrosekunden herummäkeln. Wenn ich im> Metzgerladen genau 5 Unzen Fleischwurst will, dann darf ich das nicht> auch gleichzeitig noch schnell wollen. Denn es dauert halt ein wenig,> bis die Fleischereifachwarenherausgeberin meinen Wunsch von Unzen in> Gramm umgerechnet hat.
Ich finde, das passt noch nicht ganz. Für mich sieht das eher so aus:
Der Kunde will 5 Unzen Wurst haben. Die
Fleischereifachwarenherausgeberin legt nun Wurst auf die Waage und
rechnet dann das, was dort angezeigt wird, in Unzen um, um das mit dem
Sollwert zu vergleichen. Sie stellt fest, es ist zu wenig, legt noch
etwas drauf und rechnet abermals das angezeigte Gewicht in Unzen um, und
das geht so lange, bis das Gewicht stimmt - Wurstmenge ändern, Gewicht
in Unzen umrechnen, Unzen vergleichen, immer wieder. Dabei wäre es viel
einfacher gewesen, einmal den Sollwert in Gramm umzurechnen und dann das
nur noch zu vergleichen, ohne für jeden Vergleich nochmal neu umrechnen
zu müssen.
Ingo Less schrieb:> Frank M. schrieb:>> Die Multiplikation also mit 3300L als long> Im Übrigen ist das ein 32Bitter, dort hat der int 32 Bit. Ein long ist> nicht nötig...
Stört aber auch nicht. Wenn man zwingend mindesten 32 Bit braucht, ist
ein long besser. Sollte der Code mal auf einem 16-Bitter laufen, tut's
dann immer noch, und das, ohne dass es auf dem 32-Bitter irgendeinen
Nachteil hätte. Wozu also unbedingt int?
Pefu schrieb:> Wie mißt man eigentlich eine Referenz ohne eine weitere Referenz? Und> warum der Umweg über 2 Referenzen?
Was jetzt? Ohne oder mit 2. Referenz?
Ich verstehe es so: Er hat eine genaue Referenz, die er aber nicht
direkt für den ADC nutzen kann. Also misst er die Eingangsspannung
gegenüber einer ungenaueren internen Referenz, dann misst er die genaue
Referenz gegenüber der gleichen internen Referenz, und schon kann er die
ungenaue Referenz rausrechnen.
Lothar M. schrieb:> Matthias H. schrieb:>> 4095> Darüber könnten wir aber diskutieren. Für mich ist das 1. ein Fehler in> der Steigung, und 2. ineffizient, weil dann die Division niemals per> Shift ersetzt werden kann.> Korrekt wäre hier 4096.
Ja, das wird meistens falsch gemacht. Das Thema wurde schon oft
diskutiert.