Forum: Mikrocontroller und Digitale Elektronik Arduino Drehzahlmesser


von Nick S. (kolbi)


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)


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)


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)


Lesenswert?

Arduinoquäler schrieb:
> Bis über 200 KHz ...... sicher ?

4 kHz sollten reichen!

von MaWin (Gast)


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)


Lesenswert?

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

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

von Arduinoquäler (Gast)


Lesenswert?

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

Von Minuten war nicht die Rede.

Default-Zeiteinheit ist Sekunde.

von MaWin (Gast)


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)


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)


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:

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)


Lesenswert?

Arduinoquäler schrieb:
> Default-Zeiteinheit ist Sekunde.

Seit wann gibt es Default-Einheiten?

von Dieter F. (Gast)


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

...
1
  //Main Loop To Calculate RPM and Update LCD Display
2
  void loop()
3
  {
4
    int rpm = 0;
5
    int last_rpm = 1;
6
    char buffer[7];
7
  
8
    while(1)
9
    {    
10
      //Update The RPM
11
      if(time > 0)
12
      {
13
        //Alternativ 
14
        rpm = 5000000 / time;
15
        //Mitteln - akt. Wert Faktor 3 und letzter Wert Faktor 1  
16
        rpm = ((rpm + (rpm<<1) + last_rpm)>>2);
17
18
        //ODER - wie bisher
19
        //5 Sample Moving Average To Smooth Out The Data
20
        rpm_array[0] = rpm_array[1];
21
        rpm_array[1] = rpm_array[2];
22
        rpm_array[2] = rpm_array[3];
23
        rpm_array[3] = rpm_array[4];
24
        rpm_array[4] = 60*(1000000/(time*12));    
25
        //Last 5 Average RPM Counts Eqauls....
26
        rpm = (   rpm_array[0] + rpm_array[1] + rpm_array[2] 
27
                + rpm_array[3] + rpm_array[4]                ) / 5;
28
      }
29
30
      if(rpm != last_rpm)
31
      {
32
        //Update The Rpm Count
33
        lcd.setCursor(0, 1);
34
        sprintf(buffer,"%5i",rpm);
35
        lcd.print(buffer);   
36
      }
37
      last_rpm = rpm;
38
    }
39
  }
40
41
  //Capture The IR Break-Beam Interrupt
42
  void fan_interrupt()
43
  {
44
    float time_act;
45
    time_act = (micros);
46
    time = (time_act - time_last); 
47
    time_last = time_act;
48
  }

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)


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)


Lesenswert?

Thomas W. schrieb:
> Seit wann gibt es Default-Einheiten?

Seit Sternzeit 153498.45798,54 oder so ...

von Nick S. (kolbi)


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)


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)


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)


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)


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)


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)


Lesenswert?

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

1
  #include <LiquidCrystal.h>
2
  LiquidCrystal lcd(3, 5, 9, 10, 11, 12);
3
4
  volatile unsigned long time = 0;
5
  volatile unsigned long time_last = 0;
6
  volatile int rpm_array[5] = {0,0,0,0,0};
7
8
  void setup()
9
  {
10
    //Digital Pin 2 Set As An Interrupt
11
    attachInterrupt(0, fan_interrupt, FALLING);
12
13
    // set up the LCD's number of columns and rows: 
14
    lcd.begin(16, 2);
15
    // Print a message to the LCD.
16
    lcd.print("Drehzahl:");
17
  }
18
19
20
  //Main Loop To Calculate RPM and Update LCD Display
21
  void loop()
22
  {
23
    int rpm = 0;
24
    int last_rpm = 1;
25
    char buffer[7];
26
  
27
    while(1)
28
    {    
29
      //Update The RPM
30
      if(time > 0)
31
      {
32
        //Alternativ 
33
        rpm = 5000000 / time;
34
        //Mitteln - akt. Wert Faktor 3 und letzter Wert Faktor 1  
35
        rpm = ((rpm + (rpm<<1) + last_rpm)>>2);
36
37
        //ODER - wie bisher
38
        //5 Sample Moving Average To Smooth Out The Data
39
        rpm_array[0] = rpm_array[1];
40
        rpm_array[1] = rpm_array[2];
41
        rpm_array[2] = rpm_array[3];
42
        rpm_array[3] = rpm_array[4];
43
        rpm_array[4] = 60*(1000000/(time*12));    
44
        //Last 5 Average RPM Counts Eqauls....
45
        rpm = (   rpm_array[0] + rpm_array[1] + rpm_array[2] 
46
                + rpm_array[3] + rpm_array[4]                ) / 5;
47
48
49
        time = 0;
50
      }
51
52
      if(rpm != last_rpm)
53
      {
54
        //Update The Rpm Count
55
        lcd.setCursor(0, 1);
56
        sprintf(buffer,"%5i",rpm);
57
        lcd.print(buffer);   
58
      }
59
      last_rpm = rpm;
60
    }
61
  }
62
63
  //Capture The IR Break-Beam Interrupt
64
  void fan_interrupt()
65
  {
66
    unsigned long time_act;
67
    time_act = (micros);
68
    time = (time_act - time_last); 
69
    time_last = time_act;
70
  }

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)


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)


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:
1
#include <LiquidCrystal.h>
2
LiquidCrystal lcd(12, 11, 5, 4, 3, 13);
3
4
volatile float Zeit = 0;
5
volatile float Vorherige_Zeit = 0;
6
7
void setup()
8
{
9
  //Digital Pin 2 ist jetzt ein Interrupt und reagiert auf fallende Flanken
10
 attachInterrupt(0, Sensor_Interrupt, FALLING);
11
12
  // 2x16 LCD Display einrichten
13
  lcd.begin(16, 2);
14
  // Drehzahl auf dem LCD Ausgeben
15
  lcd.print("Umdrehungen/Min");
16
}
17
18
//Hauptschleife zum Berechnen der Drehzahl und LCD Displayupdate
19
void loop()
20
{
21
  int upm = 0;
22
  
23
  while(1){    
24
25
     //Displayupdates verzögern
26
    delay(200);
27
  
28
  //Letzte Reihe löschen
29
  lcd.setCursor(0, 1);
30
  lcd.print("                ");   
31
  
32
  //Drehzahl ausgeben
33
  lcd.setCursor(0, 1);
34
  lcd.print(upm);   
35
36
lcd.setCursor(4, 1);
37
lcd.print(time);   
38
39
  //Drehzahlberechnung, *12 für die Anzahl der Impulse (Lochscheibe, Lüfterflügel,...)
40
  if(Zeit > 0)
41
  {
42
        upm = 60*(1000000/(Zeit*12));
43
  }
44
 
45
 }
46
}
47
48
//Interrrupt Capture
49
void Sensor_Interrupt()
50
{
51
   Zeit = (micros() - Vorherige_Zeit); 
52
   Vorherige_Zeit = micros();
53
}


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)


Lesenswert?

Sorry, hab das alte Programm erwischt, so müssts gehn:



1
#include <LiquidCrystal.h>
2
LiquidCrystal lcd(12, 11, 5, 4, 3, 13);
3
4
volatile float Zeit = 0;
5
volatile float Vorherige_Zeit = 0;
6
7
void setup()
8
{
9
  //Digital Pin 2 ist jetzt ein Interrupt und reagiert auf fallende Flanken
10
 attachInterrupt(0, Sensor_Interrupt, FALLING);
11
12
  // 2x16 LCD Display einrichten
13
  lcd.begin(16, 2);
14
  // Drehzahl auf dem LCD Ausgeben
15
  lcd.print("Umdrehungen/Min");
16
}
17
18
//Hauptschleife zum Berechnen der Drehzahl und LCD Displayupdate
19
void loop()
20
{
21
  int upm = 0;
22
  
23
  while(1){    
24
25
     //Displayupdates verzögern
26
    delay(200);
27
  
28
  //Letzte Reihe löschen
29
  lcd.setCursor(0, 1);
30
  lcd.print("                ");   
31
  
32
  //Drehzahl ausgeben
33
  lcd.setCursor(0, 1);
34
  lcd.print(upm);   
35
36
37
  //Drehzahlberechnung, *12 für die Anzahl der Impulse (Lochscheibe, Lüfterflügel,...)
38
  if(Zeit > 0)
39
  {
40
        upm = 60*(1000000/(Zeit*12));
41
  }
42
 
43
 }
44
}
45
46
//Interrrupt Capture
47
void Sensor_Interrupt()
48
{
49
   Zeit = (micros() - Vorherige_Zeit); 
50
   Vorherige_Zeit = micros();
51
}

von Karl H. (kbuchegg)


Lesenswert?

2 Dinge

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


Das Arduino Framework ist so aufgebaut, dass es dir ein main() vorgibt, 
welches vom Prinzip her so aussieht
1
int main()
2
{
3
  Arduino Initialisierungen
4
5
  setup();
6
7
  sei();
8
9
  while( 1 ) {
10
11
    loop();
12
13
    Ardiuno Framework interne Buchhaltung
14
  }
15
}

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
1
void loop()
2
{
3
  ...
4
  while(1) {    
5
    ...
6
  }
7
}

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
1
unsigned long lastDone;
2
3
void setup()
4
{
5
  lastDone = millis();
6
}
7
8
void loop()
9
{
10
  unsigned long now = millis();
11
12
  if( now - lastDone > duration ) {
13
    lastDone = now;
14
15
    ... mache, was auch immer du im Abstand 'duration' gemacht haben willst
16
  }
17
}

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
1
void Sensor_Interrupt()
2
{
3
   Zeit = (micros() - Vorherige_Zeit); 
4
   Vorherige_Zeit = micros();
5
}
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 User
von Nick S. (kolbi)


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)


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.

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
Noch kein Account? Hier anmelden.