Forum: Mikrocontroller und Digitale Elektronik Möglichst Resourcenschonend programmieren


von eller (Gast)


Lesenswert?

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

von David M. (md2k7)


Lesenswert?

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

von Achim (Gast)


Lesenswert?

Welche Sprache nutzt du denn? Wenn du AVR GCC nutzt, lies dir mal den 
Artikel AVR-GCC-Codeoptimierung durch.

von eller (Gast)


Lesenswert?

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.

von Huch (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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:
1
    while( rx_busy() )
2
   {  result=0; 
3
      counter = 255;
4
       do
5
       {  result+=ADC_Read();
6
       } while (--counter);
7
       result = result >> 4;
8
     
9
     voltage=(result*40960/kalibrierung);
10
       
11
     ocr = (((voltage-((unsigned long)STARTWERT*10))*255)/1000);
12
13
     if(ocr>=0xFF)
14
     {  ocr = 0xFF;
15
     }
16
      
17
     else if(ocr<=0x00)
18
     {  ocr = 0x00;
19
     }
20
      
21
     OCR0B=(unsigned char)ocr;
22
   }

von Huch (Gast)


Lesenswert?

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.

von bernd (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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% )

von Sebastian .. (zahlenfreak)


Lesenswert?

> 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

von Entwickler (Gast)


Lesenswert?

>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.

von Purzel H. (hacky)


Lesenswert?

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.

von eProfi (Gast)


Lesenswert?

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.

von eProfi (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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

von eller (Gast)


Lesenswert?

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?

von eller (Gast)


Lesenswert?

Die große Frage ist ob ein ein typecast von integer auf (unsigned char ) 
auf -10 = 0 und aus 300 = 255 macht ?  zb.

von eProfi (Gast)


Lesenswert?

> 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.

von eller (Gast)


Lesenswert?

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.

von eProfi (Gast)


Lesenswert?

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.

von Bernd N (Gast)


Lesenswert?

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 ?

von eller (Gast)


Angehängte Dateien:

Lesenswert?

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

von Huch (Gast)


Lesenswert?

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.

von Huch (Gast)


Lesenswert?

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?

von eller (Gast)


Lesenswert?

Hallo!

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

Lg

von Huch (Gast)


Lesenswert?

>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.

von avion23 (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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?

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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

von heinzel (Gast)


Lesenswert?

das wird nicht gehen, weil da ein faktor 5 drin ist

von eller (Gast)


Lesenswert?

Heißt also da ich sowieso die Division brauch, ist besser alles mit der 
auszuführen?

von Thomas W. (wagneth)


Lesenswert?

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 !

von eller (Gast)


Lesenswert?

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

von Thomas W. (wagneth)


Lesenswert?

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...

von eller (Gast)


Lesenswert?

Ja, aber darum gehts nicht!

es gut um:
voltage=((result*40960)/bandgap);

und der gesamte Code ist ein paar Beiträge weiter oben bereits im Anhang

Lg

von eller (Gast)


Lesenswert?

STARTWERT = 40000

zb.

das heißt ocr = ( voltage-40000 >> 8 )

das geht ja noch aber

voltage=((result*40960)/bandgap);

kann ich nicht mit shift lösen.

von Mupfel (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

Ja ist doch egal, darum gehts ja nicht, es geht um die Division durch 
die variable Bandgap, das ist doch hier das einzige Problem ?

von Mupfel (Gast)


Lesenswert?

>das ist doch hier das einzige Problem ?

So? Na wenn Du meinst.

von eller (Gast)


Lesenswert?

voltage=((result<<13)/bandgap);

Angenommen, das wär in Ordnung. Was hilft mir das nun weiter ?

von Thomas W. (wagneth)


Lesenswert?

Ä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 ?

von eller (Gast)


Lesenswert?

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

von Purzel H. (hacky)


Lesenswert?

>voltage=((result*40960)/bandgap);

((result *10) << 12) div bandgap  ?

von Thomas W. (wagneth)


Lesenswert?

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.

---

von eller (Gast)


Lesenswert?

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?

von eller (Gast)


Lesenswert?

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

von thomas (Gast)


Lesenswert?

Glaube

 asm volatile ("nop");

muss es heissen da sonst "optimiert" wird.

von eller (Gast)


Lesenswert?

Da hast recht danke!

Wusste jetzt nur nicht auf anhieb wos hin muss, also hab ichs erstmal 
garned hier herein geschrieben ;)

Danke

von Bernd N (Gast)


Lesenswert?

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.

von Thomas W. (wagneth)


Lesenswert?

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.

von Thomas W. (wagneth)


Lesenswert?

Was für einen Spannungsteiler hast Du denn ?

von Bernd N (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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

von Thomas W. (wagneth)


Lesenswert?

@ 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...

von Purzel H. (hacky)


Lesenswert?

Ne Akku Ueberwachung... da geht man doch nicht eine Bandgap kalibrieren. 
Las sowas weg. Bringt nix.

von Bernd N (Gast)


Lesenswert?

>> 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 :-)

von eller (Gast)


Lesenswert?

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

von Thomas W. (wagneth)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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

von Bernd N (Gast)


Lesenswert?

@ 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.

von eller (Gast)


Lesenswert?

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.

von Thomas W. (wagneth)


Lesenswert?

Auto : y=mx+c

von Bernd N (Gast)


Lesenswert?

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 
:-)

von eller (Gast)


Lesenswert?

Naja inwiefern hilft mir das ? Das es ne Geradengleichung ist, weiß ich 
;)

von Huch (Gast)


Lesenswert?

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?

von eller (Gast)


Lesenswert?

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.

von Bernd N (Gast)


Lesenswert?

>> inwiefern hilft mir das ?

Probier es aus, verstehe es, verwende es.

von Bernd N (Gast)


Lesenswert?

Originalcode von mir...
1
uint16_t getAdcValue (void)
2
{
3
    uint16_t AvgCount = 0;
4
    uint32_t AvgSum = 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) * Factor) + Offset) >> 16);           // skaliert auf 12 BIT
12
}

nicht die diskutierten Varianten... im originalen Code wird nur 
geshifted.

von Falk B. (falk)


Lesenswert?


von eller (Gast)


Lesenswert?

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?

von Bernd N (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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?

von Thomas W. (wagneth)


Lesenswert?

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.

von Thomas W. (wagneth)


Lesenswert?

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.

von Bernd N (Gast)


Lesenswert?

Ja, die Kalibrierung mache ich über 2 Stützpunkte. Also noch einmal 
ausführlich.
1
uint16_t getAdcValue (void)
2
{
3
    uint16_t AvgCount = 0;
4
    uint32_t AvgSum = 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
2
#define AdcRawH 13702                                             // Stützpunkt 500 mVolt (14 BIT)
3
#define AdcRawL  2722                                             // Stützpunkt 100 mVolt (14 BIT)
4
5
// Skalierung Delta ADC + Referenzpunkte
6
#define RefA  4000.0                                              // Referenzpunkt A 500mV-100mV=400mV
7
#define RefB  1000.0                                              // Referenzpunkt B 100mV
8
#define Scale 65536                                               // zur Basis 2^16
9
10
// Berechnung der ADC Korrekturwerte mittels Referenzpunkte
11
#define Slope  (RefA / (AdcRawH - AdcRawL))                       // Delta U / Delta ADC -> Steigung
12
#define Offset (uint32_t) ((RefB - (AdcRawL * Slope)) * Scale)    // Offset zur Basis 2^16
13
#define Factor (uint32_t) ((RefA / (AdcRawH - AdcRawL)) * Scale)  // Steigung zur Basis 2^16

Dieses Spiel kann man beliebig treiben. Hier habe ich sogar noch 2BIT 
abgeschnitten (F2013 hat nen 16BIT Wandler an Board).

von Bernd N (Gast)


Lesenswert?

Achso... resourcenschonend sollte es ja auch noch sein :-) und das ist 
es, es ist genau und kompakter als deine Version.

von eller (Gast)


Lesenswert?

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?

von Bernd N (Gast)


Lesenswert?

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 
:-)).

von eller (Gast)


Lesenswert?

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.

von Bernd N (Gast)


Lesenswert?

Ist es ja zunächst, fang mal an, poste den aktuellen Code und dann 
schaun wir mal. Welchen Tiny verwendest du denn ?

von eller (Gast)


Lesenswert?

Attiny13

mach mich gerade ans Code schreiben

von Thomas W. (wagneth)


Lesenswert?

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...

von eller (Gast)


Angehängte Dateien:

Lesenswert?

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 ?

von Bernd N (Gast)


Lesenswert?

Funktioniert so nicht... überleg mal.

von eller (Gast)


Lesenswert?

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

von Purzel H. (hacky)


Lesenswert?

Also, wenn ich genau messen muesste, so wuerde ich eine externe 2.5V 
Referenz fuer 1.8$ anschnallen. und mir die Kalibriererei schenken.

von eller (Gast)


Lesenswert?

Ich bin für kalibrieren :)

von Bernd N (Gast)


Lesenswert?

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 ?

von eller (Gast)


Angehängte Dateien:

Lesenswert?

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 !

von Thomas W. (wagneth)


Lesenswert?

Sorry das ich euch da reinplatze.
Der BD139 soll so sein ?

von avion23 (Gast)


Lesenswert?

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 :)

von eller (Gast)


Lesenswert?

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.

von eProfi (Gast)


Lesenswert?

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.

von avion23 (Gast)


Lesenswert?

Hallo eProfi,
es gibt keinen Spannungsteiler. Es wird die interne Bandgab spannung 
gemessen und mit der Versorgungsspannung verglichen. Wir müssen alle 
sparen :)

von eller (Gast)


Lesenswert?

avion23:

Doch es gibt einen Spannungsteiler, da ich mit einem Attiny13 nicht die 
interne BGD gegen Vcc messen kann!

von avion23 (Gast)


Lesenswert?

Oh Entschuldigung,
ich bin vom alten thread ausgegangen.

von Thomas W. (wagneth)


Lesenswert?

> 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 !

von eller (Gast)


Lesenswert?

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 ?

von Thomas W. (wagneth)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

Dann tus nicht ;)?

von Bernd N (Gast)


Lesenswert?

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 ???

von eller (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@  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 . . .

von eller (Gast)


Lesenswert?

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?

von Thomas W. (wagneth)


Lesenswert?

Kunstoff, schwarz, manchmal viele manchmal wenige beine.
Bei Deinen kommt rauch raus... ;)


PS: Sorry ich kann nicht anders.

von ein Zweifler (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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?

von zweifler (Gast)


Lesenswert?

Glaub einfach fest an 14 Bit und das du dich auskennst ;)

von eller (Gast)


Lesenswert?

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.

von Bernd N (Gast)


Lesenswert?

Wie weit bist du denn jetzt ?

von eller (Gast)


Lesenswert?

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

von Bernd N (Gast)


Lesenswert?

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.

von eller (Gast)


Lesenswert?

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

von Bernd N (Gast)


Lesenswert?

>> 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 !?!?

von Bernd N (Gast)


Lesenswert?

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
2
#define Slope     (DeltaOut / DeltaRaw)                           // DeltaOut / DeltaRaw  = Steigung
3
#define Nullpunkt (OutLow - AdcRawLow * Slope)
4
#define Offset    (uint32_t) (Nullpunkt * Scale)                  // Offset zur Basis 2^16
5
#define Factor    (uint32_t) (Slope * Scale)                      // Faktor zur Basis 2^16
und fertig ist die Laube. Besser kann ich es nicht erklären.

Viel Erfolg und viel Spaß über die Feiertage.

von eller (Gast)


Lesenswert?

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!

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.