Oha, das ist insofern schon mal interessant, weil die Anzeigeroutine
if (millis() - myTimeDZM > timerDZM) {
unsigned long start = millis();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_fub30_tr);
u8g2.setFontRefHeightExtendedText();
u8g2.setDrawColor(1);
u8g2.setFontPosTop();
u8g2.setFontDirection(0);
u8g2.setCursor(20, 1);
u8g2.print(Drehzahl, 0);
u8g2.sendBuffer();
myTimeDZM = millis();
Serial.println(myTimeDZM - start);
}
den Controller schon ca. eine Drittelsekunde in Beschlag nimmt.
In dieser Zeit einlaufende Pulse, die dazu führen, dass impulszz deutlich größer wird als 1610, werden bei der Abfrage "if (impulszz > 1610)" und der folgenden Umrechnung ignoriert. Es wird so gearbeitet, als wenn jeder Wert über 1610 genau 10 Umdrehungen entspricht.
Das kann man hier bei Wokwi sehr gut sehen:
https://wokwi.com/projects/437119968369247233
Ausgabe bei simulierten 850 U/min
Start
U8G2 [ms] 325
Impulse 1611
U8G2 [ms] 331
Impulse 1611
U8G2 [ms] 331
Impulse 1611
U8G2 [ms] 331
Impulse 1611
U8G2 [ms] 331
Impulse 1898
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 329
Impulse 1896
U8G2 [ms] 328
Impulse 1894
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 329
Impulse 1896
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 329
Impulse 1895
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 329
Impulse 1895
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1896
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 329
Impulse 1896
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 329
Impulse 1895
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1894
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 329
Impulse 1896
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 329
Impulse 1895
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 329
Impulse 1896
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 329
Impulse 1895
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1893
U8G2 [ms] 328
Impulse 1893
U8G2 [ms] 329
Impulse 1894
U8G2 [ms] 329
Impulse 1896
U8G2 [ms] 329
wobei sich hier noch zugunsten der Daten auswirkt, dass die Zeit myTimeDZM erst nach dem Abarbeiten der Anzeige gesetzt wird. Das führt dazu, dass bei höheren Drehzahlen zwischen den Anzeigen der Schwellwert zweimal überschritten wird. Hier für simulierte 1250 U/min, man beachte die letzte Impulsanzahl vor der Anzeige U8G2:
Impulse 2419
Impulse 1611
U8G2 [ms] 340
Impulse 1611
U8G2 [ms] 340
Impulse 2421
Impulse 1611
U8G2 [ms] 340
Impulse 1536
U8G2 [ms] 339
Impulse 2490
Impulse 1611
U8G2 [ms] 340
Impulse 1611
Ich habe Deinen Sketch jetzt im Wesentlichen wie folgt angepasst:
- Verwendung des ATOMIC_BLOCK-Makros
- Berechnung der Drehzahl und Anzeige in der selben Funktion
- Ermittlung der tatsächlich vergangenen Zeit nach dem letztem Rücksetzens des Zählers.
- Berechnung der Drehzahl aus der Anzahl der Pulse, die in diesem so ermittelten Zeitraum eingegangen sind
- Berechnung der Drehzahl weitgehend mit float-Werten, um Rundungsfehler beim Dividieren zu minimieren
- Ein delay() in der loop(), um die zeitliche Auswirkung weiterer Funktionen zu simulieren.
Sketch
/*
Forum: https://forum.arduino.cc/t/drehzahlmesser-am-auto/1396866
Wokwi: https://wokwi.com/projects/437123436443317249
2025/07/22
ec2021
*/
//#include "MFRC522.h"
#include <Arduino.h>
#include <U8g2lib.h>
#include <util/atomic.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
unsigned long myTimeDZM = 0; //Zeit Drehzahlmesser
int timerDZM = 500; //Zeit für Drehzahlmesser
unsigned long myTimeDZMImpuls = 0; //Zeit Drehzahlmesser
unsigned long myTimeZeitIm = 0; //Zeit für Impuls DZM
//Pins
#define pinImpuls 3 // Pin für Drehzahlimpuls
//OLED Display
#define pinOSDA A4
#define pinOSLK A5
U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ pinOSLK, /* data=*/ pinOSDA, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather M0 Basic Proto + FeatherWing OLED
// Drehzahlmesser
double Drehzahl = 0;
uint16_t impulszz = 0;
uint16_t impulszz_copy = 0;
int zeitimpuls = 0;
constexpr uint16_t PulseProRotation {161};
void setup()
{
//Pin In Output
pinMode(pinImpuls, INPUT); //Pin Impuls
attachInterrupt(digitalPinToInterrupt(pinImpuls), ImpulsLesen, FALLING);
SPI.begin();
u8g2.begin(); //OLED Display
starteSimulation(1200);
}
void loop()
{
if (millis() - myTimeDZM >= timerDZM) {
ATOMIC_BLOCK(ATOMIC_FORCEON)
{
impulszz_copy = impulszz;
impulszz = 0;
}
uint16_t messIntervall = millis() - myTimeDZM;
myTimeDZM = millis();
Drehzahl = (1.0 * impulszz_copy / PulseProRotation) * (60000.0 / messIntervall) ;
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_fub30_tr);
u8g2.setFontRefHeightExtendedText();
u8g2.setDrawColor(1);
u8g2.setFontPosTop();
u8g2.setFontDirection(0);
u8g2.setCursor(20, 1);
u8g2.print(Drehzahl, 0);
u8g2.sendBuffer();
}
delay(300);
}
void ImpulsLesen() {
if (micros() - myTimeDZMImpuls > 2) {
impulszz = impulszz + 1;
myTimeDZMImpuls = micros();
}
}
/*************************************************************************************/
/* Dieser Teil ist für das Simulieren der Pulse für die Drehzahlmessung erforderlich */
#include <TimerOne.h>
constexpr byte outPin {4};
constexpr unsigned long pulseProRotation {161};
unsigned long interval;
float zielDrehzahl = 1200;
byte togglePin = 0;
void starteSimulation(float ziel) {
pinMode(outPin, OUTPUT);
togglePin = 1 << outPin;
zielDrehzahl = ziel;
interval = round(1000000.0 / ((zielDrehzahl / 60.0) * pulseProRotation));
Timer1.initialize(interval);
Timer1.attachInterrupt(timer_isr);
}
void timer_isr() {
PIND = togglePin;
delayMicroseconds(3);
PIND = togglePin;
}
/*************************************************************************************/
Auf Wokwi zum Testen: https://wokwi.com/projects/437123436443317249
Ich habe dabei so wenig wie möglich an Deinem Sketch geändert, da ist sicher noch Luft nach oben ...
Gerne mal in der originalen Anwendung ausprobieren!
Viel Erfolg!
ec2021