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
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;
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. ?
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.
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...
Ich werde das Gefühl nicht los, dass sein eigentliches Problem nicht der Mittelweret ist, sondern wie er die 3 Minuten abmessen soll :-)
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.
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. ...
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)
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. ;-) ...
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
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.
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.
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
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...
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Zähler_des_AVR#Beispiel_f.C3.BCr_CTC_Clear_Timer_on_Compare_Match_.28Auto_Reload.29 Sollte ein guter Anfang zum "spielen" sein... ;-)
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
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.
@ 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 . . . ;-)
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.