-Micky:
Habe folgenden Code:
int r = analogRead(reedPin);
Einen schnell vorbeihuschenden Reedkontakt mit analogRead auszuwerten finde ich ja etwas abenteuerlich.
Ich habe Dir mal einen neuen Sketch gemacht, der stattdessen die Impulse vom Reedkontakt digital auswertet, mit Zählung in einer Interruptroutine. Die Aktualisierung erfolgt exakt einmal pro Sekunde, unabhängig von der Fahrgeschwindigkeit. Und auf 0 runter geht mein Sketch auch.
Der Sketch ist für ein Keypad-Shield, wie Du es offenbar auch verwendest.
Reedkontakt einfach direkt zwischen GND und digital Pin-2 anschließen.
(Nur die digitalen Pins 2 und 3 sind am Uno Interruptfähig und können mit meinem Sketch verwendet werden)
Die messbare Maximalgeschwindigkeit entspricht 40 Radumdrehungen pro Sekunde.
Teste mal, ich habe hier zwar ein LCD-Keypad Shield, aber keinen Reedkontakt zum Testen verfügbar.
//Anzahl Spalten des Display (16)
#define LCD_WIDTH 16
//Anzahl Zeilen des Display (2)
#define LCD_HEIGHT 2
// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2
// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0
// Radumfang in mm
#define RADUMFANG 1540
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup(){
lcd.begin(LCD_WIDTH, LCD_HEIGHT);
pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen
attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}
volatile byte reedCountSum;
volatile long reedMillisSum;
unsigned long lastReedMillis;
void reedISR()
{
if (millis()-lastReedMillis>=25) // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
{
reedCountSum++; // eine Radumdrehung zählen
reedMillisSum+=millis()-lastReedMillis; // Zeit addieren
lastReedMillis=millis(); // Zeit merken
}
}
unsigned long gesamtUmdrehungen;
void tachoAnzeige()
{
byte umdrehungen;
unsigned long zeit;
float kph, kilometer;
char buffer[10];
noInterrupts(); // Interrupts sperren
umdrehungen=reedCountSum;// Zählvariable umkopieren
reedCountSum=0; // Zählvariable auf 0 zurücksetzen
zeit=reedMillisSum; // Zeitzähler umkopieren
reedMillisSum=0; // Zeitzähler auf 0 zurücksetzen
interrupts(); // Interrupts wieder zulassen
gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
if (umdrehungen>0)
kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
else
kph=0.0;
lcd.setCursor(0, 0);
dtostrf(kilometer,9,3,buffer);
lcd.print(buffer);
lcd.print(" km");
lcd.setCursor(0, 1);
lcd.print("KM/H ");
dtostrf(kph,5,1,buffer);
lcd.print(buffer);
}
unsigned long letzteSekunde=0;
void loop()
{
unsigned long dieseSekunde=millis()/1000;
// Tachoanzeige wird genau einmal pro Sekunde aktualisiert
if (letzteSekunde != dieseSekunde)
{
tachoAnzeige();
letzteSekunde=dieseSekunde;
}
}
Zur besseren Kontrolle, ob auch alles stimmt, habe ich auch eine metergenaue Fahrtstreckenzählung seit dem letzten Reset eingebaut. Falls die Geschwindigkeitsanzeige fehlerhaft arbeitet, z.B. mögliches Kontaktprellen nicht ausreichend unterdrückt, würde man es daran erkennen, dass die gemessene Fahrtstrecke fehlerhaft ist. Ob eine gemessene Fahrtstrecke fehlerhaft gemessen wird, kann man leicht feststellen, indem man eine Strecke bekannter Länge abfährt und vergleicht.
Wenn der Tacho dann soweit OK läuft, könnte man noch die Anzeige verbessern. Und zwar kann man bei der Ausgabe von "nur Ziffern" die einfachen 1602 LCDs auch programmieren, "large digits", also große Zahlen über zwei Zeilen auszugeben. So wie hier im Youtube-Video zu sehen:
Da könnte mann dann also eine Tachoanzeige machen, die nur die Geschwindigkeit in grossen Zahlen anzeigt und sonst nichts. Gross wegen der leichteren Ablesbarkeit bei möglicherweise vorhandenen Vibrationen.