Forum: Mikrocontroller und Digitale Elektronik Arduino Drehzahlmesser


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Nick S. (kolbi)


Bewertung
6 lesenswert
nicht lesenswert
Hallo,

Ich möchte die Drehzahl einer Lochscheibe mit dem Arduino Nano 
überwachen, und auf ein LCD ausgeben.

Schaltung mit Lischtschranken und Schmidt Trigger ist aufgebaut und gibt 
ein sauberes Rechteck aus.

Die Scheibe hat 12 Löcher, und eine Drehzahl von knapp 1000 bis max 
20.000 Umdrehungen.

Ich bräuchte sogesehen nur den passenden Code.


Kann mir dabei bitte jemand helfen?

von Cyblord -. (cyblord)


Bewertung
2 lesenswert
nicht lesenswert
Nick S. schrieb:
> Hallo,
>
> Ich möchte die Drehzahl einer Lochscheibe mit dem Arduino Nano
> überwachen, und auf ein LCD ausgeben.
>
> Schaltung mit Lischtschranken und Schmidt Trigger ist aufgebaut und gibt
> ein sauberes Rechteck aus.
>
> Die Scheibe hat 12 Löcher, und eine Drehzahl von knapp 1000 bis max
> 20.000 Umdrehungen.
>
> Ich bräuchte sogesehen nur den passenden Code.

Dann würde ich an deiner Stelle anfangen zu programmieren. So gesehen.

von Arduinoquäler (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Nick S. schrieb:
> Ich bräuchte sogesehen nur den passenden Code.

Ja, genau .... das ist schnell erledigt. Das Forum entwickelt für dich.

Nick S. schrieb:
> Schaltung mit Lischtschranken und Schmidt Trigger ist aufgebaut und gibt
> ein sauberes Rechteck aus.

Bis über 200 KHz ...... sicher ?

von Route_66 H. (route_66)


Bewertung
2 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Bis über 200 KHz ...... sicher ?

4 kHz sollten reichen!

von MaWin (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Ja, genau .... das ist schnell erledigt. Das Forum entwickelt für dich.

Schon fertig, http://www.mikrocontroller.net/articles/Drehzahlmesser
muss er nur noch

aber nicht von dir, denn du...

> Bis über 200 KHz ...... sicher ?

...kannst nicht mal Sekunden und Minuten auseinanderhalten.

von Arduinoquäler (Gast)


Bewertung
-4 lesenswert
nicht lesenswert
MaWin schrieb:
> ...kannst nicht mal Sekunden und Minuten auseinanderhalten.

Was kann ich denn noch alles nicht .....

von Arduinoquäler (Gast)


Bewertung
2 lesenswert
nicht lesenswert
MaWin schrieb:
> ...kannst nicht mal Sekunden und Minuten auseinanderhalten.

Von Minuten war nicht die Rede.

Default-Zeiteinheit ist Sekunde.

von MaWin (Gast)


Bewertung
-4 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Was kann ich denn noch alles nicht

Offensichtlich eine Menge, denn du merkst noch nicht mal,
wenn man dich vorsichtig auf deinen Fehler aufmerksam macht
und hast es immer noch nicht begriffen. Merkbefreit.

von Nick S. (kolbi)


Bewertung
2 lesenswert
nicht lesenswert
Die Schaltung von http://www.mikrocontroller.net/articles/Drehzahlmesser 
ist ganz was anderes.

Ich habe einen Arduino Nano, und brauche den entsprechenden Code dazu.

Umdrehungen beziehen sich auf eine Minute, wenns Anfangs keine 20.000 
upm schafft ist egal, sonst kann ich eine Lochscheibe mit nur einem Loch 
montieren. Wär nur schön wenn ich bis knapp unter 1000U/min eine Anzeige 
auf einem LCD hätte.

Es handelt sich um ein 2x16 Zeilen LCD, das ist in den Arduinobeispielen 
dabei, aber kennen mich damit zuwenig aus, bzw funktioniert kaum ein 
Programm von mir :(


lg

von Dieter F. (Gast)


Bewertung
-8 lesenswert
nicht lesenswert
Um wenigstens etwas konstruktives beizutragen:

http://www.pyroelectro.com/tutorials/tachometer_rpm_arduino/

Wenn Du etwas Englisch verstehst ...

Deine Anpassung wäre also (time*7) durch (time*12) zu ersetzen - und die 
richtigen PINs auszuwählen.

von Nick S. (kolbi)


Angehängte Dateien:

Bewertung
7 lesenswert
nicht lesenswert
Hallo Dieter, danke für den Link, habs nach langer Fehlersuche 
tatsächlich hinbekommen, Bild im Anhang :)

Aber die Verzögerung ist jenseits von gut und böse, gibts irgenwo ein 
Tut mit dem Capture Register und Compare Match, etc?

In diesem Thread Beitrag "Re: Zündkurve verstellen beim 2Takter" hat 
mir Max.D schon einiges an Anregungen gegeben, aber selber schaff ich 
das leider nicht :(


Lg, Kolbi

von Thomas W. (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Arduinoquäler schrieb:
> Default-Zeiteinheit ist Sekunde.

Seit wann gibt es Default-Einheiten?

von Dieter F. (Gast)


Bewertung
-10 lesenswert
nicht lesenswert
Nick S. schrieb:
> Aber die Verzögerung ist jenseits von gut und böse

Ja, da wird mit Absicht verzögert - nicht unbedingt optimal ... wie 
eigentlich der komplette Code, wenn man genauer hinschaut.

Ich habe keine Ahnung, ob micros() in float kommen - aber das einfach 
mal übernommen (bin kein Arduino-Nutzer).

Probier mal

...
  //Main Loop To Calculate RPM and Update LCD Display
  void loop()
  {
    int rpm = 0;
    int last_rpm = 1;
    char buffer[7];
  
    while(1)
    {    
      //Update The RPM
      if(time > 0)
      {
        //Alternativ 
        rpm = 5000000 / time;
        //Mitteln - akt. Wert Faktor 3 und letzter Wert Faktor 1  
        rpm = ((rpm + (rpm<<1) + last_rpm)>>2);

        //ODER - wie bisher
        //5 Sample Moving Average To Smooth Out The Data
        rpm_array[0] = rpm_array[1];
        rpm_array[1] = rpm_array[2];
        rpm_array[2] = rpm_array[3];
        rpm_array[3] = rpm_array[4];
        rpm_array[4] = 60*(1000000/(time*12));    
        //Last 5 Average RPM Counts Eqauls....
        rpm = (   rpm_array[0] + rpm_array[1] + rpm_array[2] 
                + rpm_array[3] + rpm_array[4]                ) / 5;
      }

      if(rpm != last_rpm)
      {
        //Update The Rpm Count
        lcd.setCursor(0, 1);
        sprintf(buffer,"%5i",rpm);
        lcd.print(buffer);   
      }
      last_rpm = rpm;
    }
  }

  //Capture The IR Break-Beam Interrupt
  void fan_interrupt()
  {
    float time_act;
    time_act = (micros);
    time = (time_act - time_last); 
    time_last = time_act;
  }

Glücklich bin ich mit der Lösung nicht - wenn ca. 7000 Umdrehungen pro 
Minute überschritten werden geht es "in die Hose". Aus 
Performance-Gründen würde ich die "Alternative" ausprobieren ...

Wie geschrieben bin ich kein Arduino-Spezialist und würde es wohl auf 
"normaler" AVR-Ebene anders lösen. Hoffentlich schaut Karl-Heinz hier 
nicht hin, sonst bekomme ich Hiebe :-)

von Dieter F. (Gast)


Bewertung
-11 lesenswert
nicht lesenswert
Übrigens: Interessant, was Du da gebaut hast.

Habe mir den 2-Takter-Thread auch mal angeschaut. Da bin ich aber 
mechanisch  deutlich zu weit entfernt ... bin zwar vor Ur-Zeiten mal 
Quickly gefahren (immer eine Vergaser-Füllung weit), aber das ist lange 
her :-)

von Dieter F. (Gast)


Bewertung
-13 lesenswert
nicht lesenswert
Thomas W. schrieb:
> Seit wann gibt es Default-Einheiten?

Seit Sternzeit 153498.45798,54 oder so ...

von Nick S. (kolbi)


Bewertung
1 lesenswert
nicht lesenswert
Leider funktioniert da was nicht, ich bekomme die Fehlermeldung: error: 
cannot convert 'long unsigned int()' to 'float' in assignment


Wenns am Arduino liegt dass das so aufwändig ist, dann kauf ich mir gern 
andere Hardware...

Lg

von Dieter F. (Gast)


Bewertung
-11 lesenswert
nicht lesenswert
Nick S. schrieb:
> ich bekomme die Fehlermeldung: error:
> cannot convert 'long unsigned int()' to 'float' in assignment

Kannst Du bitte mal das KOMPLETTE aktuelle Coding plus ALLE 
(Fehler)-Meldungen hier einstellen? Danke ...

Nur zur Information: Mit der Meldung selbst (ohne Zeilen-Referenz) kann 
niemand etwas anfangen. Die Zeilen-Referenz bringt auch nur etwas, wenn 
man das komplette, zugrunde liegende Coding kennt ...

von Wolfgang A. (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Nick S. schrieb:
> ich bekomme die Fehlermeldung: error:
> cannot convert 'long unsigned int()' to 'float' in assignment

Und was steht in der betreffenden Code-Zeile

Dieter Frohnapfel schrieb:
> Ich habe keine Ahnung, ob micros() in float kommen - aber das einfach
> mal übernommen (bin kein Arduino-Nutzer).

Google kennst du?
"arduino micros" hilft in diesem Fall weiter ;-)
http://arduino.cc/en/reference/micros

von Dieter F. (Gast)


Bewertung
-11 lesenswert
nicht lesenswert
Wolfgang A. schrieb:
> Google kennst du?

Nö, was ist das? Du kannst ja gerne weiterhelfen, da Du ja optimal 
informiert bist :-) Ich klinke mich damit aus ...

von Dieter F. (Gast)


Bewertung
-11 lesenswert
nicht lesenswert
Wolfgang A. schrieb:
> Und was steht in der betreffenden Code-Zeile

Aber Lesen kannst Du schon

Dieter Frohnapfel schrieb:
> Kannst Du bitte mal das KOMPLETTE aktuelle Coding plus ALLE
> (Fehler)-Meldungen hier einstellen? Danke ...

gut, das freut mich, mach mal weiter ... und gute Nacht etc. an alle

von Nick S. (kolbi)


Bewertung
0 lesenswert
nicht lesenswert
Leute, Leute, bitte lockerbleiben, Gefühle haben hier nix verloren, nur 
Technik bitte! ^^

Ich wollte mit meinem letzen Post wirklich nicht undankbar klingen oder 
so, danke an alle, die sich bisher die Mühe gemacht haben da was 
weiterzubringen!


Hier die komplette Fehlermeldung:

Drehzahlmesser.ino: In function 'void fan_interrupt()':
Drehzahlmesser.ino:63:14: error: cannot convert 'long unsigned int()' to 
'float' in assignment
Error compiling.

Ganz schlau werde ich daraus nicht, ist der Fehler in Zeile 63, oder wie 
ist das zu verstehen?

Keine Ahnung ob der Schmitt-Trigger nötig ist, werds demnächst ohne 
probieren und berichten.


Lg!

: Bearbeitet durch User
von Dieter F. (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
O.K. - ein paar minus-Bewertungen kann ich noch gebrauchen :-)
Lt. Gurgel soll es also unsigned long sein - daher:


  #include <LiquidCrystal.h>
  LiquidCrystal lcd(3, 5, 9, 10, 11, 12);

  volatile unsigned long time = 0;
  volatile unsigned long time_last = 0;
  volatile int rpm_array[5] = {0,0,0,0,0};

  void setup()
  {
    //Digital Pin 2 Set As An Interrupt
    attachInterrupt(0, fan_interrupt, FALLING);

    // set up the LCD's number of columns and rows: 
    lcd.begin(16, 2);
    // Print a message to the LCD.
    lcd.print("Drehzahl:");
  }


  //Main Loop To Calculate RPM and Update LCD Display
  void loop()
  {
    int rpm = 0;
    int last_rpm = 1;
    char buffer[7];
  
    while(1)
    {    
      //Update The RPM
      if(time > 0)
      {
        //Alternativ 
        rpm = 5000000 / time;
        //Mitteln - akt. Wert Faktor 3 und letzter Wert Faktor 1  
        rpm = ((rpm + (rpm<<1) + last_rpm)>>2);

        //ODER - wie bisher
        //5 Sample Moving Average To Smooth Out The Data
        rpm_array[0] = rpm_array[1];
        rpm_array[1] = rpm_array[2];
        rpm_array[2] = rpm_array[3];
        rpm_array[3] = rpm_array[4];
        rpm_array[4] = 60*(1000000/(time*12));    
        //Last 5 Average RPM Counts Eqauls....
        rpm = (   rpm_array[0] + rpm_array[1] + rpm_array[2] 
                + rpm_array[3] + rpm_array[4]                ) / 5;


        time = 0;
      }

      if(rpm != last_rpm)
      {
        //Update The Rpm Count
        lcd.setCursor(0, 1);
        sprintf(buffer,"%5i",rpm);
        lcd.print(buffer);   
      }
      last_rpm = rpm;
    }
  }

  //Capture The IR Break-Beam Interrupt
  void fan_interrupt()
  {
    unsigned long time_act;
    time_act = (micros);
    time = (time_act - time_last); 
    time_last = time_act;
  }

Wieso bei Dir die volatile float-Deklarationen zu Beginn keine 
Fehlermeldung auslösen ist mir allerdings ein Rätsel (es sei denn, Du 
hast die gar nicht übernommen ... aber Deinen Code kann ich ja nicht 
sehen ...)

Habe noch ein "time = 0" eingebaut, damit nicht unsinnig bei jedem 
Durchlauf gerechnet wird.

von Minusgeber (Gast)


Bewertung
3 lesenswert
nicht lesenswert
Dieter Frohnapfel schrieb:
> Habe noch ein "time = 0" eingebaut, damit nicht unsinnig bei jedem
> Durchlauf gerechnet wird.

Dafür kriegst Du ein dickes Minus für das time = 0!

von Nick S. (kolbi)


Bewertung
0 lesenswert
nicht lesenswert
Es geht auch ohne Schmitt Trigger, wieder ein Bauteil gespart ;)


Da ich die Wertemittelung eigentlich gar nicht brauche, hab ich den Code 
dementsprechend geändert:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 13);

volatile float Zeit = 0;
volatile float Vorherige_Zeit = 0;

void setup()
{
  //Digital Pin 2 ist jetzt ein Interrupt und reagiert auf fallende Flanken
 attachInterrupt(0, Sensor_Interrupt, FALLING);

  // 2x16 LCD Display einrichten
  lcd.begin(16, 2);
  // Drehzahl auf dem LCD Ausgeben
  lcd.print("Umdrehungen/Min");
}

//Hauptschleife zum Berechnen der Drehzahl und LCD Displayupdate
void loop()
{
  int upm = 0;
  
  while(1){    

     //Displayupdates verzögern
    delay(200);
  
  //Letzte Reihe löschen
  lcd.setCursor(0, 1);
  lcd.print("                ");   
  
  //Drehzahl ausgeben
  lcd.setCursor(0, 1);
  lcd.print(upm);   

lcd.setCursor(4, 1);
lcd.print(time);   

  //Drehzahlberechnung, *12 für die Anzahl der Impulse (Lochscheibe, Lüfterflügel,...)
  if(Zeit > 0)
  {
        upm = 60*(1000000/(Zeit*12));
  }
 
 }
}

//Interrrupt Capture
void Sensor_Interrupt()
{
   Zeit = (micros() - Vorherige_Zeit); 
   Vorherige_Zeit = micros();
}


Zum messen hoher Drehzahlen würd ich die Drehzahl einfach auf 10er oder 
100er Stellen runden.


Herzlichen Dank für die Hilfe, Projekt fertig! :)

Lg

von Nick S. (kolbi)


Bewertung
0 lesenswert
nicht lesenswert
Sorry, hab das alte Programm erwischt, so müssts gehn:



#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 13);

volatile float Zeit = 0;
volatile float Vorherige_Zeit = 0;

void setup()
{
  //Digital Pin 2 ist jetzt ein Interrupt und reagiert auf fallende Flanken
 attachInterrupt(0, Sensor_Interrupt, FALLING);

  // 2x16 LCD Display einrichten
  lcd.begin(16, 2);
  // Drehzahl auf dem LCD Ausgeben
  lcd.print("Umdrehungen/Min");
}

//Hauptschleife zum Berechnen der Drehzahl und LCD Displayupdate
void loop()
{
  int upm = 0;
  
  while(1){    

     //Displayupdates verzögern
    delay(200);
  
  //Letzte Reihe löschen
  lcd.setCursor(0, 1);
  lcd.print("                ");   
  
  //Drehzahl ausgeben
  lcd.setCursor(0, 1);
  lcd.print(upm);   


  //Drehzahlberechnung, *12 für die Anzahl der Impulse (Lochscheibe, Lüfterflügel,...)
  if(Zeit > 0)
  {
        upm = 60*(1000000/(Zeit*12));
  }
 
 }
}

//Interrrupt Capture
void Sensor_Interrupt()
{
   Zeit = (micros() - Vorherige_Zeit); 
   Vorherige_Zeit = micros();
}

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
2 Dinge

In loop() willst du die Endlosschleife
  while(1)
nicht haben.


Das Arduino Framework ist so aufgebaut, dass es dir ein main() vorgibt, 
welches vom Prinzip her so aussieht
int main()
{
  Arduino Initialisierungen

  setup();

  sei();

  while( 1 ) {

    loop();

    Ardiuno Framework interne Buchhaltung
  }
}

Die obligate Endlosschleife steckt bereits in diesem vorgegebenem main() 
drinnen, welches du nicht selbst schreibst. D.h. die Funktion loop() 
wird laufend ohne dein Zutun aufgerufen und das willst du auch so haben, 
damit das Framework die Chance kriegt ihre eigene Buchhaltung zu 
erledigen.

Dein
void loop()
{
  ...
  while(1) {    
    ...
  }
}

ist daher kontraproduktiv. Denn genau letzters, dem Framework die 
Möglichkeit zu geben ihre eigenen Dinge zu erledigen, unterbindest du 
damit.


Das andere ist der delay, den du da drinnen hast. Du willst keinen delay 
haben (ausser ganz kurze)! Denn in dieser Zeit kann der µC nichts 
anderes machen als Däumchen drehen und noch ISR abarbeiten. Das ist dir 
aber zu wenig.
Zeitsteuerungen im Arduino Framework funktionieren so (am Beispiel mit 
Millisekunden
unsigned long lastDone;

void setup()
{
  lastDone = millis();
}

void loop()
{
  unsigned long now = millis();

  if( now - lastDone > duration ) {
    lastDone = now;

    ... mache, was auch immer du im Abstand 'duration' gemacht haben willst
  }
}

Auf die Art vermeidest du das unproduktive Däumchen drehen. Das Prinzip 
ist simpel: Wenn du alle 5 Sekunden eine Aktion machen willst und deine 
Uhr hat bei der letzten Aktion den Sekundenzeiger auf 20 gehabt, dann 
ist die nächste Aktion fällig, wenn der Sekundenzeiger auf 25 steht.

Was anderes hast du im Prinzip hier
void Sensor_Interrupt()
{
   Zeit = (micros() - Vorherige_Zeit); 
   Vorherige_Zeit = micros();
}
auch nicht gemacht. Nur dass natürlich die Verwendung von float an 
dieser Stelle den programmtechnischen Supergau darstellt und du nicht 2 
mal micros() aufrufen willst, weil du ja keine Gewähr hast, dass sich 
der Wert in der Zwischenzeit nicht geändert hat (mal abgesehen vom 
unnötigen Zeitbedarf für den Aufruf)

: Bearbeitet durch Moderator
von Nick S. (kolbi)


Bewertung
0 lesenswert
nicht lesenswert
Leider blicke ich nicht ganz durch..

Kannst du bitte den kompletten Sketch posten? Dann könnt ich das 
vergleichen und probieren.

Lg!

von Karl H. (kbuchegg) (Moderator)


Bewertung
-1 lesenswert
nicht lesenswert
Nein. Sorry.
Es ist dein Projekt und du lernst gefälligst programmieren.

Ausserdem denke ich, dass ich mehr als ausführlich die Motivation und 
die Hintergünde geschildert habe. Einfach Copy&Paste und gut ist spielt 
es bei mir nicht mehr. Nicht auf diesem simplen Schwierigkeitsgrad.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.