Pulse zählen in einer definierten Zeit

Hallo,
ich bin neu hier im Forum.
Ich versuche innerhalb einer definierten Zeit (z.B. 5 Sekunden) die Pulse eines Windsensors zu zählen. Der Windsensor hat 4 Magnete, also 4 Pulse/Umdrehung.
Die Anzahl der Pulse (können auch 0 sein) soll aufaddiert und daraus dann die Windgeschwindigkeit berechnet werden. Zur Weiterverabeitung werden die Daten in ein File geschrieben.
Die Frage ist: Wie kann die Zahl der Pulse am besten erfasst werden? Mit Hilfe von Interrupts? Oder anders? Ich habe kein Beispiel gefunden, auf dem ich aufbauen könnte.
Vielen Dank schon mal
Jogo24

Willkommen im Forum,
lese das
https://forum.arduino.cc/t/wie-programmiert-man-einen-zahler/1412284/5?_gl=11n11apq_upMQ.._gaMjA0MDA4NTI1NC4xNzYyNjczNDg0_ga_NEXN8H46L5*czE3NjI2NzM0ODQkbzEkZzAkdDE3NjI2NzM0ODQkajYwJGwwJGgxMjUxMDQwMTg3
Und
https://forum.arduino.cc/t/drehzahlmesser-mit-arduino/1110796/6?_gl=11vacmum_upMQ.._gaODExNTU1MzkwLjE3NjI2NzM4OTc._ga_NEXN8H46L5*czE3NjI2NzM4OTYkbzEkZzAkdDE3NjI2NzM4OTYkajYwJGwwJGg4MjEyNjM4MzQ.

Bei einer schnellen Pulsfolge wäre das sinnvoll, bei einer langsamen eher nicht. Aber was ist "schnell"? Das ist relativ zur Geschwindigkeit des Prozessors zu betrachten. Mit einem Oszilloskop könntest Du die Pulsfolge bei maximaler Windgeschwindigkeit aufzeichnen.

Oder Du verwendest Interrupts, denn damit kannst Du das Maximum aus dem Prozessor rausholen :wink:

Arduino Drehzahlsensor Tutorial

und Dir bei unzureichenden Kenntnissen mehr Probleme, als Lösungen einhandeln.
Selbst bei Sturm sollten die Impulse langsam genug sein, um ohne Interrupt auszukommen.

Gruß Tommy

Ich empfehle eine kurze Einführung in die Komplexität eines solchen Unterfangens mitzunehmen.

Lies mal ab hier:

was da an Gedanken und Unwägbarkeiten vorhanden waren und wie die tatsächliche Lösung nachher aussah.

Ja.
Interrupte sind erstmal keine Vereinfachung sondern machen Probleme, die du ohne gar nicht hast. Wenn man es richtig macht, kann man allerdings schneller zählen. (Und hat dadurch mehr Freiheiten, wie man im übrigen Proogramm rumtrödeln kann)

Also musst du erstmal rauskriegen, wie schnell die Pulse kommen können (und wie kurz sie dann sind).

Auch ist vorab interessant, was die langsamste Windgeschwindigkeit ist, die das Rad überhaupt bewegt und/oder die dich interessiert.

Du könntest einen Timer als Controller laufen lassen. Der zählt dann direkt die Pulse auf einen Pin.

Prellt dein Signal eigentlich?

Vielen Dank für eure Tipps.
Ich werde mich auf deren Basis mal näher mit dem geplanten Thema beschäftigen und einlesen und zunächst versuchen, ohne Interrupts auszukommen.
Beim Suchen danach hat sich schon gezeigt, dass das Verwenden von Interrupts nicht ganz ohne ist und bei den zu erwartenden Geschwindigkeiten auch nicht nötig sein sollte.
Jogo24

Das Signal ist sehr sauber, hat kein Prellen.
Jogo24

Die minimale Windgeschwindigkeit, die nötig ist, um das Anemometer zu bewegen ist mir nicht bekannt. Der Hersteller gibt dazu nichts bekannt. Es wird aber in kommerziellen Anwendungen verwendet, kein billiges Teil.
Jogo24

Wen wirklich so ist dan gibtbes vernimftige Datenblätter, zeige ein link zu deinem Teil.

Kann schon sein, dass das nicht im Datenblatt steht.
Kannst aber bei Windstille messen, wie lang die Zeit zwischen den letzten zwei Pulsen ist, wenn du es anstupst.

Aber das ist auch nur interessant, wenn deine Anzeige-Aktualisierungszeit kürzer sein sollte.

Moin @jogo24 ,

in einem Thread vom Juli des Jahres ging es um einen Drehzahlmesser für einen Fiat Ducato , der allerdings 161 Impulse pro Umdrehung bei Drehzahlen ab 850 bis über 1200 U/min erzeugt. Dort wurde mit einem Interrupt gearbeitet:

https://forum.arduino.cc/t/drehzahlmesser-am-auto/1396866

Der Sketch am Ende von Post 18 zählt im Interrupt die Impulse und berechnet in der loop die Drehzahl pro Minute aus der Anzahl von Impulsen, die innerhalb eines gegebenen Zeitintervalls eingelaufen sind.

Der Sketch in Post 24 ermittelt in der Interruptroutine die Zeit einer einzelnen Rotation; die Umrechung auf U/min erfolgt dann in bestimmten Abständen in der loop.

Die Sketche können im Wokwi-Online-Simulator getestet werden; der dort verwendete Nano erzeugt sich die Interrupts mit der Library TimerOne selbst ... :wink:

Aber:
Bei 4 Impulsen pro Umdrehung sollte die Verwendung einer Interruptroutine m.E. bei sachgemäßer Programmierung allerdings nicht erforderlich sein.
[Edit:] Der Einsatz einer ISR ist aber auch nicht problematisch ...

Das Grundgerüst mit der TimerOne-Mimik aus den o.a. Wokwi-Projekten kann aber gerne zum Testen angepasst und genutzt werden...

Viel Erfolg!
ec2021

Sorry @fony , hatte den Beitrag falsch verlinkt ... :wink:

Ich habe hier mal auf Wokwi ein Beispiel für die Ermittlung der Umlaufgeschwindigkeit eines Schalen-Anemometers auf Basis

  • der Pulsanzahl pro Zeitintervall und alternativ
  • der Zeit zwischen zwei fallenden Flanken

hinterlegt. Beides wird in einer Interruptroutine ermittelt.

Aus der Umlaufgeschwindigkeit des Rotors und Schnelllaufzahl des Anemometers lässt sich die Windgeschwindigkeit errechnen; die Quellen dazu (Wikipedia) sind im Code angeführt.

Im Wokwi-Beispiel werden die Impulse per TimerOne erzeugt. Die Eingabe der Wunschdrehzahl per Serial erfolgt in U/min. Bei 4 Pulsen pro Rotation ergibt eine Drehzahl von z.B. 15 U/min = > 60 Impulse/min => 1 Impuls/s. Bei 60 U/min ergeben sich damit 1 U/s und damit 4 Impulse/s usw.

Die benutzten Formeln sind im Header-Kommentar erläutert.

https://wokwi.com/projects/447332250347170817

Sketch
/*
   Forum: https://forum.arduino.cc/t/pulse-zahlen-in-einer-definierten-zeit/1413218
   Wokwi: https://wokwi.com/projects/447332250347170817

  2025/11/11
  ec2021

  In der Annahme, dass ein Schalen-Anemometer verwendet wird ergibt sich gemäß
  https://de.wikipedia.org/wiki/Anemometer die Berechnung der Windgeschwindigkeit
  aus der "Schnelllaufzahl" des Anemometers, die nach Wikipedia zwischen
  0,3 und 0,4 liegen soll.

  Die Schnelllaufzahl (https://de.wikipedia.org/wiki/Schnelllaufzahl) ist als das
  Verhältnis von Umfangsgeschwindigkeit des Rotors zur Windgeschwindigkeit definiert:

  Schnelllaufzahl:     Lambda
  Rotorradius:         Radius      [m]
  Rotordrehzahl:       Drehzahl    [U/s]
  Windgeschwindigkeit: WindGeschw  [m/s]

  Lambda = (2*Pi*Radius*Drehzahl)/WindGeschw

  daraus abgeleitet:

  Windgeschw = (2*Pi*Radius*Drehzahl)/Lambda

  Mit

  Faktor = (2*Pi*Radius)/Lambda  [m]

  ergibt sich

  Windgeschw = Faktor*Drehzahl  [m/s]

  Die Drehzahlerfassung wird mittels an der Rotorachse angebrachten Magneten umgesetzt.
  Pro Magnet wird ein Impuls (fallende Flanke) ermittelt. Bei M an der Achse montierten
  Magneten ergeben sich damit ebenfalls M fallende Impulsflanken für eine Umdrehung:

  Umdrehungen = (Anzahl fallender Flanken)/M
  Drehzahl    = Umdrehungen/(Beobachtungszeitraum)  [U/s]

  Alternativ lässt sich die Drehzahl auch aus der Zeit zwischen zwei fallenden Flanken
  ermitteln:

  Delta       = Zeit zwischen zwei fallenden Flanken [s]
  M            = Anzahl der Magnete
  Drehzahl    = 1/(M*Delta)

  Beispiele:  M = 4, Delta = 1,00  s ---> Drehzahl = 1/(4*1,00 s) =  0,25 U/s
              M = 4, Delta = 0,25  s ---> Drehzahl = 1/(4*0,25 s) =  1,00 U/s

*/

#include <Arduino.h>
#include <util/atomic.h>

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



// Drehzahlmessung
constexpr uint16_t  PulseProRotation {4};        // Impulse pro Umdrehung
constexpr float     Rotorradius {0.04};          // 4 cm Radius in [m]
constexpr float     Lambda  {0.4};                // Schnelllaufzahl siehe Datenblatt
constexpr float     Faktor {2 * 3.14159 * Rotorradius / Lambda}; //
constexpr unsigned  long displayInterval {2000}; // Zeitintervall für Anzeige
unsigned long       lastDisplayTime = 0;         // Zeit der letzten Anzeige
uint16_t            _impulseCount = 0;           // Impulszähler
unsigned long       _timeBetweenInterrupts = 0;  // Zeit zwischen zwei Interrupts in [µS]


void setup()
{
  //Pin In Output
  pinMode(pinImpuls, INPUT); //Pin Impuls
  attachInterrupt(digitalPinToInterrupt(pinImpuls), ImpulsZaehlen, FALLING);
  Serial.begin(115200);
  starteSimulation();
}


void loop()
{
  anzeige();
  checkSerial();
}

void anzeige() {
  if (millis() - lastDisplayTime >= displayInterval) {
    float windGeschwindigkeit = berechneWindGeschwindigkeit();
    lastDisplayTime = millis();
    Serial.print("\tWindgeschwindigkeit: ");
    Serial.println(windGeschwindigkeit);
  }
}

float getWindGeschwindigkeitAusPulsAnzahl(uint16_t impulse, unsigned long interval) {
  float Umdrehungen = float(impulse) / PulseProRotation;
  float Drehzahl    = Umdrehungen * 1000.0 / interval;
  return Faktor * Drehzahl;
}

float getWindGeschwindigkeitAusPulsAbstand(unsigned long timeBetweenInterrupts) {
  if (timeBetweenInterrupts > 0) {
    float Drehzahl = 1 / (PulseProRotation * timeBetweenInterrupts / 1000000.0);
    return Faktor * Drehzahl;
  } else {
    return 0.0;
  }
}


float berechneWindGeschwindigkeit() {
  uint16_t impulseCount;
  unsigned long timeBetweenInterrupts;
  ATOMIC_BLOCK(ATOMIC_FORCEON)
  {
    impulseCount = _impulseCount;
    _impulseCount = 0;
    timeBetweenInterrupts = _timeBetweenInterrupts;
  }
  float pulseProSek = impulseCount * 1000.0 / displayInterval;
  Serial.print("Impulse pro Sekunde: ");
  Serial.print(pulseProSek);
  // Falls im Display-Intervall kein Impuls verzeichnet wurde, haben wir vermutlich
  // Windstille ...
  if (impulseCount == 0) {
    timeBetweenInterrupts = 0;
  }
  // Geschwindigkeit aus Puls Anzahl im Display-Intervall
  //return getWindGeschwindigkeitAusPulsAnzahl(impulseCount, displayInterval);
  //
  // Oder alternativ aus dem Abstand der Pulse (über die fallende Flanke ermittelt)
  return getWindGeschwindigkeitAusPulsAbstand(timeBetweenInterrupts);
}

void ImpulsZaehlen() {
  static unsigned long _lastInterrupt = 0;
  _impulseCount++;
  if (_lastInterrupt > 0) {
    _timeBetweenInterrupts = micros() - _lastInterrupt;
  }
  _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 = 200;
byte togglePin = 0;

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

void setDrehzahl(float ziel) {
  Serial.print("Neue Drehzahl ");
  Serial.print(ziel);

  if (ziel > 0) {
    zielDrehzahl = ziel;
    float pulseProSekunde = (zielDrehzahl / 60.0) * PulseProRotation;
    interval = round(1000000.0 / pulseProSekunde);
    Serial.print("\tPulse pro Sekunde: ");
    Serial.print(pulseProSekunde);
    Serial.print("\tWindgeschwindigkeit: ");
    Serial.print(getWindGeschwindigkeitAusPulsAnzahl(pulseProSekunde * 10, 10000));
    Timer1.initialize(interval);
    Timer1.attachInterrupt(timer_isr);
  }
  Serial.println();
}

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;
}

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

Die Verwendung der "Zeit zwischen zwei Impulsen" sollte aufgrund der Masseträgheit des Rotors eher unkritisch sein.

Viel Erfolg!
ec2021

Vielen Dank euch allen für die prompte Hilfe.
Besonders interessant ist der Beitrag mit den Berechnungen von ec2021. Darauf kann man sehr gut aufbauen.
Da das Ganze inklusive 1"-OLED-Display in ein kleines Modulgehäuse eingebaut werden soll, will ich versuchen, den Sketch auf einem Nano unterzubringen.
Mal sehen, ob die Resourcen dafür ausreichen.
Danke

Das Beispiel läuft ja bereits in der Simulation auf einem Nano. Der Anteil der Puls-Simulation entfällt, dafür die Ansteuerung eines OLEDs hinzu. Das sollte funktionieren.

Wäre schön, zu hören, ob die Theorie (Code und Berechnungen) zur Praxis passt :wink:

Gruß
ec2021

P.S.: Hier noch eine Ergänzung mit I2C Oled Display ...

Zum Testen: https://wokwi.com/projects/447595962731835393

Sketch
/*
   Forum: https://forum.arduino.cc/t/pulse-zahlen-in-einer-definierten-zeit/1413218
   Wokwi: https://wokwi.com/projects/447595962731835393
   Vorläufer vom 2025/11/11
          Wokwi: https://wokwi.com/projects/447332250347170817

  OLED-Display ergänzt

  2025/11/14
  ec2021

  In der Annahme, dass ein Schalen-Anemometer verwendet wird ergibt sich gemäß
  https://de.wikipedia.org/wiki/Anemometer die Berechnung der Windgeschwindigkeit
  aus der "Schnelllaufzahl" des Anemometers, die nach Wikipedia zwischen
  0,3 und 0,4 liegen soll.

  Die Schnelllaufzahl (https://de.wikipedia.org/wiki/Schnelllaufzahl) ist als das
  Verhältnis von Umfangsgeschwindigkeit des Rotors zur Windgeschwindigkeit definiert:

  Schnelllaufzahl:     Lambda
  Rotorradius:         Radius      [m]
  Rotordrehzahl:       Drehzahl    [U/s]
  Windgeschwindigkeit: WindGeschw  [m/s]

  Lambda = (2*Pi*Radius*Drehzahl)/WindGeschw

  daraus abgeleitet:

  Windgeschw = (2*Pi*Radius*Drehzahl)/Lambda

  Mit

  Faktor = (2*Pi*Radius)/Lambda  [m]

  ergibt sich

  Windgeschw = Faktor*Drehzahl  [m/s]

  Die Drehzahlerfassung wird mittels an der Rotorachse angebrachten Magneten umgesetzt.
  Pro Magnet wird ein Impuls (fallende Flanke) ermittelt. Bei M an der Achse montierten
  Magneten ergeben sich damit ebenfalls M fallende Impulsflanken für eine Umdrehung:

  Umdrehungen = (Anzahl fallender Flanken)/M
  Drehzahl    = Umdrehungen/(Beobachtungszeitraum)  [U/s]

  Alternativ lässt sich die Drehzahl auch aus der Zeit zwischen zwei fallenden Flanken
  ermitteln:

  Delta       = Zeit zwischen zwei fallenden Flanken [s]
  M            = Anzahl der Magnete
  Drehzahl    = 1/(M*Delta)

  Beispiele:  M = 4, Delta = 1,00  s ---> Drehzahl = 1/(4*1,00 s) =  0,25 U/s
              M = 4, Delta = 0,25  s ---> Drehzahl = 1/(4*0,25 s) =  1,00 U/s

*/

#include <Arduino.h>
#include <util/atomic.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

constexpr int SCREEN_WIDTH {128}; // OLED display width, in pixels
constexpr int SCREEN_HEIGHT {64}; // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
constexpr byte OLED_RESET    { 4}; // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


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



// Drehzahlmessung
constexpr uint16_t  PulseProRotation {4};        // Impulse pro Umdrehung
constexpr float     Rotorradius {0.04};          // 4 cm Radius in [m]
constexpr float     Lambda  {0.4};                // Schnelllaufzahl siehe Datenblatt
constexpr float     Faktor {2 * 3.14159 * Rotorradius / Lambda}; //
constexpr unsigned  long displayInterval {2000}; // Zeitintervall für Anzeige
unsigned long       lastDisplayTime = 0;         // Zeit der letzten Anzeige
uint16_t            _impulseCount = 0;           // Impulszähler
unsigned long       _timeBetweenInterrupts = 0;  // Zeit zwischen zwei Interrupts in [µS]


void setup()
{
  //Pin In Output
  pinMode(pinImpuls, INPUT); //Pin Impuls
  attachInterrupt(digitalPinToInterrupt(pinImpuls), ImpulsZaehlen, FALLING);
  Serial.begin(115200);
  OledSetup();
  starteSimulation();
}


void loop()
{
  anzeige();
  checkSerial();
}

void OledSetup() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Falls nicht gefunden, stoppen
  }
  display.cp437(true);         // Benutze 'Code Page 437'
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE); // Textfarbe
  printToOled("--.-- m/s");
}

void printToOled(char * txt) {
  display.clearDisplay();
  display.setCursor(5, 0);
  display.write("Anemometer");
  display.setCursor(10, 40);
  display.write(txt);
  display.display();

}

void anzeige() {
  if (millis() - lastDisplayTime >= displayInterval) {
    float windGeschwindigkeit = berechneWindGeschwindigkeit();
    lastDisplayTime = millis();
    Serial.print("\tWindgeschwindigkeit: ");
    Serial.println(windGeschwindigkeit);
    char metersec[16];
    char txt[16];
    dtostrf(windGeschwindigkeit, 5, 2, metersec);
    snprintf(txt, sizeof(txt), "%s m/s", metersec);
    printToOled(txt);
  }
}

float getWindGeschwindigkeitAusPulsAnzahl(uint16_t impulse, unsigned long interval) {
  float Umdrehungen = float(impulse) / PulseProRotation;
  float Drehzahl    = Umdrehungen * 1000.0 / interval;
  return Faktor * Drehzahl;
}

float getWindGeschwindigkeitAusPulsAbstand(unsigned long timeBetweenInterrupts) {
  if (timeBetweenInterrupts > 0) {
    float Drehzahl = 1 / (PulseProRotation * timeBetweenInterrupts / 1000000.0);
    return Faktor * Drehzahl;
  } else {
    return 0.0;
  }
}


float berechneWindGeschwindigkeit() {
  uint16_t impulseCount;
  unsigned long timeBetweenInterrupts;
  ATOMIC_BLOCK(ATOMIC_FORCEON)
  {
    impulseCount = _impulseCount;
    _impulseCount = 0;
    timeBetweenInterrupts = _timeBetweenInterrupts;
  }
  float pulseProSek = impulseCount * 1000.0 / displayInterval;
  Serial.print("Impulse pro Sekunde: ");
  Serial.print(pulseProSek);
  // Falls im Display-Intervall kein Impuls verzeichnet wurde, haben wir vermutlich
  // Windstille ...
  if (impulseCount == 0) {
    timeBetweenInterrupts = 0;
  }
  // Geschwindigkeit aus Puls Anzahl im Display-Intervall
  //return getWindGeschwindigkeitAusPulsAnzahl(impulseCount, displayInterval);
  //
  // Oder alternativ aus dem Abstand der Pulse (über die fallende Flanke ermittelt)
  return getWindGeschwindigkeitAusPulsAbstand(timeBetweenInterrupts);
}

void ImpulsZaehlen() {
  static unsigned long _lastInterrupt = 0;
  _impulseCount++;
  if (_lastInterrupt > 0) {
    _timeBetweenInterrupts = micros() - _lastInterrupt;
  }
  _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 = 200;
byte togglePin = 0;

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

void setDrehzahl(float ziel) {
  Serial.print("Neue Drehzahl ");
  Serial.print(ziel);

  if (ziel > 0) {
    zielDrehzahl = ziel;
    float pulseProSekunde = (zielDrehzahl / 60.0) * PulseProRotation;
    interval = round(1000000.0 / pulseProSekunde);
    Serial.print("\tPulse pro Sekunde: ");
    Serial.print(pulseProSekunde);
    Serial.print("\tWindgeschwindigkeit: ");
    Serial.print(getWindGeschwindigkeitAusPulsAnzahl(pulseProSekunde * 10, 10000));
    Timer1.initialize(interval);
    Timer1.attachInterrupt(timer_isr);
  }
  Serial.println();
}

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;
}

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

Beim Hinzufügen des Displays reicht der Speicher des Nano oder anderen Modulen mit der gleichen Speicherkonfiguration nicht aus. Wenn man die abgespeckte Library SSD1306Ascii verwendet funktioniert es. Irgendwelche Grafikfunktionen brauche in dem Fall nicht.
Die Tests und Vergleiche bezüglich der Berechnungen laufen noch.