Auswertung Impulse Volkswindmesser

Hallo,

du mußt schreiben Serial.println(m[i**-1**]); weil ja nach dem Abspeichern mit i++ incrementiert wird.

Du gibst also beim ersten Aufruf des Interrupts immer das m[1] des LETZTEN 1sek Zykluses aus,
bei zweiten Aufruf des Interrupts immer das m[2] des LETZTEN 1sek Zykluses aus, welchen 0 ist, da deine Pulse zu selten kommen.

Ausserdem solltest du wirklich den Inhalt des Array überprüfen, in dem du in der Zeitscheibe mit

for (j=0; j<=i; j++)
    {
      Serial.println(m[j]);
}

wirklich den Inhalt des Arrays ausliest.

Gunther

Hallo Gunther und alle anderen,

ich habe den Inhalt des Arrays ausgelesen und die Daten, die innerhalb einer Sekunde in das Array durch die Interrupt-Routine geschrieben werden, auf dem Serial Monitor anzeigen lassen.

Hierbei ist mir aufgefallen, dass wenn ich das Anemometer sehr langsam drehe (1 Umdrehung pro Sekunde) und somit auch ein Interrupt pro Sekunde auftreten müsste, ich folgende Werte im Array stehen habe:

Beispiel 1:
m[0] = 2685008
m[1] = 2685064
m[2] = 2685108
m[3] = 0

Beispiel 2:
m[0] = 6961784
m[1] = 6961840
m[2] = 5152580

Beispiel 3:
m[0] = 8527264
m[1] = 8527320
m[2] = 8527356
m[3] = 0

Irgendwas kann doch hier beim speichern der Werte ins Array in der Interrupt-Routine nicht hinhauen, oder?

Ich werd ehrlich gesagt nicht schlau draus, wie ich es abstellen kann, dass mehrere, zum Teil auch falsche Werte in das Array geschrieben werden. Ich hatte auch schon versucht, durch ein erstes delay in der Interrupt-Routine das "Schwingen" vom Reed-Kontakt zu mindern, damit dann nur ein Wert gespeichert wird. Dies hat allerdings absolut nix gebracht.

Habt ihr Ideen, wie man das Problem lösen könnte?

Vielen Dank für eure Hilfe!

Gruß Alex

Für mich sieht das nach Kontaktprellen aus.
Anscheinend kommen die Pulse in ca. 50µs Abstand.

Probier doch mal das:

void Interrupt()
{
  noInterrupts();                     // Interrupt sperren
  m[i++] = micros();
  Serial.println(m[i]);
  delayMicroseconds(200);            // Warten bis Kontaktprellen zuende.
  Interrupts();                      // Interrupt weider zulassen
}

Und dann solltest du die Schleife zur Ausgabe des Arrayinhalts nur bis i-1 laufen lassen. (Mein Fehler, ich hatte es so geschrieben). Das verhindert den "unsinnigen" letzten Wert bei der Ausgabe. Das Array wird im Interrupt ja nur bis i-1 beschrieben. Der Platz m[ i] enthält also falsche Werte aus früheren Messungen.

Gunther

noInterrupts()

Hey Leute,

nachdem hier bisher sehr wenig weiter passiert ist, weil ich leider keine Zeit für das Projekt gefunden hab, nun ein neuer Anlauf.

Irgendwie bekomm ich das Kontaktprellen nicht weg, egal wie hoch in den delay pack.

Jetzt hab ich nochmal ganz rudimentär angefangen und mir direkt die Werte in der Interrupt Routine ausgeben lassen.

Hierbei sieht man, dass mein "RISING" immer genau 2 Werte kommen.

Ich habe dafür folgenden Code verwendet:

int i = 0;
unsigned long j;


void setup()
{
  Serial.begin(9600);

  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{

  noInterrupts();
  j = micros();
  delay(100);
  Serial.print("Wert Nr. ");
  Serial.print(i++);
  Serial.print(";");
  Serial.println(j);
  interrupts();


}


void loop()
{
  }

Dabei bekomm ich folgende Ausgabe im Serial Monitor:

Wert Nr. 0;2402216
Wert Nr. 1;2402996
Wert Nr. 2;3884176
Wert Nr. 3;3885744
Wert Nr. 4;5123992
Wert Nr. 5;5124788
Wert Nr. 6;6213224
Wert Nr. 7;6214328
Wert Nr. 8;7237460
Wert Nr. 9;7238324
Wert Nr. 10;8308352
Wert Nr. 11;8309476
Wert Nr. 12;9405480
Wert Nr. 13;9407204
Wert Nr. 14;10376576
Wert Nr. 15;10378008
Wert Nr. 16;11555068
Wert Nr. 17;11556632
Wert Nr. 18;12729400
Wert Nr. 19;12731160
Wert Nr. 20;13625240
Wert Nr. 21;13626140
Wert Nr. 22;14694512
Wert Nr. 23;14696212
Wert Nr. 24;15819660
Wert Nr. 25;15820572
Wert Nr. 26;16833956
Wert Nr. 27;16835348
Wert Nr. 28;18306752
Wert Nr. 29;18307868
usw...

Dabei beträgt der Mittelwert über alle Abstände, die sich bei 2 aufeinander direkt folgenden Impulsen ergeben: 1249,.. Mikrosekunden
Der Maximalwert beträgt: 1760 Mikrosekunden.
Der Minimalwert beträgt: 780 Mikrosekunden.

Nun habe ich auch schon versucht ein delayMicroseconds() das etwas über dem maximalwert liegt einzuführen, damit das kontaktprellen aufhört. leider ohne erfolg.

könnt ihr mir da weiterhelfen? habt ihr vielleicht noch ideen?

danke schonmal für eure antworten!

BigBangTheory:
Irgendwie bekomm ich das Kontaktprellen nicht weg, egal wie hoch in den delay pack.

Erinnerst Du Dich eigentlich an diesen Thread:
http://forum.arduino.cc/index.php?topic=156239.0
Und dort an meine "Reply #1" im Thread?
Und dort an meine "Reply #3" im Thread?

Das ist doch jetzt exakt dasselbe, was Du hier im März bereits vorgetragen hast: "Wind Datenlogger zählt 2 mal bei einem Impuls"

Und jetzt hältst Du denselben Vortrag über denselben Windmesser in diesem Thread noch einmal.

Wenn Du tatsächlich immer zwei Schaltungen bei einer Vorbeibewegung des Magneten hast, davon eine extrem kurze, dann ist das kein Prellen, sondern dann ist das eine Einbaulage des Reedkontakts mit zwei Schließungen. Das gibt es und das ist nichts besonderes. Wenn Du es immer noch nicht glaubst, dann klicke nochmal auf die im März von mir geposteten Links zum Reekontakthersteller Meder und schaue Dir die Animationen an!

Da ist nichts zu entprellen, sondern Du mußt eben beide Schließungen bei der Auswertung berücksichtigen: Die kurze und die lange Dauer zwischen zwei Schließungen des Kontakts.

Du kannst sogar eine Plausibilitätsprüfung durchführen und feststellen, ob tatsächlich ein Kontaktprellen vorliegt:

  • Du mißt die Zeit für einen kurzen Impuls in Mikrosekunden
  • Du mißt die Zeit für einen langen Impuls in Mikrosekunden
  • Plausibilitätsprüfung: Die der lange Impuls muß mindestens zehnmal so lang sein wie ein kurzer Impuls
  • Wenn ja: Dauer beider Impulse zusammenzählen = Zeit für eine Umdrehung, sonst Messung verwerfen

Da es teils um sehr kurze Zeiten geht (bei der kurzen Schließdauer) ermittelst Du die Impulse am besten mit einer Interruptbehandlungsroutine. Jede Impulsdauer packst Du aus der Interruptbehandlungsroutine abwechselnd in Variablen ("volatile" deklariert) z.B. Impuls_A und Impuls_B.

Und in der loop-Funktion schaust Du in regelmäßigen Zeitabständen nach den beiden Variablen, ermittelst ob eine mindestens 10mal größer ist als die andere, und wenn ja zählst Du sie zusammen und berechnest aus der Summe/Gesamtdauer der beiden Werte die Windgeschwindigkeit.

Wenn Du

'Hierbei sieht man, dass mein "RISING" immer genau 2 Werte kommen'

heraus gefunden hast, dann nimm dies als einen stabilen Sensor Parameter. Impulse / 2 und habe fertisch...

Setze am Besten die Plausibilitätsbetrachtung um, dann filters Du eine Menge Fehler heraus.

Greetz,

Linpo

@ jurs

Du hast da vollkommen Recht. Ich hab das ganze nochmal getestet. Es werden genau 2 Signale durch den Reedkontakt pro Umdrehung erzeugt, wobei ein kurzer und ein langer Impuls entsteht.

Sorry nochmal für meine Beratungsresistens :D.

Momentan bin ich soweit, dass ich mir die Werte (die Abstände zwischen den einzelnen Schaltungen) im Serial Monitor ausgeben lasse.

Hierbei sieht man, dass zuerst ein kurzer und dann ein langer Impuls entsteht.

In der Interrupt Routine frage ich nun ab, ob meine Variable "Abstand" größer ist als 1000 (es hat sich gezeigt das der kurze Impuls max. 640 Mikrosekunden groß ist). Dann wird der Abstandswert in die Variable limpuls gespeichert (langer Impuls)...ansonten wird der Wert in der Variable kimpuls gespeichert (kurzer Impuls).

Hier der Code:

unsigned long i,abstand,kimpuls,limpuls;
unsigned long j=0;



void setup()
{
  Serial.begin(9600);

  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{

  noInterrupts();
  
  i = micros();
  
  abstand = i-j;
  
  j=i;
  
  if (abstand >= 1000)
  {
   limpuls=abstand;
  Serial.print("langer Impuls: ");
  Serial.println(limpuls); 
  }
  else
  {
   kimpuls=abstand;
  Serial.print("kurzer Impuls: ");
  Serial.println(kimpuls); 
  }

  interrupts();


}


void loop()
{

}

Mein vorrangiges Ziel besteht momentan darin, aus den Abständen (kurzer + langer Impuls) eine Periode zu bekommen, anhand derer ich direkt nach jeder Periode die ich gemessen habe, die Windgeschwindigkeit zu berechnen.

Hierzu habe ich anhand der Werte des Herstellers zu Frequenz und Windgeschwindigkeit in Excel eine Formel erstellt, die den Werten des Herstellers des Anemometers gleicht.

Nun meine Frage:

Wie kann ich es programmiertechnisch elegant lösen, das genau ein kurzer und ein langer Impuls addiert werden (die beide zusammen gehören) und dann erst wieder der nächste kurze und der nächste lange Impuls aufsummiert werden, nicht aber schon der bereits benutze lange und dann der nächste kurze Impuls?

Vielen Dank für eure Antworten!

Hier noch eine kurze Ausgabe meine Serial-Monitors:
langer Impuls: 1288736
kurzer Impuls: 548
langer Impuls: 1373776
kurzer Impuls: 552
langer Impuls: 940952
kurzer Impuls: 500
langer Impuls: 891320
kurzer Impuls: 496
langer Impuls: 571136
kurzer Impuls: 496
langer Impuls: 454896
kurzer Impuls: 496
langer Impuls: 422892

usw...

Summiere einfach 2 aufeinanderfolgende Impulse ohne zu kontrollieren ob es ein langer oder kurzer impuls ist.

lang - kurz und kurz - lang sind gleichwertig. Es ist egal in welcher Reihenfolge die Impulse kommen, Hauptsache es sind 2 aufeinanderfolgende.

Grüße Uwe

Stimmt. Es ist ganz egal wie rum ich die Werte aufsummiere.

Wenn ich das Programm mit folgendem Code nun durchlaufen lasse, bekomme ich aber kaum bzw. keine Werte.

Ich habe nun angefangen mir die Werte der einzelnen Variablen auszugeben. Hierbei ist mir aufgefallen, dass bis zur Variable "periode" die Werte auch richtig ausgegeben werden.

Hierbei tritt nun folgendes Problem auf:

Bsp.: periode = 1354464

Ab "periodes" (Umrechnung der Mikrosekunden in Sekunden), bekomm ich anstatt bspw. periodes = 1354464 / 1000000 = 1,354464 nur folgende Werte:

0
0
1
1
usw. (periodes als unsigned long)

0..00
0.00
1.00
usw. (periodes als float)

Welchen Variablentyp müsste "periodes" haben, damit die Zahl bspw. "1,354464" richtig dargestellt wird?

Sind die nachfolgenden Variablen frequenz und wind mit den richtigen variablentypen float und double ausgestattet?

Vielen Dank für eure hilfreichen Antworten!

Anbei noch mein aktueller Code:

unsigned long i,abstand,kimpuls,limpuls, periode;
float frequenz, periodes;
double wind;
unsigned long j=0;



void setup()
{
  Serial.begin(9600);

  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{

  noInterrupts();
  
  i = micros();
  
  abstand = i-j;
  
  j=i;
  
  if (abstand >= 1000)
  {
   limpuls=abstand;
  }
  else
  {
   kimpuls=abstand;
  }
  periode = kimpuls + limpuls;
  periodes= periode / 1000000;
  frequenz = 1 / periodes;
  wind = 2.58 * (pow(frequenz,0.8927));
  interrupts();


}


void loop()
{

}

Ich würde garnix addieren.

ich würde einfach den kurzen Impuls ignorieren, und nur die micros() bei der Flanke des langen abspeichern.

in etwa so: (keine Garantie, ohne Test schnell geschrieben)

void Interrupt(){
  noInterrupts();  
  i = micros();  
  if (i-j > 1000){  
    periode =i-j;
    j=i;  
    periodes= periode / 1000000;
    frequenz = 1 / periodes;
    wind = 2.58 * (pow(frequenz,0.8927));
    interrupts();
  }
}

Wobei ich nach wie vor die ganze Berechnung ausserhalb des Interrupts machen würde.

Hallo BigBangTheory,

Ich habe vor längerer Zeit auch mit diesem Volkswindmesser eine Wetterstation gebaut.

Das Prellen des Reedkontaktes war damals das erste Problem, ich habe den Reedkontakt ausgebaut und eine kleine Gablellichtschranke (glaube die war aus nem kaputten Drucker) eingebaut.
Dann braucht man noch eine Lochscheibe, damals selbst gebaut - gibt es aber auch zu kaufen.

Wenn ein sauberes Recheckesignal kommt, ist die Sache Softwaremässig einfacher zu händeln.

Dannach stimmen die Werte des Windmessers nicht mehr mit denen überein die vom Hersteller angegeben sind.
Habe damals an einem windstillem Tag das Ding aus dem Auto gehalten und mit einem geeichtem Windmesser eine Tabelle aufgebaut. ( Bin natürlich nicht selbst gefahren)
Ein kleines Testprogramm auf dem Atmel und ein LCD zeigte mir die Impulse pro Sekunde an.

Heute würde ich auch die Impulsdauer messen :wink:

Nachtrag: Mein Anemometer mit Reedkontakt zeigte damals nicht das Verhalten wie jurs beschreibt (also kurzer und langer Impuls)
Mus aber auch zugeben das Posting nicht genau genug durchgelesen zu haben - sorry dafür.

Die ganze Berechnung werde ich denke ich noch aus der Interrupt Routine herausnehmen.

Das Problem an dem ich momentan nicht weiter komme ist, dass wenn ch den von aus der Variable Periode umrechne, also durch 1000000 teile, ich dann in der Ausgabe der Variable periodes sehr merkwürdige Werte erhalte.

Habe ich hier den falschen Variablentyp gewählt?

Das Problem habe ich in meinem letzten Post noch genauer erklärt.

Wär toll wenn ihr mir da helfen könntet :)!

Versuche es mal nach dem Vorschlag von guntherb:

Bei der Umrechnung
Frequenz = 1 / (Periodendauer * Umrechnung);
Bin ich mir nicht sicher. Aber ich weiß, dass der Arduino mit sehr kleinen Zahlen Probleme hat.
Ich würde das eher so lösen:

Umrechnung = 1000000;
Frequenz = Umrechnung / Periodendauer ;

Hey Leute,

ich habe jetzt die Berechnung des ganzen aus der Interrupt in die Loop-Routine überführt. guntherb's Vorschlag mit der Berechnung der Frequenz habe ich ebenso umgesetzt.

Wenn ich mir nun die Periode in Mikrosekunden jede Sekunde anzeigen lasse, funktioniert das wunderbar. Lass ich mir hingegen die Periode anzeigen, dann hakt das ganze und ich seh nur folgende Werte:

1
1
2
2
1
4
1
usw...

Was mache ich hierbei falsch? Muss ich für die Frequenz einen anderen Variablentyp verwenden oder woran kann das ganze liegen?

Hier noch mein aktueller Code:

unsigned long i,abstand,kimpuls,limpuls, periode, Zeitscheibe, frequenz, wind;
unsigned long j=0;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{
  noInterrupts();  
  i = micros();
  interrupts();
}

void loop()
{
  abstand = i-j;

  j=i;
  
  if (abstand >= 1000)
  {
   limpuls=abstand;
  }
  else
  {
   kimpuls=abstand;
  }

  periode = kimpuls + limpuls;
  
  frequenz = 1000000 / periode;
  
  wind = 2.58 * (pow(frequenz,0.8927));
  
  if (millis() > Zeitscheibe )    
  { 
    detachInterrupt(0); 
    
    Zeitscheibe  = millis()+1000;
    
    Serial.print("Windgeschwindigkeit = ");
    Serial.println(wind);
    
    attachInterrupt(0,Interrupt,RISING);
  }
}

Lass ich mir hingegen die Periode anzeigen, dann hakt das ganze und ich seh nur folgende Werte

Du meinst die Frequenz anzeigen ?
Wenn du das Windrad mit der Hand drehst, sind die Werte doch fast plausibel, nur halt etwas ungenau zur späteren Weiterberechnung in Windspeed.
Die Variable frequenz hast du als unsigned long definiert, versuche es mal mit float.

Dein Windmesser (1 imp pro Umdrehung) hat diese Werte, ist auch dein Zitat:

m/s Hz (6 Imp.) Hz (1 Imp.)
1 2,1 0,35
2 4,6 0,77
3 7,0 1,17
4 10,0 1,67
5 12,5 2,08
6 15,0 2,50
7 18,2 3,03
8 20,9 3,48
9 24,3 4,05
10 27,2 4,53
11 30,5 5,08
12 34,0 5,67
13 36,7 6,12
14 39,7 6,62
15 43,2 7,20
16 46,2 7,70
17 49,6 8,27
18 52,5 8,75
19 56,4 9,40
20 59,6 9,93

Ich habe bei der Variable Frequenz schon die Variablentypen unsigned long, float, double usw. ausprobiert. Leider mit keinem guten Ergebnis.

Ist es an dieser Stelle möglich mit dem Arduino folgende Rechenschritte durchzuführen?

Bsp.:

periode = 357016

frequenz = 1000000 / periode = 1000000 / 357016 = 2,8009949133932372778811033679163 Hz

Welchen Variablentyp muss in diesem Fall die Variable Frequenz haben?

Wenn ich für die Frequenz den Variablentyp "float" verwende, erhalte ich folgende Ausgaben: 1.00, 2.00 usw. (immer mit .00).

Wenn ich für die Frequenz den Variablentyp "unsigned long" verwende, erhalte ich folgende Ausgaben: 1, 2 usw..

Wär toll wenn ihr mir da weiter helfen könntet!

Gruß

100000 / periode ist eine Integer (long) - Division

100000.0 / periode ist eine Gleitkomma ( float ) - Division

BigBangTheory:
frequenz = 1000000 / periode = 1000000 / 357016 = 2,8009949133932372778811033679163 Hz

Ich weiß nicht, war meine Schule so streng? Aber wenn ich eine solche Rechnung dem Lehrer in Meßtechnik gezeigt hätte, hätte ich sofort die negativste mögliche Note erhalten.
Wieso?
Du gibst als Ergebnis eine Zahl mit einer Genauigkeit von 32 Stellen an, wo Du doch bei der Messung der Periode nur einen Genauigkeit von +/-0,9% ( 3 Stellen) hast. Dese Genauigkeit ist durch den Systemtakt des Arduinos gegeben und der ist durch den Resonator nicht sonderlich genau.

Also kannst Du nur 2,801 Hz schreiben wobei die Tausendstelstelle schon zweifelhaft ist.

Grüße Uwe

Mein ganzer Fehler lag wohl darin, in der Rechnung frequenz = 1000000 / periode zu schreiben: frequenz = 1000000.0 / periode :D.

Gibt es denn eine Möglichkeit festzulegen, wie viele Nachkommastellen man angezeigt bekommen möchte, wenn man solch eine Float-Division durchführt?

Gibt es denn eine Möglichkeit festzulegen, wie viele Nachkommastellen man angezeigt bekommen möchte

Ja, mehrere.
Ist ausserdem keine Frage der Division, sondern der Anzeige.
Schau dir mal Serial.print an