Drehzahlmesser, Problem mit einlesen

Hallo, ich habe mir mit einem Arduino Uno einen Drehzahlmesser für mein Motorrad gebaut. Dabei nehme ich die Drehzahl über die Zündimpulse am Zündkabel induktiv ab.
Das einlesen und auswerten der Drehzahl klappt sehr gut. Allerdings funktioniert das einlesen der Impulse in meinem Programm darüber, dass ein Zähler die Impulse pro Sekunde einließt. Die Drehzahl wird somit auch nur jede Sekunde an den Ausgängen ausgegeben.
Das ist nicht so optimal. Ich hätte gerne eine Möglichkeit die Drehzahl in Echtzeit auszugeben, habe aber keine Ahnung wie und ob das Möglich ist.

Anbei ist mein Programm wie es im Moment umgesetzt ist.

int pin = 7;
unsigned long N;          //Anzahl der Impulse
unsigned long T;          //Zeitintervall in us
unsigned long time;       //Startzeit
int Drehzahl = 0;         //Variable für Drehzahl
void setup() {
  Serial.begin(9600);
  pinMode(pin, INPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
  digitalWrite(13, LOW);
  T = 5e5;
}

void loop() {
  N = 0;
  time = micros();
  do {
    if (pulseIn(pin, HIGH) > 0) N++;
  }
  while ( micros() < (time + T) );
  Serial.println(N);
  Drehzahl = N * 240;
  Serial.println(Drehzahl);
  
  if (Drehzahl < 1000) {
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 1000 && Drehzahl < 2000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 2000 && Drehzahl < 3000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 3000 && Drehzahl < 4000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 4000 && Drehzahl < 5000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 5000 && Drehzahl < 6000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 6000 && Drehzahl < 7000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 7000 && Drehzahl < 8000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);
    digitalWrite(13, LOW);
  }
  if (Drehzahl > 8000 && Drehzahl < 9000) {
    digitalWrite(5, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);
    digitalWrite(13, HIGH);
  }

}

Drehzahl2.ino (2.98 KB)

Hi,

du kannst einen Interrupt nehmen, dann die zeit zwischen zwei impulsen messen und direkt ausgeben, damit bekommst du 16 aktualisierungen pro sekunde bei 1000upm hin (bei nem 2 Zylinder 4-Takt)

Habe sowas auch schon überlegt :slight_smile:

Die Drehzahl wird somit auch nur jede Sekunde an den Ausgängen ausgegeben.

Ich hätte gedacht, dass dein Sketch das inzwischen alle halbe Sekunde macht. (5e5 µs = 500 ms)
Das kannst du auch noch schneller machen.

Im Extremfall könntest du statt der Anzahl Pulse im Intervall die Dauer zwischen zwei Pulsen messen und aus dem Kehrwert deine Drehzahl bestimmen. Nur Serial.print solltest du dann reduzieren, damit das nicht deine loop-Zeiten bremst (1ms je Zeichen bei 9600, wenn der Ausgabepuffer erstmal voll ist)

Wenn du einfach T = 50ms setzt bekommst du etwa so viele Äktualisierungen pro Sekunde wie dein Auge erfassen kann. T = 100ms reicht vermutlich auch schon dicke.

Die Methode meiner Vorredner (Impulsdauermessung) sollte auch funktionieren, allerdings könnten Interrupts das ganze etwas verkomplizieren. Das Mitteln über einige Zeit gibt weiterhin vermutlich die schöneren Ergebnisse aus, da der Ausgang dadurch geglättet wird.

Wie sieht eigentlich genau die "Sensorik" aus? Einfach ein Draht ums Zündkabel und an den Pin?

Hi

Das Zählen per WHILE sehe ich etwas kritisch - wie lange kann der Impuls anliegen? Kann Dieser dadurch ggf. auch Mal doppelt gezählt werden?
Wobei Du ja schreibst, daß Das recht anständig läuft.

Mein Ansatz wären zwei PULSEIN, pro loop()-Durchlauf Einen, 1x den HIGH-Puls, 1x den LOW-Puls.
So hast Du nach spätestens 4 Zündungen eine HIGH und eine LOW-Zeit, beide addiert ergibt die Zeit einer Umdrehung (2-Takter) oder zwei Umdrehungen (4-Takter).
Das Umrechnen dieser Zündungs-Periode auf Deine Drehzahl überlasse ich wieder Dir :slight_smile:
So kannst Du auch in JEDEM loop()-Durchlauf Deine LEDs anpassen, da Du bei jedem Durchlauf eine neue (die aktuelle) Periodendauer hast.

MfG

wie lange kann der Impuls anliegen? Kann Dieser dadurch ggf. auch Mal doppelt gezählt werden?

Eher geht einer verloren, wenn anderes (zu lange ISR) dazwischenkommt.
pulseIn(pin, HIGH); wartet bei Bedarf bis LOW erkannt wird, wartet dann auf den Wechsel LOW->HIGH und danach wieder auf HIGH->LOW. In der while - Schleife hier sollte also LOW schon immer anliegen. Florian hat an den gemessenen Zeiten selbst gar kein Interesse, sondern nutzt nur die Tatsache, dass pulseIn bei ihm bei jedem Wechsel HIGH->LOW einmal fertig wird.

Problematischer ist eher

micros() < (time + T)

Formal richtiger wäre

micros() - time < T

um bei Überlauf von time+T Problemeeinen kleinen Schluckauf zu vermeiden, wenn time+T = 0 ergibt.
(Das kann alle 71 Minuten passieren)

Mich interessiert das Projekt. Funktioniert es nun wie gewünscht?

McKaiver:
Hi,

du kannst einen Interrupt nehmen, dann die zeit zwischen zwei impulsen messen und direkt ausgeben, damit bekommst du 16 aktualisierungen pro sekunde bei 1000upm hin (bei nem 2 Zylinder 4-Takt)

Habe sowas auch schon überlegt :slight_smile:

Das ist eine Gute Idee, ich werde sie zuhause mal austesten. Das einzige Problem, was ich dabei sehe ist, dass beim verfehlen von einem Impuls, die Drehzahl direkt um den Faktor 2 falsch ist.
Mit Interrupt habe ich noch nie Programmiert. Ein Tipp für mich wo das anschaulich erklärt wird?

z.B. hier.

Gruß Tommy

Mahimus:
Wenn du einfach T = 50ms setzt bekommst du etwa so viele Äktualisierungen pro Sekunde wie dein Auge erfassen kann. T = 100ms reicht vermutlich auch schon dicke.

Die Methode meiner Vorredner (Impulsdauermessung) sollte auch funktionieren, allerdings könnten Interrupts das ganze etwas verkomplizieren. Das Mitteln über einige Zeit gibt weiterhin vermutlich die schöneren Ergebnisse aus, da der Ausgang dadurch geglättet wird.

Wie sieht eigentlich genau die "Sensorik" aus? Einfach ein Draht ums Zündkabel und an den Pin?

Das habe ich bereits versucht, dann wird die Messung aber sehr ungenau.
Im Prinzip ist es Tatsächlich nur ein Kabel um das Zündkabel. Dieser Impuls wird dann über eine Verstärkerschaltung auf +5V - 0 V Impulse verstärkt.

Tommy56:
z.B. hier.

Gruß Tommy

Danke:)

FloriaN___K:
Das habe ich bereits versucht, dann wird die Messung aber sehr ungenau.

Vielleicht ne blöde Frage, aber hast du dann auch den Faktor (die 240) in dieser Formel angepasst?

Drehzahl = N * 240

Wenn du es lieber über Interrupts versuchen möchtest kannst du ja erstmal x Werte ermitteln und dann über diese x Werte mitteln. Oder besser noch: den Median errechnen! Hier und da mal eine Fehlmessung führt dann nicht dazu, dass die LEDs flackern. Du benötigst ja wie gesagt ohnehin nicht mehr als 20 Aktualisierungen pro Sekunde, eigentlich noch weniger.
Edit: Für 20 Werte/Sek wäre ein Mitteln evtl. je nach Zylinderanzahl doch ausgeschlossen. Probier einfach mal aus.

Wie viele Zylinder hast du denn überhaupt und zündet das Möp jede Umdrehung oder nur jede zweite? (Ich meine gehört zu haben, dass auch 4-Takter jede Umdrehung an jedem Zylinder zünden, jede zweite Zündung geht dann eben ins Leere.)

Mahimus:
Vielleicht ne blöde Frage, aber hast du dann auch den Faktor (die 240) in dieser Formel angepasst?

Drehzahl = N * 240

Wenn du es lieber über Interrupts versuchen möchtest kannst du ja erstmal x Werte ermitteln und dann über diese x Werte mitteln. Oder besser noch: den Median errechnen! Hier und da mal eine Fehlmessung führt dann nicht dazu, dass die LEDs flackern. Du benötigst ja wie gesagt ohnehin nicht mehr als 20 Aktualisierungen pro Sekunde, eigentlich noch weniger.
Edit: Für 20 Werte/Sek wäre ein Mitteln evtl. je nach Zylinderanzahl doch ausgeschlossen. Probier einfach mal aus.

Wie viele Zylinder hast du denn überhaupt und zündet das Möp jede Umdrehung oder nur jede zweite? (Ich meine gehört zu haben, dass auch 4-Takter jede Umdrehung an jedem Zylinder zünden, jede zweite Zündung geht dann eben ins Leere.)

Ja die Formel wurde natürlich angepasst.
Problem ist, dass ich im schlechtesten Fall (Standgas), nur 10 Impulse pro Sekunde erhalte. Es handelt sich um einen 4Takt- 1 Zylinder
Messe ich jetzt also nur 1/10 Sekunde kann es im Ungünstigsten fall sein, dass mal zwei, mal ein Impuls in dieser Zeit erfasst wird --> Drehzahl springt um Faktor 2.

Das Mitteln über Interrupt löst das Problem doch auch nicht oder? Da muss ich ja auch warten bis einige Werte eingelesen wurden.

Ich bin leider noch nicht dazu gekommen den Programmcode anzupassen. Werde mich aber dieses Wochenende hinsetzen und gucken ob mein Problem über das einlesen der Zeit zwischen zwei Impulsen gelöst ist.

Hi

Wenn Du viele Impulse bekommst, kannst Du eine Zeit lang Diese zählen und trotzdem ein schnelles aber trotzdem halbwegs genaues Ergebnis zu bekommen.
Wenn die Impulse rar werden ist's besser, wenn Du die Zeit misst, Die zwischen den Impulsen vergangen ist - der Kehrwert ergibt wieder die Frequenz.
(also jeweils die gleiche Flanke)
Alle Sekunde 1 Impuls -> 1n/sek
Alle halbe Sekunde 1 Impuls -> (1:0,5 Sek) 2n/sek

So bekommst Du trotz sehr weniger Messwerte recht genaue Drehzahlen.

MfG

FloriaN___K:
Problem ist, dass ich im schlechtesten Fall (Standgas), nur 10 Impulse pro Sekunde erhalte. Es handelt sich um einen 4Takt- 1 Zylinder

Echt? Dreht die gute dann ca. 600upm oder ca. 1200?

Jedenfalls hast du dann natürlich recht, das sind zu wenig Daten, hatte mit etwas anderen Werten gerechnet.

das sind zu wenig Daten

Das wären 100 ms zwischen 2 Impulsen, bzw. 10 bei zehnfach höherer Drehzahl. Das ist doch ein handhabbarer Wertebereich.

Das Mitteln über einige Zeit gibt weiterhin vermutlich die schöneren Ergebnisse aus, da der Ausgang dadurch geglättet wird.

Das wären auch meine Bedenken.
Ob du wirklich einzelne Pulse verlierst und dadurch halbe Drehzahl oder mit zusätzlichen Störungen doppelte, muss man sehen, bevor man dagegen Filter "erfindet".

1200 RPM.
Bei einem 4-Takter ist nur bei jeder 2. Umdrehung ein Zündimpuls.
Grüße Uwe

michael_x:
Das wären 100 ms zwischen 2 Impulsen, bzw. 10 bei zehnfach höherer Drehzahl. Das ist doch ein handhabbarer Wertebereich.

Klar, nur sind 10/s zu wenig um zehnmal pro Sekunde über N Werte zu mitteln, wenn N sinnvollerweise >> 1 sein soll. Das meinte ich.

uwefed:
Bei einem 4-Takter ist nur bei jeder 2. Umdrehung ein Zündimpuls.

Das muss offenbar nicht so sein. Erfahrungsberichte im Netz sagen mal so mal so. Ich weiß nur sicher, dass bei meinem Möp der Zündgeber an der KW sitzt. Es wäre in dem Fall nur praktikabel einmal pro Umdrehung zu zünden.

Hi

Hast Du denn schon probiert, die Zeit ZWISCHEN den Impulsen zu messen?
(Eigentlich die Zeit zwischen zwei gleichen Flanken)
Der Wert ist anti-proportional zur Drehzahl - und 1:x kann man den Arduino rechnen lassen ...

MfG

Mahimus:
Echt? Dreht die gute dann ca. 600upm oder ca. 1200?

Mit ~1200
Habe das Problem jetzt aber durch das Zeitmesser per Interrupt gelöst