Hallo, ich suche eine Lösung für mein Problem und hoffentlich kann mir jemand auf die Sprünge helfen, der Mikrocontroller ist ein ATmega8. Ich erwarte ein sinusförmiges Eingangssignal von 0 bis 5V, Frequenz ist 50Hz. Der Nullpunkt dieser Sinuskurve liegt bei 2,5V. Nun will ich mich ein wenig tiefer in die AVR-GCC-Programmierung wagen und möchte den höchsten Spannungswert mittels Software finden und speichern. Meine Überlegungen: Da es sich um eine Frequenz von 50Hz handelt, ist eine Periode 20ms lang. Für die Abtastung einer Periodenlänge kommt daher ein Zeitfenster von 20ms in Frage. In diesen 20ms werden (sagen wir mal) 200 ADC-Messwerte gelesen und überprüft, ob der aktuelle Messwert größer ist als der zuletzt gemessene ADC-Wert. Nur, wenn das der Fall ist, wird der neue Messwert als als "Höchstwert" gespeichert, der dann mit dem folgenden ADC-Messwert verglichen wird. Sind die 20ms abgelaufen, wird eine neue Messwertaufnahme gestartet, und das insgesamt 10 Mal. Die eingelesen Messwerte werden jeweils nach dem Ablauf des Zeitfensters aufaddiert. Wenn 10 Messwerte aufgenommen wurden, wird daraus der Mittelwert gebildet und ggfs. ausgegeben. Kann man das so machen oder gibt es eine elegantere Lösung für dieses Problem? Besten Dank, Olaf
Olaf schrieb: > Wenn 10 Messwerte aufgenommen wurden, wird daraus der > Mittelwert gebildet und ggfs. ausgegeben. Warum gerade 10 Messwerte?
du kannst die Differenz zum letzten Messewert ausrechnen und immer dann, wenn die das Vorzeichen wechselt, ist entweder eich Hoch- oder ein Tiefpunkt.
MarioT schrieb: > Warum gerade 10 Messwerte? Damit ich dadurch den arithmetischen Mittelwert bekomme und so ein Schwanken der Messwerte weitestgehende verhindern möchte. Wenn grob gesagt alle 20ms ein Messwert ausgespuckt wird, schwankt die Anzeige mehr, als wenn alle 200ms ein Mittelwert aus den 10 aufgenommenen Werten ausgegeben wird. Armin schrieb: > du kannst die Differenz zum letzten Messewert ausrechnen und immer dann, > wenn die das Vorzeichen wechselt, ist entweder eich Hoch- oder ein > Tiefpunkt. Ich muss doch aber wissen, ob sich der Messwert in der Differenzmessung wirklich um einen Hochpunkt handelt und es sich nicht um ein "fallendes" Signal handelt. Ich stehe um diese Uhrzeit wohl aufm Schlauch und weiß nicht, wie ich das genau zu verstehen habe.
aber wenn du den Zeitpunkt kennst, bis zu dem das Signal steigt und ab dem das Signal fällt, dann ist das der Hochpunkt. --> Morgen nochmal durchlesen.
mit der Mittelwertbildung erreichst du niemals den Spitzenwert, sondern immer einen Wert, der leicht darunter liegt (Abtastrate kann nicht unendlich hoch sein, d.h. den absoluten Spitzenwert wirst du nur selten treffen. Normalerweise liegst du knapp davor oder dahinter, beides liefert Messwerte, die tiefer liegen) Glücklicherweiser ist die Steigung eines Sinussignals gering, so dass die Fehler wahrscheinlich vernachlässigbar bleiben.
if Wert_neu - Wert_alt > 0 then Wert_alt = Wert_neu Olaf schrieb: > Damit ich dadurch den arithmetischen Mittelwert bekomme und so ein > Schwanken der Messwerte weitestgehende verhindern möchte. Ich meinte warum müssen es unbedingt "10" Messungen sein? Du willst es doch auf einem µC machen. Der "denkt" aber etwas anders als Du. Du rechnest doch Dezimal, wenn man etwas durch 10 teilt verschiebst Du doch nur das Komma. Für einen µC ist teilen durch 10 aber schon ein größerer Akt.
Oh, das Thema passt mir gerade super. Werde bald was ähnliches machen. Ich finde die Idee mit der Differenz der Messwerte auch gut. Nur sieht es bei mir so aus, dass ich die PWM an einem Drehstrommotor zuerst über einen Filter jage und dann die Amplitude und Frequenz messen will. Jetzt hat mein Sinus, je nach Drehzahl des Motors, bis zu 300 Hz. Habe jetzt mal in der Simulation einen Filter gebastelt. Bei hohen Frequenzen bekomme ich dann auch einen wunderbaren Sinus, nur unten wirds schwer. Der Sinus ist dort auch erkennbar, aber halt nicht ganz so sauber (siehe Bild). Da kann ich diese Methode schon wieder vergessen, oder?
Benni Nori schrieb:
> Bild). Da kann ich diese Methode schon wieder vergessen, oder?
Ja.
Man sollte auch bedenken, dass für die Bestimmung der Differenz der
elektronische Aufbau schon sauber sein sollte. Ansonsten passiert es
nämlich, dass der ADC selbst bei absolut konstanter Eingangsspannung
immer ein wenig um den wahren Wert schwankt (+/- 1 oder 2 Digit)
Wenn ich aber sowieso weiß, dass die 0-Linie meiner Spannung bei 2.5V
liegt, dann würde ich das Maximum bzw. Minimum genau so ermitteln wie
der TO das hatte.
Sobald die Spannung einen Wert von 2.5V + Hysterese überschreitet wird
die nächste Maximumsuche scharf geschaltet und das letzte gefundene
Minimum als das Minimum im letzten Abschnitt ausgewiesen. Unterschreitet
die Spannung 2.5V - Hysterese, so wird die Minimum-Suche scharf
geschaltet und das zuletzt gefundene Maximum ausgegeben.
Hallo, ich habe mich derweil in diesem genialen Forum weiter umgeschaut und bin auf einen ähnlichen Beitrag gestoßen. Da ich eine 4 stellige 7-Segment-Anzeige verwende, habe ich den Code dieses Posts teilweise verwendet. Ich kam nun zu folgendem Code (mich interessiert nur die positivste Spannungsspitze):
1 | volatile unsigned char fertig = 0; |
2 | volatile unsigned int result; |
3 | volatile unsigned int offset = 511; |
4 | volatile unsigned int peak = 511; |
5 | |
6 | void messung (void) |
7 | {
|
8 | {
|
9 | ADCSRA |= (1<<ADSC); |
10 | while ( ADCSRA & (1<<ADSC) ) { |
11 | ;
|
12 | }
|
13 | result = ADCW; |
14 | }
|
15 | fertig = 1; |
16 | }
|
17 | |
18 | int main ( void ) |
19 | {
|
20 | adcinit(); |
21 | ioinit(); |
22 | |
23 | while (1) |
24 | {
|
25 | if (fertig == 0) |
26 | {
|
27 | messung(); |
28 | }
|
29 | |
30 | if (fertig == 1 && result > peak) |
31 | {
|
32 | peak = result; |
33 | fertig = 0; |
34 | }
|
35 | |
36 | if (fertig == 1 && result < offset) |
37 | {
|
38 | Errechnet = (int)(peak / 5.11); |
39 | peak = offset; |
40 | fertig = 0; |
41 | }
|
42 | |
43 | if (!Taster_gedrueckt) |
44 | DisplayNumber(Errechnet); |
45 | else DisplayDigit(peak); |
46 | }
|
47 | }
|
Leider funktioniert das nicht wirklich. Der Atmega8 macht nur eine Messung und läuft nicht ständig durch, obwohl ich doch das "fertig-Flag" zurücksetze. Ist wohl doch nicht so einfach, wie ich mir das gedacht habe?! Gruß, Olaf
zum einen fehlt da einiges vom Code, zum anderen kannst du dir die Variable fertig komplett sparen (ist zwar nicht der Fehler, macht das Programm aber übersichtlicher)
wofür brauchst du das "Fertig" überhaupt? das macht hier doch nur sinn, wenn die messung() in einem parallel thread läuft, oder? ich kann grad nicht folgen. Ansonsten seh ich bloß, dass, wenn einmal genau 511 gemessen wird, das ganze Ding stehen bleibt (fertig=1 dauerhaft)
Olaf schrieb: > if (fertig == 1 && result > peak) . . > if (fertig == 1 && result < offset) wenn keine der beiden Bedingungen wahr ist, wird "fertig" nicht zurückgesetzt. Vielleicht ist das das Problem.
Walter schrieb: > zum einen fehlt da einiges vom Code, > zum anderen kannst du dir die Variable fertig komplett sparen (ist zwar > nicht der Fehler, macht das Programm aber übersichtlicher) Der restliche Code ist nur die Ausgabe für die 7-Segment-Displays. Mehr habe ich nicht im Code stehen, halt nur die Ansteuerung der Displays (das funktioniert supi) und dann die ADC-Geschichte (funktioniert nicht wirklich). Meine Stehlampe zieht 1,12A, das Display hat nur eine Nachkommastelle und zeigt 1,1A an. Soweit ist das korrekt. Ich habe das fertig-Flag definiert, damit die if-Anweisungen ausgeführt werden. Armin schrieb: > wofür brauchst du das "Fertig" überhaupt? > das macht hier doch nur sinn, > wenn die messung() in einem parallel thread läuft, oder? Antwort siehe oben... Parallel läuft es eigentlich nur mit der 7-Segment-Ausgabe. dr.schmock schrieb: > Olaf schrieb: >> if (fertig == 1 && result > peak) > . > . >> if (fertig == 1 && result < offset) > > wenn keine der beiden Bedingungen wahr ist, wird "fertig" nicht > zurückgesetzt. Vielleicht ist das das Problem. Hhm, mein Offset beträgt 511, entspricht also 2,5V. Und ich komme wirklich unter die 2,5V! Aber in diese Richtung muss ich mal weitersuchen.
Wenn ich das "fertig-Flag" wegnehme, funktioniert die Anzeige wieder. :-) Nun habe ich aber das Problem, dass bei 0A, also 2,5V (511) die Anzeige keine 0 mehr anzeigt, sondern beim letzten Spannungswert stehen bleibt. :-(
Olaf schrieb: > Wenn ich das "fertig-Flag" wegnehme, funktioniert die Anzeige wieder. > :-) Eben. Dieses 'fertig' ist ein Selbstläufer. Es bringt dir nichts und ist nur ein Quell von Fehlern. > Nun habe ich aber das Problem, dass bei 0A, also 2,5V (511) die Anzeige > keine 0 mehr anzeigt, sondern beim letzten Spannungswert stehen bleibt. > :-( Klar. Weil deine gemessene Spannung niemals die Bedingung erfüllt if ( result < offset) Mach noch einen Zähler mit rein, der jedesmal nach einer Messung um 1 erhöht wird. Dann machst du noch if ( result < offset || counter > 200 ) (200 oder was dir anmgemessen erscheint) so dass du nach spätestens 200 messungen eine Ausgabe erzwingst (und natürlich den Counter dann auch wieder auf 0 zurück setzt).
Karl heinz Buchegger schrieb: > Klar. Weil deine gemessene Spannung niemals die Bedingung erfüllt > > if ( result < offset) > > Mach noch einen Zähler mit rein, der jedesmal nach einer Messung um 1 > erhöht wird. Dann machst du noch > > if ( result < offset || counter > 200 ) > > (200 oder was dir anmgemessen erscheint) so dass du nach spätestens 200 > messungen eine Ausgabe erzwingst (und natürlich den Counter dann auch > wieder auf 0 zurück setzt). Danke, das hört sich vernünftig an. Werde aber morgen damit weitermachen, für heute reicht es mir! Muss dann wohl in der Nacht darüber weitergrübeln. grins Eventuell werde ich erst einmal 16 Peaks sammeln und dann den artihm. Mittelwert bilden, damit die Anzeige nicht zappelt. Gute Nacht, vielen Dank für alle Antworten und bis morgen! :-) Lieben Gruß, Olaf
Karl heinz Buchegger schrieb: > Klar. Weil deine gemessene Spannung niemals die Bedingung erfüllt > > if ( result < offset) Am Tage versteht man das besser und es stimmt, bei 0A (2,5V) komme ich wirklich nie unter offset (2,5V). Der Zähler ist bereits eingebaut und nach 20 Zählschritten wird der Wert auf 0 gesetzt, wenn offset nicht mehr unterschritten wird. Jetzt kann ich ohne Grübeln beruhigt in den Urlaub fahren! Besten Dank, Olaf
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.