Guten Abend,
ich bin gerade dabei ein Programm für einen kleinen Attiny mit 1kB zu
schreiben, und da stoßt es schnell an seine Grenzen, deshalb wollte ich
Fragen, welche Befehle oder Aktionen am meisten Resourcen bzw.
Programmspeicher brauchen, um sie eventuell mit anderen schnelleren bzw.
mit welchen mit weniger Speicherplatzbedarf zu ersetzen.
Danke schonmal
Gruß
eller
Hallo,
was möchtest du denn genau realisieren? Mit einigen Hinweisen können
hier sicher viele aus Erfahrung sagen, ob es mit 1 KB geht, oder nicht.
Im Allgemeinen kann man sagen, dass ein C-Programm etwas mehr Speicher
braucht, als eins in Assembler, vor allem bei 1 KB werden schon
irgendwelche Prologe/Epiloge und Variableninitialisierungen ins Gewicht
fallen.
Ich würde zuerst mal programmieren und bei Bedarf einen größeren nehmen.
Es zahlt sich kaum aus, viel Arbeit reinzustecken, um doch noch unter 1
KB zu kommen - der nächstgrößere Controller kostet nicht die Welt.
Gruß
David
Hallo!
Ich verwende AVR-GCC danke ich werde mir das mal durchlesen!
Ich bin momenten auf exakt 1024 Bytes.
Soweit bin ich fertig mit programmieren, es kann nur sein das eine
Kleinigkeit noch dazukommt.
Zuerst solltest Du Dir, meiner Ansicht nach, diese Schlagwort-Getexte
abgewöhnen. Du siehst an den Antworten, das stattdessen wesentliche
Informationen fehlen.
Was die Befehle an "Resourcen" brauchen siehst Du in der
Befehlsreferenz. Du wirst unschwer schliessen können, das der
Addier-Befehl die Resource "Addierer" braucht. Es gibt keinen
alternativen Addierbefehl der sein Ergebnis ohne Addiereinheit erledigen
könnte. Wie sollte das auch gehen?
Wenn es einen Addierbefehl gäbe, der wenig "Resourcen" braucht, wozu
dann einen zweiten der viel "Resourcen" braucht?
Fasst man das ganze weiter, so mag es Unterschiede geben, wenn man
mögliche Daten bzw. Datentypen variiert. Du kannst z.B. den Datenpfad
vom Carry-Flag "schonen", indem Du einen Addier-Befehl ohne Übertrag
verwendest, aber das ist in der Praxis irelevant, wenn Du nicht die Wahl
hast.
Was Du eigentlich suchst, ohne es zu wissen ist ein anderer kürzerer
Algorithmus, der das selbe tut, was Du schon implementiert hast. Das hat
mit den Assemblerbefehlen und auch mit den Hochsprache-Befehlen und
Ausdrücken nichts zu tun.
Wir müssten also wissen was Dein Programm tun soll und welchen
Algorithmus Du verwendest. Dann könnten wir Dir Alternativen
vorschlagen.
Hallo Huch!
Die hast natürlich recht, ich will meinen Code "besser" programmieren,
einiges habe ich schon geschafft, um einige Abfragen wegzubekommen bzw.
statt for schleifen, do - while verwendet.
Im Grunde genommen tut das Programm nicht viel hier:
Nach etwas Überlegung muss ich einräumen, das nach den Informationen
unter http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung
hier durchaus gefragt worden sein könnten und meine Antwort mehr oder
weniger weit am Ziel vorbeigegangen sein könnte.
Es kommt mir zwar nicht so vor, als wenn bewusst danach gefragt wurde,
(dieses "Resourcenschonend") aber es könnte doch möglich sein.
Ich bitte meine Antwort in diesem Sinne als weitere Anregung und nicht
als Widerspruch verstehen zu wollen.
eller schrieb:> voltage=(result*40960/kalibrierung);>> ocr = (((voltage-((unsigned long)STARTWERT*10))*255)/1000);
Multiplikationen und vor allem Divisionen mit so großen Zahlen vermeiden
wenn nur irgendwie möglich. Das kostet ne Menge. Auch generell versuchen
mit möglichst möglichst kleinen integer-typen auszukommen.
Dazu halt die Wertebereiche+Formeln entsprechend umbauen. Am Ende soll
der Wert ja in ein 8Bit OC-Register, da ists in wenigen Fällen nötig,
den Wert vorher auf 32Bit aufzublasen. Also zuerst überlegen was In- und
Output Wertebereiche sind, dann versuchen im kleinsten davon zu rechnen
und prüfen ob ne LUT an manchen Stellen evtl. schneller/kleiner wird,
als die Rechnerei.
Hallo,
also in ocr wird gespeichert, wie der duty cycle von der PWM sein soll.
muss also zwischen 0-255 liegen.
kalibrierung liegt im EEPROM und wird zu anfangs des Programms, in eine
locale variable eingelesen ( eben in die kalibrierung )
result ist hier immer das Ergebnis der ADC-Wandlung
voltage liegt im Bereich bis maximal 42000 und STARTWERT bis 4100
somit komm ich mit 16Bit nicht aus, oder gibts ne Möglichkeit ?
das ganze ist immer so, bei STARWERT beginnt die PWM und bei voltage +
1000 endet die PWM ( maximaler duty cycle = 100% )
> kalibrierung liegt im EEPROM und wird zu anfangs des Programms, in eine> locale variable eingelesen ( eben in die kalibrierung )
voltage=(result*40960/kalibrierung);
Speicher im EEPROM besser gleich das Ergebnis von 40960/kalibrierung
(wenns reinpasst). Dann sparst du dir die division in Software. Die
dürfte nicht billig sein...
ocr = (((voltage-((unsigned long)STARTWERT*10))*255)/1000);
überlege dir mal, wie viel Genauigkeit du hier wirklich brauchst (auch,
da OCR am ende auf 8 bit beschränkt wird. Eventuell kommst reicht es,
statt 255/1000 einfach /4 zu schreiben. Das löst sich dann in zwei
schifts auf und braucht deutlich weniger Platz als die Division.
Und wenn STARTWERT wirklich nur bis 4100 geht reichen sowieso 16 bit.
unsigned long sind 32...
Gruß,
Sebastian
>Speicher im EEPROM besser gleich das Ergebnis von 40960/kalibrierung
Dabei geht aber Auflösung flöten!
Auch, wenn man zum Beispiel an drei Stellen den Aufruf einer DIV_L
erzwingt, bringt es nichts, diese Aufrufe auf einen zu reduzieren, da
die Funktion auf jeden Fall im Programmcode vorhanden/hinzugelinkt ist.
Gerade bei so kleinen Speichergrößen ist es besser, einen größeren
Prozessor zu nehmen, wenn es möglich ist. Es sei denn, sehr große
Stückzahlen sollen produziert werden, wobei dann jeder Cent zählt.
Geht die Rechnung ueber float ? Oder ueber integer ? An der gezeigten
Mathe kann man noch vereinfachen. Der ADC und das UART fehlen, resp
wurden von einer Library genommen.
Da kann noch Einiges optimiert werden:
> result = result >> 4;> voltage=(result*40960/kalibrierung);
Fällt dir was auf? Zuerst /16 und dann *40960
*40960 ist für den µC eine krumme Zahl. Versuche eine "gerade" Zahl
(Vielfaches von 2). Den Wertebereich von result kannst Du ja auch mit
der Anzahl der Schleifendurchläufe steuern. Wer sagt denn, das das 255
sein müssen?
Evtl. kannst Du sogar das Kalibrieren mit der Anzahl der
Schleifendurchläufe machen. Auf jeden Fall diese Division
result*40960/kalibrierung
vermeiden, indem Du mit dem Kehrwert von kalibrierung multiplizierst.
evtl. reicht ein 16-Bit-Variable für result, wenn das ADC-Ergebnis
rechtsbündig steht und die Schleifenzahl nicht zu groß wird,(z.B. <=64).
Dann brauchst Du 10 Bits für ADC und 6 Bits für die Anzahl der
Schleifen, das passt in 16 Bits.
if(ocr>=0xFF)
{ ocr = 0xFF;
}
else if(ocr<=0x00)
{ ocr = 0x00;
}
Prüfe, ob Du das überhaupt brauchst.
Zum Schluss steht dann
U8_t kalibrierung;
U16_t result;
while(rx_busy()){
result=0;
//oder result=2<<9 (result wird später beim >>10 gerundet)
counter = kalibrierung;
do{ result+=ADC_Read(); }
while (--counter);
//evtl. umstellen oder addieren:
ocr=startwert-(result>>10);
OCR0B=(unsigned char)ocr;
}
Das dürfte deutlich weniger Code erzeugen und ausreichend genau sein.
Evtl. ist es besser, für die Kalibrierung mehr Bits zu spendieren, und
dafür den ADC weniger (8+8):
result=0;
//oder result=1<<9 (result wird später beim >>10 gerundet)
counter = kalibrierung;
do{ result+=ADC_Read()>>2; }
while (--counter);
//evtl. umstellen oder addieren:
ocr=startwert-(result>>10);
OCR0B=(unsigned char)ocr;
}
Beachte: liest Du ADC links- oder rechtsbündig aus?
Um wieviel Bits Du schieben (1<<x und result>>y) musst, habe ich nicht
geprüft.
Auf jeden Fall muss x=y-1 sein, damit das Aufrunden funktioniert.
Korrektur: oben steht 2<<9, das muss 1<<9 heißen.
Bitte schreibe uns, wie Du es gelöst hast.
Die Rechnung geht natürlich über Integer, Float geht ja nichtmal hinein
in einen attiny13 ;)
Einen größeren Speicher kann ich leider nicht nehmen.
heißt also 40960/kalibrierung brauch ich nicht in EEPROM gleich so zu
speichern, da es nichts bringt ?
Die Genauigkeit beim ocr hätte ich gerne auf 8Bit und das auf 2 Stellen
genau.
stimmt der cast auf unsigned long, ist wohl nicht nötig, dass mit /4
muss ich mir nochmal überlegen, es geht dann nicht von voltage + 1000
sondern von voltage + 1024
Hallo eProfi!
mit der Schleife mit 255 möchte ich natürlich, die ADC Auflösung auf
14Bit erhöhen, das möchte ich soweit möglich beibehalten.
40960 ist festgelegt durch meine Kalibrierspannung von 4096*10 (4.096V)
Dieserhier:
if(ocr>=0xFF)
{ ocr = 0xFF;
}
else if(ocr<=0x00)
{ ocr = 0x00;
}
brauch ich insofern, ich schreib ja nachher ocr in OCR0B ich weiß nicht,
was der µC macht, wenn in einem 8-Bit timer plötzlich 300
hineingeschrieben wird? bzw. eine Zahl kleiner 0?
> mit der Schleife mit 255 möchte ich natürlich, die ADC Auflösung> auf 14Bit erhöhen, das möchte ich soweit möglich beibehalten.
Soso, 14 Bits dann auf 8 Bit-PWM übertragen.
Überlege mal, was es Dir bringt, das aufzugeben: Du sparst Dir die
aufwendige = "teure" Division.
> 40960 ist festgelegt durch meine Kalibrierspannung von 4096*10 (4.096V)
Trenne mal Spannungen und Werte, mit denen gerechnet wird.
Das ist ein wichtiger Abstraktionsschritt (den Du noch vollziehen
musst).
Der Mensch denkt dezimal, der µC rechnet binär und der ADC wandelt
ratiometrisch, genau wie die PWM.
Da der µC die Berechnung ausführt, ist es klug, die dezimale Denkweise
beim Programmieren aufzugeben.
> Die große Frage ist ob ein ein typecast von integer auf> (unsigned char ) auf -10 = 0 und aus 300 = 255 macht ? zb.
Beim AVR sicher nicht, bei einigen Signalprozessoren übrigens schon
(Saturation).
Es wird einfach das untere Byte genommen, d.h. 300 --> 300-256=44
Am besten, Du prüfst, welche Wertebereiche die Variablen in den
Extremfällen annehmen können und wie man die vorhandenen Bits aufteilt
und optimal ausnutzt.
Dann siehst Du auch, ob Du die Werte begrenzen musst.
Probier mal meinen Ansatz, und Du wirst sehen, man kann vieles anders
machen als man zuerst denkt. Das erweitert den Horizont.
Für Fragen / Hilfe stehe ich gerne zur Verfügung.
eProfi schrieb:> Soso, 14 Bits dann auf 8 Bit-PWM übertragen.> Überlege mal, was es Dir bringt, das aufzugeben: Du sparst Dir die> aufwendige = "teure" Division.
Ich brauche es deshalb da der ADC Wert noch mit dem 124Bus von Peter
Danneger weitergesendet wird. Und außerdem habe ich sonst nicht eine so
hohe Auflösung, da ich ja nur den Bereich 40000-41000 auf die PWM
umsetze.
> Trenne mal Spannungen und Werte, mit denen gerechnet wird.> Das ist ein wichtiger Abstraktionsschritt (den Du noch vollziehen> musst).
Ja das ist wahr, das heißt besser 4096*16 oder ?
>> Der Mensch denkt dezimal, der µC rechnet binär und der ADC wandelt> ratiometrisch, genau wie die PWM.>> Da der µC die Berechnung ausführt, ist es klug, die dezimale Denkweise> beim Programmieren aufzugeben.> Beim AVR sicher nicht, bei einigen Signalprozessoren übrigens schon> (Saturation).> Es wird einfach das untere Byte genommen, d.h. 300 --> 300-256=44
Ich habs grad überprüft, ja du hast natürlich recht, also voltage kann
werte von 25000-43000 annehmen, STARTWERT kann Werte von 3500-4200
annehmen.
Somit komm ich denke ich mal um die Abfrage <0 und >255 nicht herum.
Oder hab ich hier wieder eine falsche Denkweise?
>> Am besten, Du prüfst, welche Wertebereiche die Variablen in den> Extremfällen annehmen können und wie man die vorhandenen Bits aufteilt> und optimal ausnutzt.> Dann siehst Du auch, ob Du die Werte begrenzen musst.>> Probier mal meinen Ansatz, und Du wirst sehen, man kann vieles anders> machen als man zuerst denkt. Das erweitert den Horizont.>> Für Fragen / Hilfe stehe ich gerne zur Verfügung.
Rück doch mal bitte mit allen Infos raus.
> Ich habs grad überprüft, ja du hast natürlich recht, also voltage> kann werte von 25000-43000 annehmen, STARTWERT kann Werte von> 3500-4200 annehmen.
Du steckst immer noch tief in Deinem Programm.
Vergiß Deinen Ansatz mal für einen Augenblick.
Welche physikalische Größe wird gemessen?
Welchen Bereich hat die Eingangsspannung, wie ist die Referenzspannung?
Wird differentiell gemessen?
In welchem Bereich liegt der Wert kalibrierung?
Wiviel Bits sind notwenig?
Wie lautet die Abbildungsvorschrift?
Was passiert, wenn ADC 0 oder 1023 wird (Fehlerfall)?
Am besten hänge mal das ganze Projekt an.
Die Randbedingungen sind wichtig für das Finden einer optimalen Lösung.
Oversampling, ADC, resourcenschonend kann man auch so machen:
Beitrag "ADC und Fixed-Point Arithmetik"
Hast du mal überlegt ob du das Ganze durch shift operationen
vereinfachen kannst ?
eProfi schrieb:> Rück doch mal bitte mit allen Infos raus.>>> Ich habs grad überprüft, ja du hast natürlich recht, also voltage>> kann werte von 25000-43000 annehmen, STARTWERT kann Werte von>> 3500-4200 annehmen.> Du steckst immer noch tief in Deinem Programm.> Vergiß Deinen Ansatz mal für einen Augenblick.>> Welche physikalische Größe wird gemessen?
Spannung, über einen Spannungsteiler mit dem Verhältnis 1:0.225 in etwa
> Welchen Bereich hat die Eingangsspannung, wie ist die Referenzspannung?> Wird differentiell gemessen?> In welchem Bereich liegt der Wert kalibrierung?
ich kalibriere mit einer hochgenauen 4.096V Referenzspannungsquelle, der
Wert liegt also bei ca. 4.096*0,225 (Spannungsteiler ) / 1.05 (BGD
Referenz)= 900 als ADC ergebnis ( 10 - Bit )
> Wiviel Bits sind notwenig?
Ich hätte gern 14Bit, 12Bit wäre eventuell auch noch vertretbar, aber 14
wären schön.
> Wie lautet die Abbildungsvorschrift?
Was ist eine Abbilungsvorschrift?
> Was passiert, wenn ADC 0 oder 1023 wird (Fehlerfall)?
Nichts passiert, da der Wert ja gesendet wird, entscheidet der Master
was passiert.
>> Am besten hänge mal das ganze Projekt an.> Die Randbedingungen sind wichtig für das Finden einer optimalen Lösung.
So das .c File ist im Anhang.
Danke
Es mag sein, dass ich was nicht verstehe. Ich finde Deine Erklärung an
manchen Stellen unklar oder zu lakonisch. Ich verstehe z.B: den
Kalibrierwert und die Kalibrierspannung nicht, was aber auch an mir
liegen kann. Wahrscheinlich meinst Du mit dem Kalibrierwert einen
Faktor, der den Messfehler des AD-Wandlers gemessen am Ende des
Wertebereiches gemessen, ausgleichen soll. Dieser Wert wird im
allgemeinen recht nahe an 1 liegen und wird günstigerweise als Bruch
dargestellt.
Sei es wie es sei, vielleicht sind die folgenden Überlegungen für Dich
von Wert:
1. Du hast einen AD-Wandler der mit 10 Bit auflöst (also Wertebereich
0-1023)
2. Du willst einen Ergebniswert mit 8 Bit (also 0-255)
Nimmt man nur diese beiden Tatsachen, so solltest Du ohne Probleme mit
einem 16Bit Datentyp oder weniger auskommen. Soweit ist das ja, denke
ich auch klar.
Nun hast Du die Einschränkung, das Du den Wertebereich des AD-Wandlers
nicht ausnutzt. Du schreibst das Du in der 100uV Skalierung nur den
Bereich von 40000-41000 [100uV] ausnutzen willst.
Das ist ein Widerspruch, denn Du kommst ja mit der Referenzspannung von
4,096V maximal eben auf 40960 [100uV]. Das solltest Du bitte mal
erklären.
Rechnet man das mal aus, so kommt man darauf, das Dein zu nutzender
Bereich nur ca. ein 40stel des möglichen überstreicht. Damit verbleiben
etwa 4 bis 5 signifikante Bits des AD-Ergebnisses.
Daraus folgt zum einen, das Du maximal 8 bis 16 mal die Messung
wiederholen brauchst um die Auflösung wieder auf 8 Bit zu bringen.
Aber daraus folgt auch, das die Hardwareanschaltung an sich fehlerhaft,
zumindest aber mangelhaft ist. Du solltest schon die Anschaltung des
Gebers so gestalten, das der Wertebereich möglichst nahe an 8 Bit
herankommt. Manchmal ist das aus verschiedenen Gründen auch nicht
möglich. Schreib doch mal, was an dem AD-Wandler eigentlich
angeschlossen ist, bitte.
[Ich sehe gerade das Du das in einem späteren Post auf einen Bereich von
ca. einem 5tel korrigiert hast. Damit bleiben dann sogar 9 Bit). Die
AD-Wandlung brauchst Du dann garnicht zu wiederholen um die Auflösung zu
erhöhen oder die Anschaltung des Gebers zu ändern.]
Kommen wir nun zu den Berechnungen selbst. Es fällt auf, das Du im
Programm den AD-Wert in Spannungen in Volt umrechnest, dann Deinen
Offset für den nutzbaren Spannungsbereich in dieser Skala abziehst und
dann wieder dividieren musst.
Nun ist es aber sinnvoll, diese Berechnungen in der Volt-Skala erstmal
nur auf dem Papier anzustellen und diese als Ansatzpunkt zu nehmen
möglichst in den Skalen, wie sie vom AD-Wandler zurückgegeben werden
umzurechnen, damit Du weniger Wertebereich und auch weniger Berechnungen
brauchst. Das wird Dir schätzungsweise ungefähr 4 Bit an Wertebereich
einsparen, weil der Faktor 4096(0) pro Bit hier die Zwischenergebnisse
extrem aufbläht.
Dann ist es sinnvoll bei jedem Berechungsschritt zu überlegen was der
Wertebereich des Ergebnisses ist und die Reihenfolge so umzustellen, das
ein Limit von 8 oder 16 Bit nicht überschritten wird. Allgemein ist es
wegen der abgeschnittenen Bruchteile günstig Divisionen zuletzt
auszuführen.
Es wäre vielleicht hilfreich, wenn Du Deine Erklärung von 19.12.2010
00:44 durch vollständige Angaben von Wertebereich und Einheit ergänzt
sowie durch Angaben darüber wie sie sich entweder durch Hardware oder
Berechnungen ergeben haben.
Es mag sein, das ich hier etwas gründlicher vorgehen will, als
notwendig. Einige Antworter scheinen ja das Ganze nachvollziehen zu
können. Falls Dir diese mehr weiterhelfen, ignoriere mein Post hier
einfach.
Viel Erfolg.
Ich sehe gerade, das Du hier
>Ich hätte gern 14Bit, 12Bit wäre eventuell auch noch vertretbar, aber 14
wären schön.
wieder eine hohe Auflösung forderst.
Wozu aber 14 Bit Auflösung, wenn Dein Ergebnis, der OCR-Wert ohnehin nur
8 Bit hat und dein zu nutzender Teilwertebreich auch schon 8 Bit?
>Wie gesagt wird der Wert weggesendet!>Und dafür brauche ich eine höhere Auflösung, natürlich ist 14 Bit für>den 8-Bit Timer nicht sinnvoll
Oops. Das habe ich überlesen. Sorry.
Hallo eller,
ich habe festgestellt, dass teilen vom gcc nicht durch shifts ersetzt
wird, selbst wenn es sich um unsigned und vielfache von zwei handelt.
Warum weiß ich nicht, es gab mal einen religiösen thread dazu.
Also alle /4096 durch shifts ersetzen.
Schaust du dir eigentlich das *.lss file an? Da kannst du ziemlich genau
sehen, wie viele Operationen für deinen Quellcode gebraucht werden.
Deine C-Kommentare werden sogar mit geschleift.
Generell kann ich eProfis Ansatz bestätigen
Beitrag "Re: Möglichst Resourcenschonend programmieren" Zur Not alles in
eigenständige *.c und *.h Dateien stopfen, nur damit man nicht die
Übersicht verliert.
Komischerweise braucht das weniger Speicherplatz :
ocr = (((voltage-((unsigned long)BAL_START*10))*255)/1000);
als das:
ocr = ((voltage-(unsigned long)BAL_START*10)>>2);
und zwar braucht zweiteres um 20 Bytes mehr! Verstehen warum tu ich
allerdings nicht.
Hab gerade herausgefunden, dass das anscheinend daran liegt, dass er
Divisionen wohl mit einem Algorithmus macht, den er sowieso irgendwo im
Speicher liegen hat, aber shift-Operationen jedesmal komplett ausführt,
heißt also wohl shift ist schneller aber braucht im Endeffekt mehr
Speicher richtig?
eller schrieb:> heißt also wohl shift ist schneller aber braucht im Endeffekt mehr> Speicher richtig?
Wenn Du deine Divisionsroutinen im Code komplett sparen kannst, wird
Shiften auch weniger Speicher brauchen. Schneller ist das auf jeden
Fall.
Du hast recht, der Speicherplatz ist um etwa 9% weniger, wenn ich alle
Divisionen durch shift operationen ersetzt.
Die Frage ist nur wie ich dieses hier ersetzen könnte:
voltage=((result*40960)/bandgap);
jemand eine Idee?
Danke
Lg
Vielleicht nicht...
Ist eine frage der Aufgabenteilung.
Dein Tiny könnte doch die Regelung komplett mit dem Rohwert machen.
Warum sollte der andere Kontroller (der ansacheinend mehr Bums(tm) hat)
den übermittelten Rohwert nicht umwandeln ?
Entschuldige falls ich was überlesen habe !
Nein, das ginge natürlich schon!
Aber dann müsste ich 5 Bytes senden anstatt der bisherigen 3 Bytes, ist
hald ein erheblich höherer Zeitaufwand zusätzlich. Denn ich brauch ja 14
Bit von der kalibrierung, 14 Bit vom derzeitigen Messwert und ca. 6 Bit
für die Angabe der Zellennummer.
Außerdem brauch ich ja immernoch die umrechnung für die PWM, da die ja
auch die derzeitige Spannung braucht um zu wissen ab wann sie
einschalten muss.
Oder denk ich da gerade falsch?
Lg
voltage=(result*40960/kalibrierung);
ocr = (((voltage-((unsigned long)STARTWERT*10))*255)/1000);
Hmmm, warum ?
SARTWERT ist doch eine Konstante ?
Hänge doch mal btr. Code, Konstanten und definitionen an.
Es wird doch wohl möglich sein das ganze Sinnvoll auszulagern...
Nun erklär doch mal bitte warum Du, in wessen Namen auch immer, nur
unbedingt mit 40960 multiplizieren willst. Das ist Dir hier schon
zweimal gesagt worden:
Autor: Huch (Gast)
Datum: 19.12.2010 13:02
Nun ist es aber sinnvoll, diese Berechnungen in der Volt-Skala erstmal
nur auf dem Papier anzustellen und diese als Ansatzpunkt zu nehmen
möglichst in den Skalen, wie sie vom AD-Wandler zurückgegeben werden
umzurechnen, damit Du weniger Wertebereich und auch weniger Berechnungen
brauchst.
Autor: Thomas W. (wagneth)
Datum: 20.12.2010 21:00
>Dein Tiny könnte doch die Regelung komplett mit dem Rohwert machen.
Äh Du bist der mit dem riesen Akkupack ?!?
Kenne die Tinys nicht aber bandgap dürfte doch bekannt sein (2,56V) !?
Vielleicht wäre scharfes nachdenken über die Aufgabe besser... ?
Habe Deine Akkus überhaupt genug rauschen für oversampling ?
Ja du kennst die Tinys nicht - > Bandgap ist zw. 0.95 und 1.05V
scharfes Nachdenken ? tu ich doch eh, aber ich wüsste dennoch nicht, wie
ich die Divison hier durch shift oder sonstiges ersetzen könnte.
Das ganze System hat genug Eigenrauschen ja
40960 / 0,95 = 43115
40960 / 1,05 = 39010
Wie kalibrierst Du die Bandgap ref ?
Nach meinem Blick ins DBL scheint es zu lügen.
Dort steht min/typ/max 1,0 / 1.1 / 1.2 V !?!?
---
Wieviel braucht delay.h ?
Das lässt sich doch bestimmt mit in einen Timer verpacken !
In der ISR eine Variable nach belieben hoch/runterlaufen lassen.
Variable auf Startwert.
Warten bis Wert erreicht.
Kostet eine Variable 16bit, inkrement und Abfrage in der ISR, Abfrage am
Ort des Geschehens.
---
Thomas W. schrieb:> 40960 / 0,95 = 43115> 40960 / 1,05 = 39010>> Wie kalibrierst Du die Bandgap ref ?
Ich lege als Versorgungsspannung 4.096V an, der Wert den er für die ADC
Messung erhält, speichert er im EEPROM
>> ---> Wieviel braucht delay.h ?> Das lässt sich doch bestimmt mit in einen Timer verpacken !>> In der ISR eine Variable nach belieben hoch/runterlaufen lassen.> Variable auf Startwert.> Warten bis Wert erreicht.>> Kostet eine Variable 16bit, inkrement und Abfrage in der ISR, Abfrage am> Ort des Geschehens.>> ---
Naja, da ich das fast nie brauche, sollte es reichen wenn ich einfach
das mach:
for(uint32_t i=48000000;i>0;i--)
asm("nop");
Bräuchte hald 32 Bit hierfür. Oder?
Thomas W. schrieb:> Nach meinem Blick ins DBL scheint es zu lügen.> Dort steht min/typ/max 1,0 / 1.1 / 1.2 V !?!?
Laut der Kennlinien die weiter unten zu finden sind, ist es eher im
Bereich 0.95-1.05V je nach Vcc und Temperatur
Ich hatte dir ja schon einen Link gesetzt aber ich weiß nicht genau was
du da eigentlich messen willst. Riesenakku ? Kannst du nicht einfach mal
die Aufgabe beschreiben ? für mich bist du immer noch auf dem Holzweg da
du dich zu sehr auf DEINE Lösung konzentrierst.
Ich habe den ganzen Thread gelesen aber verstehe immer noch nicht. Wird
hier ein Zellenverbund oder eine Einzelzelle vermessen ? 14 BIT ? 4096
??? paßt für mich auch nicht.
Strukturiere doch mal Dein Programm nach dem Problem/Aufgabe.
Ich würde garnicht den Absolutwert der Zelle übertragen,
nur die Abweichung.
Genau diese und nur diese Abweichung interessiert Dich doch auch für die
PWM !?
Das verhindert vielleicht nicht diese eine Division,
macht das ganze aber wesentlich schöner/einfacher.
Wobei man die dann vielleicht noch schöner machen könnte.
Bei der ganzen Manpower die hier versucht hat zu helfen hätten wir das
nebenbei erleidigen können ;)
@ Bernd:
Ich weiss es nicht ob er es ist, aber : Vor einiger Zeit hat jemand nach
Einer Akkuüberwachung, Balancing etc. für zusammengesetzten Li** - Akkus
gefragt.
Lösung war glaube ich einen Tiny pro Zelle und das ganze in einer Art
von TokenRing galvanisch isoliert zu vernetzen.
Hallo Thomas,
sollte dem so sein dann verstehe ich die ganze Diskussion nicht. Selbst
wenn er auf 1mV pro Zelle auflösen möchte und den Wert dann per UART
übetragen will dann braucht er nur dem Link zu folgen. 600 Byte
inclusive UART und dann noch die PWM ableiten... alos ~ 800 Byte sollte
zu schaffen sein.
Ich hätte lieber eine exakte Aufgabenbeschreibung und dann das Problem
durchdenken statt an dem vorhandenen Code zu arbeiten. Desweiteren
reichen dann 12 BIT völlig. Egal was er an einer Zelle messen /
überwachen will (vermutlich irgendein Delta), 12 BIT reichen da aus es
sei denn es gibt noch einen Grund den ich nicht verstehe.
Ja es geht darum große Akku Packs zu überwachen und zusätzlich soll die
Momentanspannung jeder Zelle an einen Hauptrechner gesendet werden
allerdings per 124Bus und nicht per UART
Daher möchte ich die Gesamtspannung wegsenden.
Ja das bin ich, ich habe nur den Thread leider nicht mehr auffinden
können.
Funktionieren tut das Programm problemlos, nur wärs hald schön wenn
vielleicht noch Platz übrig bliebe, wenn nicht, ist es auch nicht so
schlimm.
Das einzige was das Hauptsächliche Programm zu machen hat ist die
kalibrierungsroutine, um den Spannungsteiler und die BGD die ja nicht
immer ganz exakt sind, abgleichen zu können.
Danach muss er nur die PWM steuern und die Momentanspannung
weitersenden, das ist eigentlich die Aufgabe des ganzen.
Eine Auflösung von zumindest 1mV wäre hald schön, und dies erfordert
doch kaum recht viel mehr Speicher denk ich mal, denn ob 10Bit oder
14Bit ich brauch sowieso ne 16Bit variable, das einzige, die Schleife
und das addieren und schiften kommt hinzu.
Was die Frage des rauschens anbelangt hab ich bei den Messungen
festgestellt das dies ausreicht und mit der Auflösungserweiterung auf 14
Bit sehr gut funktioniert.
Danke schonmal für eure Hilfe.
Lg
@ Bernd:
Ach lässt sich Dein Source schön leicht lesen !
Ich denke er hat keinen Bock an 50 (oder wieviele auch immer) jeweils
den ADC/BandgapRef auszumessen und jeweils zu (hard) codieren.
Wobei da die Faulheit doch eher nach einer Konfiguration per
Protokoll/EEPROM über den Master schreit (Werte natürlich
vorausberechnet).
Das wäre dann schon richtig gut :)
(Im moment scheint er es beim kontaktieren+Taste drücken machen zu
wollen.)
Ich vermisse irgendwie noch einen Temperatursensor.
Den ganzen Li** Akkus vertraue ich keinen cm...
>> Ich denke er hat keinen Bock an 50 (oder wieviele auch immer) jeweils>> den ADC/BandgapRef auszumessen und jeweils zu (hard) codieren.
Das geht auch per Autokalibrierung, ich messe auch keine Bandgap sondern
2 Referenzpunkte. Alles andere ist eine einfache Berechnung.
Bei sehr viel Luxus brauchts dann eben doch mehr als 1k. Die Wunschlos
Glücklich Version kann ich für einen 2k Chip liefern :-)
Bernd N schrieb:>>> Ich denke er hat keinen Bock an 50 (oder wieviele auch immer) jeweils>>> den ADC/BandgapRef auszumessen und jeweils zu (hard) codieren.>> Das geht auch per Autokalibrierung, ich messe auch keine Bandgap sondern> 2 Referenzpunkte. Alles andere ist eine einfache Berechnung.>> Bei sehr viel Luxus brauchts dann eben doch mehr als 1k. Die Wunschlos> Glücklich Version kann ich für einen 2k Chip liefern :-)
Ich hab kein Problem damit 50 der Attinys dann zu kalibrieren!
Was meinst du mit Auto kalibrierung?
Das kalibrieren geht doch recht flott, Board an die 4.096V
Spannungsquelle, PB3 auf Masse schließen, 5 sekunden warten, fertig.
Und wie ist die Konfiguration über den Master gemeint?
Lg
y=mx+c
Ist schon klar.
(Abweichung von der Linearität und Stufen abgesehen)
Ich dachte er will nur so wenig wie möglich in den nodes machen.
Ich schätze mal das er sowieso mit einem Fehler(U,theta) von 0,25V/2
messen wird.
Soll ja bei den EisenPhosphat dingern nicht so schlimm sein.
Richtig, die LiFePo4 sind da nicht so, die explodieren auch ned gleich.
Der Temperaturfehler ist nicht so schlimm für mich, da sich auch die
Akkus bei tieferen bzw. höheren Temperaturen anders Verhalten
@ eller,
>> Was meinst du mit Auto kalibrierung?
Du willst resourcenschonend einen Meßwert erfassen ? bist du dem Link
gefolgt ? es geht kaum resourcenschoenender und es wird nur "geshifted".
Paß den Code auf deine Gegebenheiten an und versuchs ob es für dich was
ist.
Ich bin dem Link gefolgt, und hab die shift operationen doch eingebaut,
und mein Programm ist an meine Gegebenheiten angepasst. Da aber
immernoch eine Division vorkommt, bringt das ganze shiften nichts.
Ja, deine Division durch Bandgap würde entfallen wenn du deine Idee
verwerfen würdest. Das ist es was ich meine. Sei mir nicht böse aber mir
fällt es schwer deiner Grundidee zu folgen. Alles was du brauchst steht
in dem Link und ich bin mir sicher das du es für deine Anwendung einfach
übernehmen kannst.
Forderung ist doch auf 1mV Auflösung zu kommen und dann deinen Code für
die weitere Verarbeitung... vielleicht bin ich auch zu doof zu verstehen
:-)
Meine Güte:
Der Faktor wird eine Zahl nahe eins sein. Klar?
Er lässt sich als gebrochen rationale Zahl darstellen. Klar?
Sei der Faktor f = a/b.
b wird wahrscheinlich auf Anhieb keine Zweierpotenz sein. Klar?
Wie muss man den Bruch verändern, damit b eine Zweierpotenz ist?
Das ist so ungefähr fünfte Klasse Elementarmathematik. Das wirst Du doch
wohl hinbekommen?
Bernd N schrieb:> Ja, deine Division durch Bandgap würde entfallen wenn du deine Idee> verwerfen würdest. Das ist es was ich meine. Sei mir nicht böse aber mir> fällt es schwer deiner Grundidee zu folgen. Alles was du brauchst steht> in dem Link und ich bin mir sicher das du es für deine Anwendung einfach> übernehmen kannst.>> Forderung ist doch auf 1mV Auflösung zu kommen und dann deinen Code für> die weitere Verarbeitung... vielleicht bin ich auch zu doof zu verstehen> :-)
Also er macht doch auch hier eine division:
1
return((((AvgSum>>5)*Factor)+Offset)/Scale);
Und außerdem, braucht er ja 2 Testpunkte, was nicht viel Sinn ergibt,
meines erachtens.
Bernd N schrieb:> Originalcode von mir...> uint16_t getAdcValue (void)> {> uint16_t AvgCount = 0;> uint32_t AvgSum = 0;>> for (AvgCount = 0; AvgCount < 512; AvgCount ++) {> ADCSRA |= (1 << ADSC); // AD Wandler
starten
> while (ADCSRA & (1 << ADSC)); // AD Wandlung
fertig ?
> AvgSum += ADC; // Mittelwert
über 512 Messungen
> }> return ((((AvgSum >> 7) * Factor) + Offset) >> 16); // skaliert
auf 12 BIT
> }>> nicht die diskutierten Varianten... im originalen Code wird nur> geshifted.
Danke für den Code
Ja hiermit könnte ich die Division umgehen, allerdings muss ich so jedem
Attiny ein eigenes Programm mit seinem kalibrierten Werten einspielen
mit Factor und Offset, oder?
Ich würde vermuten das du nur einmal durch die Kalibreierung mußt denn
allzusehr werden die nicht streuen (wenn aus der gleichen Charge). Ich
verwende, wie gesagt, eine Autokalibrierung aber denn wird es etwas mehr
Code.
Vorteil dieser Version, sehr effektiver Code und alle linearen Fehler
sind heraus. Du erhältst Meßergebnisse die wirklich genau sind und deine
gewünschte Auflösung von 1mV ist garantiert. In deinem Fall liegen die
Verhältnisse eher noch günstiger da UREF ~ 1V, bei 12 BIT bist du sogar
bei einem 1/2 mV.
Wie gesagt, probier halt ob es für dich paßt. Das kannst nur du
entscheiden. Wenn möglich dann poste mal deinen überarbeiteten Code und
dann schaun wir weiter.
Danke Bernd!
Die Autokalibrierung machst du wie ? mit den zwei Referenzspannungen die
du misst, und die du dann in die .h schreibst oder wie? Das hab ich noch
nicht ganz verstanden, und wieso ist das besser als einfach nur eine
4.096V Als Quelle dran zu hängen und diesen Wert als Referenz zu nehmen?
Genau so schauts aus.
Kennst Du zwei punkte auf einer gerade, kannst Du alle anderen auf
dieser inter und extrapolieren.
Lineare Algebra, y=m*x+c
MeinDing (TM) wäre nun wie weiter oben beschrieben Allen zu sagen bitte
die Kalibrierwerte zum Master senden.
Der Rechnet und schickt dir Korrekturgrössen an die einzelnen Nodes die
wiederum die Daten im EEPROM ablegen.
My Thought.
Du gehst davon aus das Deine Gerade eine UIrsprungsgerade ist (geht
durch 0/0).
Das Macht Bernds nicht.
In Kombination wirst Du mehrere Fehler haben :
- Offset
- Linearität
- irgendwelche Treppen, nichtlinearitäten.... Die allerdings noch drin
bleiben und recht gering aufallen dürften.
Ja, die Kalibrierung mache ich über 2 Stützpunkte. Also noch einmal
ausführlich.
1
uint16_tgetAdcValue(void)
2
{
3
uint16_tAvgCount=0;
4
uint32_tAvgSum=0;
5
6
for(AvgCount=0;AvgCount<512;AvgCount++){
7
ADCSRA|=(1<<ADSC);// AD Wandler starten
8
while(ADCSRA&(1<<ADSC));// AD Wandlung fertig ?
9
AvgSum+=ADC;// Mittelwert über 512 Messungen
10
}
11
return(AvgSum>>7);// skaliert auf 12 BIT
12
}
Du verwendest diesen Konstrukt und läßt dir den Wert für für die 2
Referenzpunkte ausgeben. In deinem Fall z.B. 1V und 100 mV.
In meinem Fall war es:
1
#define AdcRawH 3206 // Stützpunkt 2.00 Volt
2
#define AdcRawL 605 // Stützpunkt 0.40 Volt
>> und wieso ist das besser...
Weil es keinen idealen Wandler gibt und du somit alle linearen Fehler
sowie Offset und Gain bereits korrigiert hast. Deine Forderung war eine
Messung auf 1mV genau... meine Erwartungshaltung wäre, wenn ich ein DVM
nehme und die ADC Messung prüfe dann sollte das Ergebnis identisch sein.
Das ist bei deinem derzeitigen Code überhaupt nicht der Fall. Was nutzt
dir die Referenz wenns trotzdem ungenau wird ? :-)
Bei diesem Verfahren machst du einmal eine Kalibrierung und gut ist.
Natürlich kann die auch automatisch erfolgen (siehe Link).
Hier ein Beispiel für einen Wandler mit VREF 0,6 V (MSP430F2013)
1
// Referenzpunkte Abgeglichen mit DMM Fluke 87 III
Ok danke !
Das versteh ich soweit, das heißt ich könnte einerseits zb. mit einer
4.096V Referenz messen und dann mit einer 2.048V und dies für die beiden
Punkte verwenden ? Denn die Spannung der Zellen liegt für gewöhnlich
genau dazwischen.
Thomas W. schrieb:> MeinDing (TM) wäre nun wie weiter oben beschrieben Allen zu sagen bitte> die Kalibrierwerte zum Master senden.>> Der Rechnet und schickt dir Korrekturgrössen an die einzelnen Nodes die> wiederum die Daten im EEPROM ablegen.>> My Thought.
Was heißt die Kalibrierwerte zum Master senden, du meinst also ich leg
an alle 4.096V an und die sollen mal an den Master senden, welchen ADC
Wert sie dafür erhalten, danach leg ich 2.048V an, und sie senden wieder
den ADC Wert den sie dafür erhalten.
Der Master rechnet dann für jeden einzelnen zurück auf den
Korrekturfaktor für Linearität und Faktor, und sendet das den einzelnen
µCs wieder die das dann in den EEPROM speichern?
Klar, kannst du so machen und der Vorschlag von Thomas hat auch einen
gewissen Charme. Der Master kann auch auf Plausibilität prüfen und und
und. Aber mach mal den ersten Schritt (Ideen habe ich auch noch einige
:-)).
Hört sich auf alle Fälle schonmal sehr gut an, lieber wär mir
allerdings, wenn das in jedem µC selbst gespeichert ist, da würde ich
vielleicht sogar in kauf nehmen, dass ich jeden einzeln kalibriere, das
würde das Programm noch einfacher, schneller machen und bräuchte dazu
noch weniger Speicher und ist genauer. Bei Thomas variante, hab ich
wieder einiges an Code, dass er das vom Master empfängt und im EEPROM
speichert etc.
Genau,
so ein System muss sich Schritt für Schritt entwickeln.
Jede Lösung die Du verwendest ist ein Kompromiss der in die eine oder
andere Richtung neigt.
Das Ganze zu Zentralisieren spart dir ev. Taster oder Jumper ein...
Bläst aber die Kommunikation auf.
Ev. wirst Du die noch für was anderes Brauchen ?!
Dann würde es wieder Sinn machen.
---
Ich denke Dir würde auch ein int_8 reichen um den Spannungswert zum
Master zu übertragen...
naja, gerade der Master soll eine möglichst genaue Spannung bekommen,
deshalb die 16 Bit
Die neue .c im Anhang.
Ich weiß nicht ganz ob ich es verstanden habe, aber so denke ich passt
das ?
Hallo Bernd!
Ich hab mir das nochmals angeschaut, weiß aber nicht worans hakt.
Das einzige was mir einfällt ist, dass ich getAdcValue() nicht einfach
als voltage annehmen kann, aber die Berechnung stimmt doch oder nicht?
Lg
So, ich nehme mir noch einmal Zeit für dein Thema. Vergiß mal die 14 BIT
und überleg mal. Du hast einen AD Wandler mit 10 BIT und eine interne
VREF von ~ 1V.
1V / 1024 = 0,0009765625V => ~ sagen wir 1mV. Du kannst also mit den 10
BIT 0 - 1.000V darstellen.
Der Bereich der dich interessiert ist (wenn ich es richtig verstanden
habe) 3.901V - 4.096 !?!? sagen wir 0 - 5.000V !?!?
Also spielen wir mal DVM und schalten auf den nächsten Bereich => /10.
Somit kannst du nun 0 - 10.00V darstellen oder ? Also fehlt dir eine
Stelle.
Rechnen wir also mit 14 BIT. 1V / 4096 = 0,000244140625V => ~ 250uVolt.
Wir verwenden den nächsten Meßbereich, wie schon zuvor, und können somit
0 - 10.000V darstellen nur deine letzte Stelle springt um 2 Stellen
respektive die Auflösung reicht nicht ganz. Wie dem auch sei, wir
bestimmen nun unseren Spannungsteiler selbst und stellen 0 - 5.000V dar
und schon gehts mit 12 BIT. Frage, wie muß der Spannungsteiler aussehen
?
Erfolgreich kompakten Code zu schreiben heißt auch sich möglichst genau
mit den Gegebenheiten auseinanderzusetzen.
Warum nicht 14 BIT ? weil du die eh nicht hinbekommst. Hierzu bräuchtest
du noch eine Rauschquelle (lese dir mal die App. Notes durch). Für 2 BIT
mehr sind die ADC's, der AVR Serie, gut.
Jetzt zu deinem Problem. Du brauchst ein Wertepaar Delta U / Delta ADC.
Darauf basiert ja das Ganze. Ich sehe bei dir kein Delta. Andersherum
gefragt:
1. welchen ADC Rohwert erhälts du wenn am ADC Eingang 900mV anliegt und
du ein Oversampling von 12 BIT verwendest ? Wert notieren und merken.
2. Welchen ADC Rohwert erhälts du wenn am ADC Eingang 100mV anliegt und
du ein Oversampling von 12 BIT verwendest ?
Mit diesem Wertepaar stellst du deine Gleichung auf.
Habe ich noch was übersehen ?
Hast du mal eine Skizze der Schaltung ?
Bernd N schrieb:> So, ich nehme mir noch einmal Zeit für dein Thema. Vergiß mal die 14 BIT> und überleg mal. Du hast einen AD Wandler mit 10 BIT und eine interne> VREF von ~ 1V.>> 1V / 1024 = 0,0009765625V => ~ sagen wir 1mV. Du kannst also mit den 10> BIT 0 - 1.000V darstellen.>> Der Bereich der dich interessiert ist (wenn ich es richtig verstanden> habe) 3.901V - 4.096 !?!? sagen wir 0 - 5.000V !?!?
Ja sind gute 0-4.300V die ich brauch
> Also spielen wir mal DVM und schalten auf den nächsten Bereich => /10.> Somit kannst du nun 0 - 10.00V darstellen oder ? Also fehlt dir eine> Stelle.>> Rechnen wir also mit 14 BIT. 1V / 4096 = 0,000244140625V => ~ 250uVolt.> Wir verwenden den nächsten Meßbereich, wie schon zuvor, und können somit> 0 - 10.000V darstellen nur deine letzte Stelle springt um 2 Stellen> respektive die Auflösung reicht nicht ganz. Wie dem auch sei, wir> bestimmen nun unseren Spannungsteiler selbst und stellen 0 - 5.000V dar> und schon gehts mit 12 BIT. Frage, wie muß der Spannungsteiler aussehen> ?
Ich hab den Spannungsteiler mit 0.225 angenommen, heißt 6k2 und 1k8.
> Erfolgreich kompakten Code zu schreiben heißt auch sich möglichst genau> mit den Gegebenheiten auseinanderzusetzen.>> Warum nicht 14 BIT ? weil du die eh nicht hinbekommst. Hierzu bräuchtest> du noch eine Rauschquelle (lese dir mal die App. Notes durch). Für 2 BIT> mehr sind die ADC's, der AVR Serie, gut.>> Jetzt zu deinem Problem. Du brauchst ein Wertepaar Delta U / Delta ADC.> Darauf basiert ja das Ganze. Ich sehe bei dir kein Delta. Andersherum> gefragt:> 1. welchen ADC Rohwert erhälts du wenn am ADC Eingang 900mV anliegt und> du ein Oversampling von 12 BIT verwendest ? Wert notieren und merken.
921,6 ( wenn BGD = 1V )
> 2. Welchen ADC Rohwert erhälts du wenn am ADC Eingang 100mV anliegt und> du ein Oversampling von 12 BIT verwendest ?
102,4 ( wenn BGD = 1V )
> Mit diesem Wertepaar stellst du deine Gleichung auf.
Steigung ist somit 800mV/819,2 = 0,9765625
Faktor zu multiplizieren bei 12Bit ist also
0,9765625 * 4096 = 4000
So muss ich mir das ausrechnen oder?
Danach natürlich statt 921,6 den tatsächlich erhaltenen Wert, und statt
102,4 den tatsächlich erhaltenen Wert.
Der Faktor mit dem ich Multiplizieren muss sollte also
> Habe ich noch was übersehen ?
Nein, aber ich denke ich mal?
> Hast du mal eine Skizze der Schaltung ?
Im Anhang !
Hi eller,
schön, dass du gut vorankommst.
Noch ein Vorschlag von mir: Hast du schon einmal versucht, nur die Daten
zu übertragen? Also dein ADCH + ADCL? Das wäre in meinen Augen schon
einmal ein Ansatz. Das Teilen kann ja tatsächlich der server / master
übernehmen. Es wäre interessant zu wissen, was dabei heraus kommt.
Übrigens gibt es einen Unterschied zwischen Auflösung und Genauigkeit.
Du benötigst nicht mehr als 50mV Genauigkeit, schätze ich. Die Auflösung
kann dafür auf die 1mV zugehen.
Übrigens werde ich dein Projekt aus aktuellem Anlaß nachbauen. Natürlich
erst, nachdem du fertig bist und mit kleinen attiny25 :)
naja, ich bräuchte natürlich mehr Bytes zum übertragen!
Ich muss ja auch die kalibrierung übertragen.
Der Unterschied zwischen Auflösung und Genauigkeit ist mir klar, hab
versucht immer Auflösung zu schreiben ;) Ich hoffe ich hab mich nie
verschrieben :)
Wegen BD139, den hab ich nurmal so reingegeben, muss ich mir erst
anschauen was ich tatsächlich verwende, hat aber momentan noch keine
Auswirkungen auf das Programm.
Wer ab und zu meine Posts ließt, weiß, dass ich geduldig und hilfsbereit
bin. Was Du hier veranstaltest, gefällt mir aber gar nicht:
Ist es denn so schwer, im ersten Post zu sagen:
Ich will ein LiPo-Balancer bauen für soundsoviel Zellen, der nebenbei
einem Master über einen 124Bus die kalibrierten Spannungen übertragen
soll.
Das Balancing soll über den PWM-Ausgang erfolgen. Kompletter Code im
Anhang.
So ist in vier Zeilen das wichtigste gesagt.
Stattdessen lässt Du die Leute hier herumraten und wertvolle Zeit
vergeuden.
Außerdem behaupte ich mal, dass Du schwer von Begriff bist. Schon
mehrfach wurde auf andere elegantere Lösungswege hingewiesen, und Du
klebst an Deinem Entwurf fest.
Nochmal meine Lösung zum mitschreiben:
Du legst Deine 4,096V an, dann lässt Du den Wandler sooft wandeln, bis
die Summe 4096*256 oder 4096*4*256 (12Bit) oder 4096*16*256 (14 Bit)
oder vomn mir aus 40960*256 ist (dabei lässt Du das untere Byte unter
den Tisch fallen).
Die Anzahl der benötigten Wandlungen ist Dein Kalibrierwert, den merkst
Du Dir im Eprom. FERTIG.
Zum Messen summierst Du genausooft wie beim Kalibrieren, ignorierst das
untere Byte und berechnest den PWM-Wert. FERTIG.
Dafür brauchst Du keine Division und maximal eine Multiplikation.
Den Kalibrierwert würde ich auswerten, z.B. dass er in einem gewissen
Bereich liegen muss, sonst hellhörig werden, ob z.B. der Spannungsteiler
nicht stimmt.
> Ja das bin ich, ich habe nur den Thread leider nicht mehr> auffinden können.
Komisch, dass ich den Thread in 2 Minuten fand:
Kommt davon, wenn man sich zuerst Manuel und dann eller nennt.
Beitrag "40 Spannungen einlesen und an AtMega8 übertragen"
An Bernd: statt
for (AvgCount = 0; AvgCount < 512; AvgCount ++) {
schreibt man besser, kürzer und schneller:
avgCnt=512;do{
...}
while(--avgCnt);
Denn: es muss nicht VOR jedem Schleifendurchlauf mit 512 verglichen
werden, der Vergleich mit 0 kommt kostenlos im Zero-Flag, nachdem der
DEC-Befehl ausgeführt wurde.
Wenn man wie Manuel/eller eine Schleife 256 mal durchlaufen lassen und
nur ein uint8_t verwenden will, muss man den Startwert nicht auf 255,
sondern auf 0 setzen!
So, genug Frust abgeladen. Tut mir leid.
Hallo eProfi,
es gibt keinen Spannungsteiler. Es wird die interne Bandgab spannung
gemessen und mit der Versorgungsspannung verglichen. Wir müssen alle
sparen :)
> Ja das bin ich, ich habe nur den Thread leider nicht mehr> auffinden können.
Komisch, dass ich den Thread in 2 Minuten fand:
Kommt davon, wenn man sich zuerst Manuel und dann eller nennt.
Beitrag "40 Spannungen einlesen und an AtMega8 übertragen"
^--- Wenn ich so das ende lese könnt ich kotzen und mir in den Arsch
beissen nicht früher aufgehört zu haben !
Thomas W. schrieb:>> Ja das bin ich, ich habe nur den Thread leider nicht mehr>> auffinden können.> Komisch, dass ich den Thread in 2 Minuten fand:> Kommt davon, wenn man sich zuerst Manuel und dann eller nennt.> Beitrag "40 Spannungen einlesen und an AtMega8 übertragen">> ^--- Wenn ich so das ende lese könnt ich kotzen und mir in den Arsch> beissen nicht früher aufgehört zu haben !
Was passt denn nun wieder nicht ?
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Ich darf nicht Antworten.
Brauchte mal ne Pause... was ist denn hier los ?
>> 921,6 ( wenn BGD = 1V )>> 102,4 ( wenn BGD = 1V )
???
Bei 900 mV solltest du bei 12 BIT einen RawWert von ~ 3800 haben und bei
100mV sagen wir mal 800, das ist dein DeltaU/Delta ADC.
Ich würde einen SpgsTeiler /10 verwenden und den endgültigen Meßwert
noch einmal schieben => /2 dann bist du die leidige "5" los. Hast du es
jetzt verstanden ???
Bernd N schrieb:> Brauchte mal ne Pause... was ist denn hier los ?>>>> 921,6 ( wenn BGD = 1V )>>> 102,4 ( wenn BGD = 1V )>> ???> Bei 900 mV solltest du bei 12 BIT einen RawWert von ~ 3800 haben und bei> 100mV sagen wir mal 800, das ist dein DeltaU/Delta ADC.>> Ich würde einen SpgsTeiler /10 verwenden und den endgültigen Meßwert> noch einmal schieben => /2 dann bist du die leidige "5" los. Hast du es> jetzt verstanden ???
Sorry ja, hab jetzt nur den tatsächlichen Wert ohne den 12-Bit genommen.
Aber wenn ich nen 1/10 Spannungsteiler hab, verlier ich doch beinahe
100% Genauigkeit.
Ja im prinzip hab ichs verstanden.
@ eller (Gast)
>Sorry ja, hab jetzt nur den tatsächlichen Wert ohne den 12-Bit genommen.>Aber wenn ich nen 1/10 Spannungsteiler hab, verlier ich doch beinahe>100% Genauigkeit.>Ja im prinzip hab ichs verstanden.
GAAAAANZ sicher . . .
Falk Brunner schrieb:> @ eller (Gast)>>>Sorry ja, hab jetzt nur den tatsächlichen Wert ohne den 12-Bit genommen.>>>Aber wenn ich nen 1/10 Spannungsteiler hab, verlier ich doch beinahe>>100% Genauigkeit.>>>Ja im prinzip hab ichs verstanden.>> GAAAAANZ sicher . . .
Nein, was ist noch mal ein Mikrocontroller?
Aus dem Datenblatt
10-bit Resolution
0.5 LSB Integral Non-linearity
± 2 LSB Absolute Accuracy
und durch Oversampling kommen da plötzlich 14 Bit heraus ?
warum den nicht gleich 16 ;)
Der Ad Wandler wandelt auch bei Oversampling nicht besser er mittelt nur
den Dreck, den du dir auf der Leitung und durch den Controller selbst
einfängst.
Deshalb bekommst du auch Zwischenwerte.
Hallo ja das Prinzip von Oversampling ist mir eh klar, dass da ein
gewisses rauschen sein muss damit es überhaupt funktioniert, deshalb
wende ich das ja auch an!
Danke jetzt weiss ich was ein mC ist :) und ich dachte schon, da wo der
rauch rauskommt das kann man essen?
zweifler:
Naja der Beitrag war etwas sinnlos, finde es in gewisser Weise ein wenig
unverschämt, zu sagen ich kenn mich bei garnichts aus.
Entschuldigung an alle die meinen, ich habe sie in irgendeiner Art
beleidigt, oder so.
Hallo!
Ich bin noch am grübeln.
Irgendwas passt an der Scale berechnung nicht, denn so wäre der RefA
Punkt, der maximal Punkt für die Messung, heißt also wenn RefA 4.096V
gemessen ist, kann ich nie über 4.096V messen, da ich sonst über 12-Bit
( oder 14-bit ) komme.
Denn angenommen bei 13-Bit hab ich ein Delta U von 2048mV, oberer
Messwert ist für 4096mV 14000 und bei 2048mV sind es 7000, ist
deltaU/deltaADC = 0,293
zur Basis 2^14 macht das dann 4793,5
hab ich dann also einen Messwert von 1024 ( RohADCWert ) auf 14-Bit also
16384 * Factor und danach 12 mal geshiftet ergibt 19174. Ist aso
außerhalb von 14-Bit, ich hab also irgendwo einen denkfehler drin?
Lg
Kannst du mal beschreiben wie du vorgegangen bist ? ich kann deine
Gedanken beim besten Willen nicht nachvollziehen.
Du hast da einiges an Verständnisschwierigkeiten und sei mir nicht böse,
probier die Dinge zunächst mal aus. Du willst ja schließlich etwas
lernen. Ich hab das Gefühl das du sehr stark in deinem eigenen
Denkansatz gefangen bist und daher dein Blick für Vorschläge etwas
getrübt ist :-) Wenn du nah vor einem Mosaik stehst dann siehst du
Farbklekse, wenn du Abstand nimmst entsteht erst das ganze Bild.
Verwende doch zunächst das Original und probier es aus. Über Details
kann man dann immer noch diskutieren. Das 14 BIT keinen Sinn machen
solltest du aber langsam einsehen. Wenn ich deinen Schaltplan so
betrachte dann ist das auch kein Aushängeschild.
Keine Ahnung warum der Thread hier entglitten ist aber wenn du immer
noch interesse am Lernen hast dann können wir das durchaus zu Ende
diskutieren.
Bernd N schrieb:> Kannst du mal beschreiben wie du vorgegangen bist ? ich kann deine> Gedanken beim besten Willen nicht nachvollziehen.>> Du hast da einiges an Verständnisschwierigkeiten und sei mir nicht böse,> probier die Dinge zunächst mal aus. Du willst ja schließlich etwas> lernen. Ich hab das Gefühl das du sehr stark in deinem eigenen> Denkansatz gefangen bist und daher dein Blick für Vorschläge etwas> getrübt ist :-) Wenn du nah vor einem Mosaik stehst dann siehst du> Farbklekse, wenn du Abstand nimmst entsteht erst das ganze Bild.>> Verwende doch zunächst das Original und probier es aus. Über Details> kann man dann immer noch diskutieren. Das 14 BIT keinen Sinn machen> solltest du aber langsam einsehen. Wenn ich deinen Schaltplan so> betrachte dann ist das auch kein Aushängeschild.>> Keine Ahnung warum der Thread hier entglitten ist aber wenn du immer> noch interesse am Lernen hast dann können wir das durchaus zu Ende> diskutieren.
Hallo!
natürlich hab ich noch Interesse am Lernen, um das geht es ja.
Ja anscheinend verstehe ich es wirklich nicht ganz, 14-Bit hab ich
einfach nur so angenommen, es ändert nichts ob ich 10-Bit nehme, das
funktioniert irgendwie so nicht.
Ich habe RefA = 4096mV
RefB= 2048mV
ADC (bei 4096mV) = 900
ADC (bei 2048mV) = 450
Scale = 1024 ( 10-Bit )
Factor = delta U / delta ADC *Scale = 2048mV/450 * 1024
>> ADC (bei 4096mV) = 900>> ADC (bei 2048mV) = 450
Dein ADC Eingang zeigt bei 1V Eingangspannung 1023 bzw. 4096, wie kommst
du auf diese Werte ? Mach doch mal das was man dir sagt. Viel weiter
oben hatte ich es dir doch erklärt wie du vorgehst !?!?
Leider kein feedback mehr, aufgegeben ? Ich habe die Formel mal ein
bischen umgebaut und ich hoffe das es nun leichter ist es zu verstehen.
Das folgende Beispiel verwendet das gleiche Prinzip für eine 4-20 mA
Messung bei 14 BIT. Der Wandler hat einen Eingangsspannungsbereich von
0 - 0.6V.
Am Meßwiderstand ergibt sich eine Spannung von 540 mV bei 20mA welche
einem RawWert von 14810 entspricht. Der 2te Punkt ist 4mA, 108mV und das
ergibt einen RawWert von 2928.
Wie kommen die Werte zueinander ? ganz einfach, mit einem Labormeßgerät
legt man 540.00mV an den Eingang und das ergibt den RawWert 14810. Nun
das Labornetzteil auf 108.00 mV und das sind dann 2928.
1
// ADC Eingangswerte für die Referenzpunkte
2
#define AdcRawHigh 14810 // Stützpunkt 20.00 mA (540 mV)
3
#define AdcRawLow 2928 // Stützpunkt 4.00 mA (108 mV)
4
#define DeltaRaw (AdcRawHigh - AdcRawLow)
Auf dem Display soll aber 20.00 mA stehen und nicht 14810. Ebenso soll
4.00 mA ausgegeben werden und nicht 2928. Alle Werte dazwischen sollen
auch in die entsprechende Skala passen. Wir formulieren also:
1
// Display Ausgabewerte für die Referenzpunkte
2
#define OutHigh 20000.0 // Ausgabewert für AdcRawHigh = 20.00 mA
3
#define OutLow 4000.0 // Ausgabewert für AdcRawLow = 4.00 mA
4
#define Scale 65536 // zur Basis 2^16
5
#define DeltaOut (OutHigh - OutLow)
Hier kannst du hoffentlich erkennen das nur eine Umskalierung
stattfindet. Nun noch die Berechnung mit einem Schritt mehr:
1
// Berechnung der ADC Korrekturwerte mittels Referenzpunkte
Guten Morgen!!
Danke, das ist ja fast ein Weihnachtsgeschenk :)
Jetzt hab ichs verstanden, dass ich den Wert den ich gerne als
Anzeigewert hätte angeben muss! Das war mir vorhin nicht klar, habe die
Rechnungen jetzt einmal nachvollzogen und jetzt verstehe ich es auch,
ich werd es jetzt noch in mein Programm einbauen und schauen ob das
alles past.
Vielen vielen Dank !
Ich wünsche noch ein frohes Fest!