/*
Forum: https://forum.arduino.cc/t/drehzahlmesser-am-auto/1396866
Wokwi: https://wokwi.com/projects/437633723585780737
2025/07/27
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 _lastInterruptMicros = 0;
unsigned long lastInterruptMicros = 0;
unsigned long _oneRotMicros = 0;
unsigned long oneRotMicros = 0;
unsigned long _pulsePerSecond = 0;
unsigned long pulsePerSecond = 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;
lastInterruptMicros = _lastInterruptMicros;
pulsePerSecond = _pulsePerSecond;
}
if (micros() - lastInterruptMicros > 1000000UL / PulseProRotation) {
Drehzahl = 60.0 / ( 1.0 * PulseProRotation / pulsePerSecond);
} else {
if (oneRotMicros > 0) {
double oneRotMillis = oneRotMicros / 1000.0;
Drehzahl = 60000.0 / oneRotMillis;
} else {
Drehzahl = 0.0;
}
}
}
void ImpulsLesen() {
static unsigned long secondStartTime = micros();
static unsigned long startTime = micros();
static uint16_t pulseCount = 0;
static uint16_t pulseCounterSecond = 0;
if (micros() - _lastInterruptMicros >= 2) {
pulseCount++;
pulseCounterSecond++;
if (pulseCount >= PulseProRotation) {
_oneRotMicros = micros() - startTime;
startTime = micros();
pulseCount = 0;
}
_lastInterruptMicros = micros();
if (_lastInterruptMicros - secondStartTime >= 1000000UL) {
_pulsePerSecond = pulseCounterSecond;
pulseCounterSecond = 0;
secondStartTime = _lastInterruptMicros;
}
}
}
/*************************************************************************************/
/* 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;
}
/*************************************************************************************/