Forum: Mikrocontroller und Digitale Elektronik Mittelwert von ADC über 3 Minuten ?


von gerd (Gast)


Lesenswert?

Hallo Leute,
ich brauche mal eure Hilfe,
Ich benötige einen Mittelwert aus einer bestimmten Zeit (3Minuten) von 
einem Analogsignal.
Erst mal die Rahmenbediungen: Ich verwende einen Atmega 32 mit 4 MHZ und 
Programmiere in C..
Ich bekomme das Analogsignal über einen Spannungsteiler an den ADC vom 
Atmega und lese diesen auch entsprechend aus. Das klappt auch soweit auf 
meinem Display wird der ADC Wert angezeigt und ich kann auch Mittelwerte 
von mehreren Messwerten machen und ausgeben.

Mein Problem ist jetzt nur, ich muss einen Mittelwert aus 3Minuten haben 
und das Programm muss natürlich nebenbei weiter laufen (da unter anderem 
noch eine Frequenz am ICP-Port gemessen wird..)
Sowas hat doch bestimmt schon mal jemand gemacht? ich hätte ja mal 
vermutet das wird mit einem Timer gemacht aber ich komm da irgendwie 
nicht weiter..

Hat vielleicht jemand etwas Code mit dem er mir Helfen könnte?

danke für die Mühe,
schönen Gruß
Gerd

von Ich (Gast)


Lesenswert?

Ist eigentlich nicht so wild. Du hast eine bestimmt Anzahl an Messungen 
pro Sekunde. Sagen wir jetzt mal 10. Also willst du den Durchschnitt von 
30 Messungen. Sprich eine Messung hat 1/30tel Gewichtung. Jetzt nimmst 
du immer dein alten Durchschnittswert dieser hat 29/30tel Gewichtung und 
addierst dein neuen Wert mit 1/30 dazu. So hast du immer einen 
Kontinuierlichen Durchschnittswert.

Beispiel:

durchschnittswert = ( ( durchschnittswert * 29 ) + messwert ) / 30;

von Stephan H. (stephan-)


Lesenswert?

oder den gleitenden Mittelwert.
Wenn es auf die 3 Minuten beschränkt ist, kann man ja die 
Mittelwertbildung nur für 3 Min laufen lassen. :-)
zB.
Wert= wert(alt) *3 + Wert(neu) /4

Dann einen Timer machen der 1 Sekunde erzeugt. Einen Zähler für dez 180 
Sek.
Und während dieser Zeit erfolg die Mittelwertbildung und Decrementierung 
des 180 Sek Zählers. Bei Zähler = 0 ist dann Schluss mit Mittelwert.
Wenn es so sein soll. ?

von Nn N. (jaytharevo)


Lesenswert?

Wie oft würdest du gern Wandlen? Falls du den ADC voll laufen lässt 
kommt da in 3min eine ganz schöne Menge an Werten zusammen.

von AVRli (Gast)


Lesenswert?

Hi Gerd,

also ich habe sowas ähnlichen über 5 min gemacht. Nun müste man wissen 
wie schnell sich die Werte denn nun ändern, bei mir waren es mal 
Windgeschwindigkeiten. Ohne Timer geht da nichts denke ich mal.

Den habe ich so geschrieben das er mir ca. jede Sekunde ein Flag setzt 
das dem Hauptprogramm mitteilt "neuen Wert aufnehmen".

Im Hauptprogramm dann folgenes...

Wert aufnehmen und in einen Ringpuffer schieben damit Du zu jeder Zeit 
wirklich Werte der letzten 5 min hast. Hängt nun auch davon ab wie viel 
Aufnahmen Du brauchst. Alle Minute wären dann 5, alle 10 Sekunden dann 
30 Werte. Wenn Du den Wert dann haben willst den Mittelwert aller 
Aufnahmen ermitteln.

Bei kleineren Messzeiten würde sich auch eine Durchschnittsrechnung 
anbieten.

IST = (ACT_READ * 0.1) + (IST * 0.9);

Dann zieht sich das allmählich auf einen Zwischenwert. "Glättung" nur 
wenn man hier zu schnell den neuen Wert berechnet geht's auch nicht... 
also etwas Zeit zwischen den einzelnen Messungen. 1 Sekunde darf es 
bestimmt sein.

Gruß AVRli...

von Karl H. (kbuchegg)


Lesenswert?

Ich werde das Gefühl nicht los, dass sein eigentliches Problem nicht der 
Mittelweret ist, sondern wie er die 3 Minuten abmessen soll :-)

von Bernd N (Gast)


Lesenswert?

Ich werde das Gefühl nicht los das die Kombination aus Frequenzmessung 
und ADC sein Problem ist :-) aber da warten wir mal auf das Feedback.

von Hannes L. (hannes)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ich werde das Gefühl nicht los, dass sein eigentliches Problem nicht der
> Mittelweret ist, sondern wie er die 3 Minuten abmessen soll :-)

Eben.

Normal würde ich mit gleitendem Mittelwert arbeiten, also
Ist = Alt * 255 / 256  + Neu / 256. Das ist in ASM eine einfache 
Subtraktion und eine einfache Addition, wobei die Division durch 256 
durch Byteshifting (Umbenennung) erfolgt und nix kostet.

Wenn es unbedingt die 3 Minuten sein müssen, dann würde ich 256 Bytes 
Ringbuffer anlegen, den ADC frei durchlaufen lassen und mittels Timer 
auslesen, wobei das Timer-Intervall auf 3 Minuten / 256 eingestellt 
wird. Somit dauert es 3 Minuten, bis alle Werte aktualisiert wurden. 
Wird der Wert gebraucht, addiert man den Inhalt des Ringbuffers und 
wirft das Low-Byte weg, was einer Division durch 256 (Byteshifting) 
entspricht. In ASM lächerlich einfach und effizient, in einer 
Hochsprache vermutlich etwas kryptisch.

...

von Karl H. (kbuchegg)


Lesenswert?

Hannes Lux schrieb:

> entspricht. In ASM lächerlich einfach und effizient, in einer
> Hochsprache vermutlich etwas kryptisch.

LOL
Höre ich da etwas heraus?

(Es ist auch in einer Hochsprache wie C lächerlich einfach)

von JojoS (Gast)


Lesenswert?

einfach dicken Kondensator vor den ADC Pin setzen?

von Hannes L. (hannes)


Lesenswert?

Karl heinz Buchegger schrieb:
> Hannes Lux schrieb:
>
>> entspricht. In ASM lächerlich einfach und effizient, in einer
>> Hochsprache vermutlich etwas kryptisch.
>
> LOL
> Höre ich da etwas heraus?

Das muss ein Irrtum sein, Du schaffst es nicht, mit meinen Sechzich tu 
ich mir das nicht mehr an... ;-)

>
> (Es ist auch in einer Hochsprache wie C lächerlich einfach)

Das war der Frage und den bisherigen Antworten aber nicht anzusehen. 
Wenn es soooo einfach wäre, gäbe es ja keinen Diskussionsbedarf. ;-)

...

von gerd (Gast)


Lesenswert?

Moin,
ich messe auch Wind aber bei mir ist es die Windrichtung, die Windfahne 
gibt einen analogen Messwert aus.
Der ADC nimmt dieses analog-Signal auf und es soll auch als 3 Minuten 
Mittelwert ausgegeben werden.

Ich habe die Messwertaufnahme erfolgreich am laufen und kann auch einen 
gleitenden Mittelwert ausgeben , was halt noch fehlt ist die Zeit ich 
kann keinen Mittelwert über die Zeit machen, da ich nicht weiß wie viele 
Messwerte ich in welcher zeit aufnehme und das ja auch noch abhängig von 
dem restlichen Programmdurchlaufzeiten ist und die können ja variieren 
denke ich ..( da wird z.b ja noch eine Frequenz gemessen, und andere 
steuerungsaufgaben vorgenommen..) Zur Zeit addiere ich einfach die 
letzten 100 Messungen auf und teile dann durch 100..

Ich bräuchte am besten ein Beispiel von einer Messwertaufnahme, die 
einen Mittelwert über ein vorgegebenes Zeitintervall berechnet.

@AVRLi : dein Beispiel hört sich so ähnlich an, wie das was ich da vor 
habe, könntest du mit netterweise deinen  Code zur verfügung stellen? 
mich würde interessieren wie du die Timer verwendest, das hab ich 
irgendwie noch nicht so drauf...

schönen Gruß
gerd

von Karl H. (kbuchegg)


Lesenswert?

Dann wirds Zeit, dass du dich mit Timern beschäftigst.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

Wenn man den Dreh raus hat, sind die Dinger unglaublich einfach.

> Ich bräuchte am besten ein Beispiel von einer Messwertaufnahme,
> die einen Mittelwert über ein vorgegebenes Zeitintervall berechnet.

Reduziere die Aufgabenstellung etwas.
Du brauchst einen Code, der in bestimmten Zeitintervallen Messwerte 
aufnimmt.
Die Zeitintervalle generiert dir der Timer mit einem Interrupt. Siehe 
Tutorial.

von jl (Gast)


Lesenswert?

gerd schrieb:
> da ich nicht weiß wie viele
> Messwerte ich in welcher zeit aufnehme


das solltest du aber, z.B alle 100ms eine Wandlung.

Oder kommt sporadisch von einem externen Sensor ab und zu mal was in 
dein uC hinein?
Dann gibts nur ein array das gross genug für den schlimmsten Fall ist 
(Datendauerfeuer) und mit jedem Element einen Zeitstempel ablegen. Dann 
alle Elemente mit 'aktuelle Zeit' >= Zeitstempel > 'aktuelle Zeit - 
3min' addieren und durch die Anzahl dividieren.

von Tom (Gast)


Lesenswert?

Hier ist genau diese Aufgabe halbwegs komfortabel vor dem Anwender 
versteckt: http://www.rn-wissen.de/index.php/Gleitender_Mittelwert_in_C

Größe des Arrays auf 180, jede Sekunde (siehe Timer) mit AddToFloatAvg 
einen neuen Messwert reinspeichern und bei Bedarf mit GetOutputValue den 
Durchschnitt aus den letzten 180 Werten lesen.

Wenn der RAM für die gewünschte Messfrequenz nicht reicht, könnte man 
z.B. den Durchschnitt über die letzten 2 Sekunden berechnen und diesen 
alle 2s auslesen und in einen zweiten Filter schreiben, der dann den 
Durchschnitt ueber die letzten 90 Werte ( = 3 Minuten) berechnet.

Grüße,
Tom

von AVRli (Gast)


Lesenswert?

Hi Gerd,

Karl heinz Buchegger schrieb:
> Dann wirds Zeit, dass du dich mit Timern beschäftigst.

Da kann ich mich nur anschließen. Auf das Wissen aus den Artikeln kann 
man super zurückgreifen und tolle Ergebnisse erzielen.

Karl heinz Buchegger schrieb:
> Reduziere die Aufgabenstellung etwas.

Sehe ich auch so. Bau Dir erstmal einen Timer der Dir alle 5 Sekunden 
eine LED toggelt. Wenn das steht, dann weißt Du, Timer hab ich. ;-)

Dann würde ich im INT einen Wert vom ADC einlesen und mir den in einem 
Ringpuffer schreiben. Vlt. so...

...
volatile uint8_t wind_dir[32];
...

// im Timer INT wenn 5 Sekunden abgelaufen sind dann ADC
// einlesen und ab in den Buffer damit

wind_dir[pos_in] = DIR; // DIR ist Dein Wert den du liest
pos_in++;
pos_in = pos_in & 0x1F;

Bei einer Rate von 5 Sekunden und einer Buffergröße von 32 hast du dann 
genau die letzten 70 Sekunden im Buffer.

Im Mainprogramm kannst Du dann zu jeder beliebigen Zeit deine 
Durschnittberechnung über den Inhalt des gesamten Buffer anstellen. Du 
kannst sicher sein das es zu dem Zeitpunkt wo Du es berechnest immer die 
letzten 70 Sekunden herangezogen werden. Nun dem Hauptprogramm durch ein 
FLAG mitteilen wann 60 Sekunden im TIMER abgelaufen sind. Im 
Hauptprogramm das FLAG 3x zählen und dann die Berechnung und Ausgabe. 
Dann haste den Mittelwert der letzten 70 Sekunden alle 3 Minuten 
ausgegeben.

Windrichtung über die gesamten 3 Minuten ist wohl sehr träge, ich glaube 
da dauert es eine Weile bis die richtige/aktuelle Richtung angezeigt 
wird.



Viel Erfolg!

Gruß AVRli...

von AVRli (Gast)


Lesenswert?


von gerd (Gast)


Lesenswert?

Danke für die Hilfe,
jetzt hab ich erst mal nen Ansatz wie die sache anzugehen ist.. ich 
werde dann mal etwas üben und mich dann mal wieder melden; )

thx,
gerd

von Karl H. (kbuchegg)


Lesenswert?

gerd schrieb:
> Danke für die Hilfe,
> jetzt hab ich erst mal nen Ansatz wie die sache anzugehen ist.. ich
> werde dann mal etwas üben und mich dann mal wieder melden; )
>

Ich denke, das schlimmste was du jetzt tun kannst ist es, in dein 
vorhandenes Programm einen Timer hineinzuquetschen.

Fang zunächst damit an, dir ein Spielprojekt zu generieren, in dem du 
dich mit dem Timer vertraut machst. Fürs erste, wie schon angesprochen, 
genügt es, wenn du es schaffst eine LED nur über den Timer zum blinken 
zu bringen und auch verstehst, welche Register wie zu setzen sind, damit 
sich genau die von dir gewünschte Blinkfreeuenz ergibt.

Von dort geht man dann weiter und hängt zb den ADC an.

Es ist auch nicht ungewöhnlich, dass du merkst, dass dein Spielprojekt 
viel besser funktioniert, als das was du jetzt hast und anfängst Teile 
von deinem jetzigen Projekt in das Spielprojekt zu übernehmen. Solange, 
bis dein Spielprojekt zum eigentlichen Programm wird.

Programmieren bedeutet auch, sich von altem Code zu trennen, wenn man 
merkt, dass dieser Code einen nicht weiter bringt.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Programmieren bedeutet auch, sich von altem Code zu trennen, wenn man
>merkt, dass dieser Code einen nicht weiter bringt.

Das gilt nicht nur fürs Programmieren . . . ;-)

von Peter D. (peda)


Lesenswert?

Hannes Lux schrieb:
> In ASM lächerlich einfach und effizient, in einer
> Hochsprache vermutlich etwas kryptisch.

Ich muß Dich leider enttäuschen, in C ist es sogar noch einfacher als in 
Assembler.


Peter

von Hannes L. (hannes)


Lesenswert?

Peter Dannegger schrieb:
> Hannes Lux schrieb:
>> In ASM lächerlich einfach und effizient, in einer
>> Hochsprache vermutlich etwas kryptisch.
>
> Ich muß Dich leider enttäuschen, in C ist es sogar noch einfacher als in
> Assembler.

Tja, wenn man es kann... - Dann ist es keine Kunst mehr... ;-)

Und ich kann es nunmal nicht. Und da ich meine (meist recht kleinen) 
AVR-Basteleien ganz gut in ASM hinbekomme (wobei ich viel von Dir 
gelernt habe), sehe ich auch keine Notwendigkeit mehr, jetzt noch mit C 
zu beginnen.

Ich hatte nunmal beim Einstieg (vor ziemlich genau 21 Jahren) aufs 
falsche Pferd gesetzt, für den Commodore plus/4 gab es nunmal kein C. 
Ich hatte daher Basic gelernt und etwas 6502-Assembler.

Und mal ehrlich, ohne Dein (versdammt gutes) ASM-Wissen könntest Du mit 
C auch nicht so virtuos umgehen.

>
>
> Peter

Gruß in die Hauptstadt,
Hannes

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.