Auswertung Impulse Volkswindmesser

Hi Leute,

ich habe mir einen ersten Code erarbeitet, bei dem momentan die Periodendauern (HIGH + LOW) in einem großen Array gespeichert werden. Nach dem Messintervall werden alle Werte des Arrays addiert, sowie im Anschluss durch die Periodenanzahl geteilt, sodass ich einen Mittelwert bekomme.
Der Code funktioniert noch nicht richtig, ist aber denk ich erstmal eine gute Grundlage.
Ich bin hierbei davon ausgegangen, dass wenn ein "HIGH-Signal" anliegt und ich dessen Länge messe, hiernach direkt ein LOW-Signal folgen muss, welches die erste Messung beendet und die Messung der Länge des LOW-Signals startet, und umgekehrt.

Was sagt ihr dazu? Wo sollte ich noch Veränderungen am Code vornehmen und wie kann man ihn noch besser machen, sodass er auch bei langsamen Windgeschwindigkeiten richtig funktioniert?

Bin ich vielleicht mit dem Code auch auf dem totalen Holzweg? Lasst euch aus darüber :)!

int AnemometerPin = 2;
int Messintervall = 1000;
int StartZeit = 0;
int EndZeit = 0;
int i = 0;
int j = 0;
int k = 0;
int HIGHZeit = 0;
int LOWZeit = 0;
int Periodendauer;
int PinStatus;
int Anzahl;
float SummePulsdauer = 0;
float Mittelwert = 0;
float pulsearray[99];


void setup()
{
  Serial.begin(9600);
  pinMode(AnemometerPin, INPUT);
  
}

void loop()
{
  for (k = 0; k < 100; k++)
  {
    pulsearray[k]=0;
  }
  
  StartZeit = EndZeit;
  
  i = 0;

  Mittelwert = 0;
  
  SummePulsdauer = 0;

  while (EndZeit-StartZeit < Messintervall)
  {
    
    PinStatus = digitalRead(AnemometerPin);
    
    if (PinStatus == HIGH)
    {
      HIGHZeit = pulseIn(AnemometerPin, HIGH);
      LOWZeit = pulseIn(AnemometerPin, LOW);
    }
    else if (PinStatus == LOW)
    {
      LOWZeit = pulseIn(AnemometerPin, LOW);
      HIGHZeit = pulseIn(AnemometerPin, HIGH);
    }
    Periodendauer = HIGHZeit + LOWZeit;
    
    pulsearray[i]=Periodendauer;
    
    i++;
   
    EndZeit = millis();  
    
    Anzahl = i;
  }
  for (j=0; j<=Anzahl; j++){
  
  SummePulsdauer = SummePulsdauer + pulsearray[j];
  }
  
  Mittelwert = SummePulsdauer / Anzahl;
  
  Serial.print("Pulsdauer Mittelwert:  ");
  Serial.println(Mittelwert);
}

Vielen Dank schonmal für eure vielen tollen Antworten zu diesem Thema, die bisher kamen und hoffentlich noch weiter kommen :)!

Hallo,

nur zwei Anmerkungen:

  1. wenn du den Pinstatus nur im Loop abfragst, um die Zeiten zu ermitteln, dann bekommst du zwangsläufig Ungenauigkeiten, weil der Durchlauf des Loops ja auch Zeit braucht. Besser wäre hier ein Interrupt.
  2. Du versuchst die Zeiten HIGH und LOW zu messen, addierst die auf um einen Mittelwert übers Speicherintervall zu bilden. Damit errechnest du dir die Anzahl der Pulse pro Speicherintervall. Einfacher (und genauer) wäre es hier, die Impulse zu zählen. Das ist letztlich genau das, was du gerade machst, nur du machst es aufwändig, umständlich und Fehlerbehaftet.

Die Sache mit der gemessenen und im Anschluss gemittelten Periodendauer pro Sekunde um hieraus die "gemittelte" Frequenz zu berechnen, schien mir irgendwie logisch. Daher habe ich versucht das ganze über den Weg der Periodendauermessung zu beschreiten.

Ich habe den Code jetzt in Richtung Interrupt angepasst. Jetzt bekomm ich aber gar keinen Wert mehr ausgegeben :D. Was habe ich hier falswch gemacht?

int AnemometerPin = 2;
int Messintervall = 1000;
int StartZeit = 0;
int EndZeit = 0;
int i = 0;
int j = 0;
int k = 0;
int Periodendauer;
int PinStatus;
int Anzahl;
int last;
float SummePulsdauer = 0;
float Mittelwert = 0;
float pulsearray[99];
unsigned long m;
unsigned long v;


void setup()
{
  Serial.begin(9600);
  pinMode(AnemometerPin, INPUT);
  attachInterrupt(0,UebergangHighLow, RISING);
}

void loop()
{
  for (k = 0; k < 100; k++)
  {
    pulsearray[k]=0;
  }
  
  StartZeit = EndZeit;
  
  i = 0;

  Mittelwert = 0;
  
  SummePulsdauer = 0;

  while (EndZeit-StartZeit < Messintervall)
  {
   
    pulsearray[i]=Periodendauer;
    
    i++;
   
    EndZeit = millis();  
    
    Anzahl = i;
  }
  for (j=0; j<=Anzahl; j++){
  
  SummePulsdauer = SummePulsdauer + pulsearray[j];
  }
  
  Mittelwert = SummePulsdauer / Anzahl;
  
  Serial.print("Pulsdauer Mittelwert:  ");
  Serial.println(Mittelwert);
}

void UebergangHighLow()
{
  detachInterrupt(0);                         // Interrupt ausschalten damit er uns nicht 
  m = millis();                               // Millisekundenzähler auslesen
  v = m - last;                               // Differenz zum letzten Durchlauf berechnen
  if (v > 10) {                               // ignorieren wenn <= 10ms (Kontaktpreller)
  Periodendauer = v;                          // Wert in Periodendauer übernehmen
  last = m;                                   // und wieder den letzten Wert merken
  }
  attachInterrupt(0, UebergangHighLow, RISING );
}

Ich messe hierbei die Zeit vom Übergang HIGH zu LOW bis dieser wieder auftaucht. Das müsste ja genau der Periodendauer entsprechen, oder? Dieser Wert der Periodendauer wird dann in das Array geschrieben, die Anzahl der Array-Elemente gezählt und im Anschluss der Mittelwert gebildet und ausgegeben. Trotzdem muss ich mich hier irgendwo verhaspelt haben, da ich momentan gar keine Ausgabe mehr bekomme.

Gruß Alex

Hallo Alex,

spontan fällt mir auf:

  • zu zählst in loop eine whileschleife hoch, in der du erwartest, dass bei jedem Schleifendurchgang ein neuer Wert "Periodendauer" zur Verfügung steht. aber du weißt ja nicht, wann der Impuls kommt und deinen Interrupt auslöst, das sind Prozesse die parallel und voneinander unabhängig laufen!
  • deine Interruptroutine ist sehr lang. Interruptroutinen sollten so knapp wie möglich sein. ich würde in der Interruptroutine nur den aktuellen Micros()-Wert in einem Array abspeichern und einen (globalen) Indexzähler hochsetzen.
void UebergangHighLow()
{
  detachInterrupt(0);                         // Interrupt ausschalten damit er uns nicht 
  m[i++] = micros();                               // Microsekundenzähler auslesen
  attachInterrupt(0, UebergangHighLow, RISING );
}

Und dann erst in der Auswertung die Zeiten ausrechen:

{
  detachInterrupt(0);   
  Periodendauer = (m[i-1] - m[0])/(i-1);
  i = 0;
  attachInterrupt(0, UebergangHighLow, RISING );
}

generell solltest du aber versuchen mit "Serial.print" an den verschiedenen Stellen des Codes versuchen rauszufinden was wo gerechnet wird, ob der Interrupt überhaupt aufgerufen wird, etc.
Diese Form von debuggen ist unverzichtbar. Ich hatte schon funktionen, da habe ich nach jeder Codezeile mit "Serial.print" alle Variablen ausgegeben, weil ich den Fehler anders nicht gefunden habe.

Diese Form von debuggen ist unverzichtbar...

... geht nur nicht gut innerhalb der Interrupt-Routine.

Eigentlich ist es ganz tabu, aber 64 Zeichen passen in den Ausgabepuffer, und werden dann am Ende von loop() gesendet.
Aber die Interrupt-Routine darf nicht auf das Leeren des Puffers warten müssen.

michael_x:
... geht nur nicht gut innerhalb der Interrupt-Routine.

Richtig.

aber man kann im Interrupt ein Flag setzen, und dieses in der Loop auswerten...

Was ich jetzt irgendwie noch nicht ganz verstanden habe ist:

In loop werte ich dann die Zeiten aus, welche ich in der Interrupt-Routine an mein Array m übergeben habe und berechne die Zeit zwischen der jetztigen und dem vorherigen Interrupt, oder?

Auf der einen Seite, dem Interrupt, speicher ich die jeweilige Zeit in der der Interrupt kam. Auf der anderen Seite, im loop werte ich die Zeiten aus. Wie kann ich es nun realisieren, dass ich mir quasi einen Mittelwert über alle Zeiten (Periodendauern) die innerhalb einer Sekunde aufgetreten sind, ausgeben lasse, durch den ich dann, pro Sekunde eine mittlere Frequenz habe?

Da komm ich gerad irgendwie nicht weiter.

Eigentlich hast du es richtig erfasst.

Betracht das mal als zwei Arbeiter:

der eine, Arbeiter1, notiert bei jedem jedem Impuls die aktuelle Zeit und schreibt sie auf ein Blatt. (Deine Array "m")
dann kommt der andere nach einer festgelegten Zeit (1sec) vorbei.
Er nimmt das Blatt und rechnet die Zeiten aus.
Dann gibt er Arbeiter1 wieder ein neues Blatt (i=0), und läßt ihn wieder Zeiten aufschreiben.
Bis wieder eine sekunde um ist.

Klar?

das habe ich verstanden :).

es funktioniert dann ja auch nicht mit einer while-routine, weil ich ja theoretisch nix mache, in der sekunde, außer das ich immer wieder durch die interrupts unterbrochen werde.

müsste ich dann in der loop-routine mit nem delay (1000) arbeiten, um jede sekunde diese routine zu starten, welche dann die zeiten der interrupts (das array) auswertet und dann gemittelt als periodendauer bzw. frequenz ausgibt, oder wie wär es am geschicktesten, die ausgabe pro sekunde zu erstellen?

dort häng ich momentan. vllt. ist es ja auch ganz trivial, nur irgendwie will ich von dem schlauch nicht runter, auf dem ich stehe :D.

vielen vielen dank aber schonmal für eure tollen antworten und die super unterstützung die ich hier bisher erlebt habe!!

Nein! Auf keinen Fall delay()!

Das machst du mit millis() Abfrage.

  if (millis() > Zeitscheibe_1sek )      // Zeitscheibe wird alle 1000ms aufgerufen
  { Zeitscheibe_1sek  = millis()+1000;  
   // mach deine Auswertung
  }

Schau dir dazu auch mal das Beispiel "Blink ohne Delay" an.

Hallo Leute,

ich hab das bisher hier von euch gelernte nun in folgendem Code umgesetzt:

int Zeitscheibe;
int i = 0;
int j = 0;
float Periodendauer = 0;
float SummePeriodendauer = 0;
float Umrechnung = 0.000001;
float Frequenz = 0;
volatile float m[100];

void setup()
{
  Serial.begin(9600); //starten der seriellen Kommunikation
  attachInterrupt(0,Interrupt,RISING); //wenn ein Signal von LOW nach HIGH an digital Pin 2 eingeht, wird die Interrupt-Routine "Interrupt" gestartet 
}

void Interrupt() //Interrupt-Routine
{
  m[i++] = micros(); //in das Array wird, wenn der Interrupt ausgelöst wird, die jeweilige Zeit seitdem das Programm gestartet wurde, in Mikrosekunden, gespeichert
}

void loop() //loop-Routine
{
 if (millis() > Zeitscheibe )      // wird jede Sekunde aufgerufen
  { 
   detachInterrupt(0); //Interrupt wird zur Auswertung des Arrays vorübergehend außer Kraft gesetzt
    Zeitscheibe  = millis()+1000;  //Berechnung der neuen Größe der Zeitscheibe
    for (j=0; j==i; j++)
    {
      SummePeriodendauer = SummePeriodendauer + (m[i+1]-m[i]); //Aufsummierung der Periodendauern zwischen den Interrupts
      
      Periodendauer = SummePeriodendauer / i; //gemittelte Periodendauer innerhalb einer Sekunde in Mikrosekunden
      
      Frequenz = 1 / (Periodendauer * Umrechnung); //Frequenzberechnung
      
      Serial.print("Frequenz:  "); //Ausgabe der gemittelten
      
      Serial.println(Frequenz);//Frequenz pro Sekunde auf dem Serial Monitor
      
    }
      j = 0; //Zuruecksetzen der 
      
      i = 0; //Zaehlvariablen
    
    
    attachInterrupt(0,Interrupt,RISING); //Interrupt kann wieder ausgeführt werden
  } 
}

Der Serial Monitor zeigt mir als Ausgabe wenn der Windmesser steht als Frequenz brav 0.00 an. Sobald ich ihn jedoch in Bewegung versetze, wird mir nix mehr ausgegeben, obwohl ich doch in der Auswertungsroutine (loop) extra den Interrupt während der Auswertung und der Ausgabe unterbinde.

Woran kann es liegen, dass mir nur "richtige" Werte ausgegeben werden, wenn der Windmesser steht?

P.S. Starte ich nur den Serial Monitor, bewege den Windmesser aber noch nicht, wird mir folgendes ausgegeben: Frequenz: nan

Woran kann das liegen?

Gruß Alex

Hallo,

ein paar Sachen, die mir aufgefallen sind:

int Zeitscheibe; muss heißen:
unsigned long Zeitscheibe; weil die Funktionen millis() und micros() einen unsigned long Wert liefern.

for (j=0; [b]j==i[/b]; j++)
    {
      SummePeriodendauer = SummePeriodendauer + ([b]m[i+1][/b]-m[i ]);

Da stecken drei Fehler drin:

  • Die for-Schleife wird durchlaufen, solange die Bedingung "true", also erfüllt ist. Deine Bedingung i==j ist aber nur erfüllt, wenn das Array leer ist, also bei Windstärke Null!.
  • Du fragst in der Schleife das Array mit "i" ab, deine Laufvariable ist aber "j"
  • Du fragst in der Schleife eine Arrayplatz "j+1" ab, als darf j nur bis "i-1" laufen.
    Also:
for (j=0; [b]j<i[/b]; j++)
    {
      SummePeriodendauer = SummePeriodendauer + (m[[color=maroon]j[/color]+1]-m[[color=maroon]j[/color]]);

Aber dies Schleife ist meiner Meinung sowieso überflüssig:
Du mußt nicht die Dauer jeden einzelnen Pulses ausrechnen und diese Summieren.
SummePeriodendauer = m[i]-m[0]; erfüllt genau den gleichen Zweck!
Schreib dir mal eine Reihe von Zahlen auf und rechne es nach.

j = 0; //Zuruecksetzen der brauchts nicht. j wird autmatisch in der for-schleife zurückgesetzt.

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 ;

Generell:
Wenn deine Code Sachen macht, die du nicht verstehst, da fragt mit "Serial.print" an den verschiedenen Stellen die zwischenergebnisse ab.

z.B. würde ich mir mal den Inhalt des Array anzeigen lassen. Also in der Zeitscheibe als erstes:

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

Und dann aber auch mal die Zwischenergebnisse jeweils ansehen:

Serial.print("SummePeriodendauer: ");Serial.println(SummePeriodendauer);

und

Serial.print("Periodendauer: ");Serial.println(Periodendauer);

Das sind dann Hilfen um rauszufinden, was der Arduino überhaupt rechnet.

und, was mir gerade noch auffällt:
Deine for-Schleife ist erst sehr spät geschlossen.
Ich denke da fehlt eine geschweifte Klammer:
for (j=0; j==i; j++)
{
SummePeriodendauer = SummePeriodendauer + (m[i+1]-m[ i]);
}

Grüße

Gunther

Hallo Leute,

ich hab meinen Quellcode modifiziert, mir mittels Excel ne näherungsweise Gleichung zu den Frequenz - Windgeschwindigkeits-Werten erzeugt, welche ich in meinem Quellcode nutze, sowie die einzelnen Schritte per "Serial.println..." angesehen um genau zu verstehen, was an welcher Stelle meines Programms geschieht.

Hier mal mein bisheriger Quellcode:

unsigned long Zeitscheibe;
unsigned long m[99];
int i = 0;
float Periodendauer = 0;
float Umrechnung = 1000000;
float Frequenz = 0;
float Windgeschwindigkeit;

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

  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{

  m[i++] = micros();

  Serial.println(m[i]);


}


void loop()
{
 if (millis() > Zeitscheibe )    
  { 
    detachInterrupt(0); 
    
    Zeitscheibe  = millis()+1000; 

    Periodendauer = (m[i] - m[0]) / i;
   
    Frequenz = Umrechnung / (Periodendauer); 
    
    Windgeschwindigkeit = 2.58 * (pow(Frequenz,0.8927));         
    
/*    Serial.print("Windgeschwindigkeit:  "); 
      
    Serial.println(Windgeschwindigkeit);
*/    
    Periodendauer = 0;
    
    i = 0; 
    
    attachInterrupt(0,Interrupt,RISING);
  }

}

Ich lasse mir momentan die Werte des Interrupts direkt im Interrupt ausgeben, sodass ich sehen kann, welche Werte im Array abgespeichert werden. Hierbei ist mir aufgefallen, dass immer der aktuelle micros() Wert und danach der Wert 0 abgespeichert wird.
Hat einer von euch eine Idee, wieso das passiert?

Hier mal ein Ausschnitt aus meinem Serial Monitor:

Vielen Dank schonmal für eure Hilfe :)!

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