Drehzahlmesser am Auto

Weil ich da die Pinbelegung nicht ändern kann. Und an den vorgebenen Pins hängt schon ein RFID Reader dran.

Mit SPI oder I2C?

oder will?

So kurze Rückmeldung: Es funktioniert tatsächlich astrein mit dem Sketch. Es wird allerdings immer die doppelte Drehzahl angezeigt, also im leerlauf nicht 850 sondern 1700. Aber das läßt sich ja über die Variable korrigieren.

Sehr schön, dass es prinzipiell bei Dir funktioniert!

Ich habe die Routinen nochmals angepasst (jedoch ohne Berücksichtigung Deiner Erkenntnis zur Drehzahlangabe, das kannst Du sicher in Deiner Anwendung anpassen ...).

Hintergrund: Die Drehzahlberechnung hängt bisher noch stark von den weiteren Randbedingungen in Deinem Gesamtsketch ab. Der folgende Sketch führt die relevanten Messungen in der ISR aus, indem die Zeit für eine Rotation in Mikrosekunden ermittelt und bereitgestellt wird.

In der loop() läuft dann nur noch die Umrechnung von Mikrosekunden/Rotation auf Umdrehung/Minute und die Anzeige.

Siehe Wokwi: https://wokwi.com/projects/437369416786846721

Sketch:

/*
   Forum: https://forum.arduino.cc/t/drehzahlmesser-am-auto/1396866
   Wokwi: https://wokwi.com/projects/437369416786846721

  2025/07/25
  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



//Pins
constexpr byte pinImpuls {3}; // Pin für Drehzahlimpuls


//OLED Display
constexpr byte 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
constexpr uint16_t PulseProRotation {161};
constexpr unsigned long rotationDisplayInterval {500}; //Zeitintervall der Drehzahlanzeige
unsigned long lastRotationDisplayTime = 0;             //Zeit der letzten Drehzahlanzeige
unsigned long _oneRotMicros  = 0;
unsigned long oneRotMicros  = 0;
double Drehzahl = 0;



void setup()
{
  //Pin In Output
  pinMode(pinImpuls, INPUT); //Pin Impuls
  attachInterrupt(digitalPinToInterrupt(pinImpuls), ImpulsLesen, FALLING);
  SPI.begin();
  u8g2.begin(); //OLED Display
  starteSimulation();
}


void loop()
{
  drehzahlAnzeige();
  checkSerial();
  //  delay(300);
}

void drehzahlAnzeige() {
  if (millis() - lastRotationDisplayTime >= rotationDisplayInterval) {
    lastRotationDisplayTime = millis();
    drehzahlBerechnen();
    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();
  }
}

void drehzahlBerechnen() {
  ATOMIC_BLOCK(ATOMIC_FORCEON)
  {
    oneRotMicros = _oneRotMicros;
  }
  if (oneRotMicros == 0) {
    Drehzahl = 0.0;
    return;
  }
  double oneRotMillis = oneRotMicros / 1000.0;
  Drehzahl = 60000.0 / oneRotMillis;
}

void ImpulsLesen() {
  static unsigned long lastInterrupt = 0;
  static unsigned long startRotTime = micros();
  static uint16_t pulseCount = 0;
  if (micros() - lastInterrupt > 2) {
    pulseCount++;
    if (pulseCount >=  PulseProRotation) {
      _oneRotMicros = micros() - startRotTime;
      startRotTime = micros();
      pulseCount = 0;
    }
    lastInterrupt = micros();
  }
}

/*************************************************************************************/
/* Dieser Teil ist für das Simulieren der Pulse für die Drehzahlmessung erforderlich */
#include <TimerOne.h>
constexpr byte outPin {4};
unsigned long interval;
float zielDrehzahl = 1200;
byte togglePin = 0;

void starteSimulation() {
  pinMode(outPin, OUTPUT);
  togglePin = 1 << outPin;
  setDrehzahl(1200);
  Serial.begin(115200);
  delay(500);
  Serial.println("Drehzahl eingeben: ");
}

void setDrehzahl(float ziel) {
  Serial.print("Neue Drehzahl ");
  Serial.println(ziel);
  if (ziel > 0) {
    zielDrehzahl = ziel;
    interval = round(1000000.0 / ((zielDrehzahl / 60.0) * PulseProRotation));
    Timer1.initialize(interval);
    Timer1.attachInterrupt(timer_isr);

  }
}

void checkSerial() {
  constexpr int maxC {20};
  static char inp[maxC];
  static int index = 0;
  boolean changed = false;
  while (Serial.available()) {
    char c = Serial.read();
    switch (c) {
      case '0' ... '9':
        if (index < maxC) {
          inp[index++] = c;
          inp[index] = '\0';
        }
        break;
      case '\n':
        int zahl = atoi(inp);
        index = 0;
        if (zahl >= 0)
          zielDrehzahl = zahl;
        changed = true;
        break;
    }
  }
  if (changed) {
    Timer1.detachInterrupt();
    setDrehzahl(zielDrehzahl);
  }
}

void timer_isr() {
  PIND = togglePin;
  delayMicroseconds(3);
  PIND = togglePin;
}

/*************************************************************************************/


Über die serielle Schnittstelle läßt sich bei dem Wokwi-Sketch die Zieldrehzahl eingeben; es erfolgt jedoch keine Abfrage auf plausible Werte, zum Testen sollte das aber genügen.

Gruß
ec2021