In diesem Beitrag zeige ich dir, wie du deinen eigenen digitalen Tachometer für dein Fahrzeug bauen kannst.
Ein solches Projekt erfordert nicht nur technisches Geschick und Kreativität, sondern bietet auch die Möglichkeit, etwas Einzigartiges zu schaffen, das perfekt auf deine Bedürfnisse abgestimmt ist. Egal, ob du ein Technik-Enthusiast bist oder einfach nur Spaß am Basteln hast dieser DIY-Tacho ist eine großartige Möglichkeit, deine Fähigkeiten auszubauen und dein Fahrzeug mit einem personalisierten Touch zu versehen.
Lass uns loslegen und Schritt für Schritt durch den Bauprozess gehen!
Um die aktuelle Geschwindigkeit zu messen, wird einer oder mehrere kleine Magnete an einer Speiche des Vorderrads befestigt (bei mehreren ist auf eine symmetrische Anordnung zu achten, siehe Abbildung), während ein Hall-Sensor an der Gabel montiert wird. Jedes Mal, wenn der Magnet am Sensor vorbeikommt, registriert dieser eine Umdrehung des Rades.
Die Geschwindigkeit wird aus der Anzahl der Radumdrehungen pro Zeitspanne und dem Umfang des Rades berechnet, den der Benutzer zuvor in der Software eintragen muss. Der Radumfang dient als Basis, um die Geschwindigkeit mit der Formel zu ermitteln:
$$ geschwindigkeit = (radumfang (m) ⋅ deltaTime (s))⋅3.6 $$
Die Schaltung umfasst vier Hauptkomponenten: einen Adafruit Trinket M0 Mikrocontroller, ein Display, einen Hallsensor sowie eine speziell entwickelte Leiterplatte, die für die Gleichrichtung und Transformation der Spannung auf 5V zuständig ist.
Das Display wird von der Leiterplatte mit Spannung versorgt. Die I2C-Datenleitungen des Displays sind direkt mit dem Mikrocontroller verbunden.
Der Hallsensor wird ebenfalls an die Leiterplatte angeschlossen. Sein Ausgangssignal wird über die Leiterplatte zum GPIO-Pin 1 des Mikrocontrollers weitergeleitet.
Der Mikrocontroller bezieht die 5V-Betriebsspannung sowie GND von der Leiterplatte. Zusätzlich liefert er eine 3,3V-Leitung zurück an die Leiterplatte. Diese 3,3V-Spannung wird zur Versorgung des Displays, des Pull-up-Widerstands und des Hallsensors genutzt.
Die Leiterplatte umfasst einen Gleichrichter aus vier Dioden, einen Pull-up-Widerstand für das Hallsensorsignal, einen LM1117-Spannungsregler sowie einen Anschluss für einen externen 1000-µF-Kondensator.
Am Eingang (IN) der Leiterplatte wird eine Wechsel- oder Gleichspannung zwischen 6 und 20 V (gemäß Datenblatt des LM1117) angelegt. Diese Spannung wird durch den Gleichrichter in eine Gleichspannung umgewandelt und anschließend mithilfe des Kondensators geglättet. Der Spannungsregler wandelt die geglättete Spannung in konstante 5 V um, die zur Versorgung des Mikrocontrollers dienen.
Der Kondensator ist aus Platzgründen nicht direkt auf der Leiterplatte montiert und wird extern angeschlossen. Zusätzliche Anschlüsse auf der Leiterplatte sind für die Anbindung der Peripherie vorgesehen.
Die Leiterplatte wurde mit Fusion 360 erstellt und kann anhand der Gerber-Files bei JLCPCB beschafft werden.
Neuere Motorräder verwenden in der Regel ein 12V-Gleichspannungssystem, wodurch der Betrieb des Tachos problemlos möglich ist. Ältere Mopeds und Motorräder hingegen verfügen oft über ein 6V-Wechselspannungssystem ohne Batterie. In solchen Fällen kann es vorkommen, dass die vom Motor erzeugte Wechselspannung im Leerlauf deutlich unter 6V sinkt. Dies führt dazu, dass der Spannungswandler nicht mehr korrekt arbeitet.
Um dieses Problem zu lösen, kann die Spannung mithilfe eines Spannungsverdopplers erhöht werden. Ein solcher Verdoppler besteht lediglich aus zwei Dioden und zwei Kondensatoren. Eine ausführliche Erklärung dieses Prinzips habe ich in einem separaten Blogbeitrag bereitgestellt.
Weitere Informationen gibt es dort:
Für das Gehäuse des Tachos wird ein alter 48 mm Tacho verwendet. Dieser wird an der Unterseite geöffnet, sodass der rechts gezeigte Aufbau hineinpasst.
Folgende Teile sind 3D geruckt:
#include "SPI.h"
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
#define Serial SERIAL_PORT_USBVIRTUAL
#endif
volatile int geschwindigkeit;
volatile unsigned long lastInterruptTime; // Zeitpunkt des letzten Interrupts
const int sensor = 1; // Pin für den Sensor
const unsigned long timeout = 1000; // Timeout für Stillstand in Millisekunden
int sensorsig;
// Individuell anpassen
const int magnetCount = 3;
const int radumfang = 1200; // mm
void setup() {
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
// Initialisierung des Displays
display.display();
delay(2000); // Pause for 2 seconds
display.clearDisplay();
pinMode(sensor, INPUT_PULLUP);
// Startzeit initialisieren
lastInterruptTime = millis();
// Interrupt aktivieren
attachInterrupt(digitalPinToInterrupt(sensor), time, FALLING);
}
void loop() {
sensorsig = digitalRead(sensor);
// Überprüfung auf Timeout
unsigned long currentTime = millis();
if (currentTime - lastInterruptTime > timeout) {
geschwindigkeit = 0; // Geschwindigkeit auf 0 setzen bei Timeout
}
// Geschwindigkeitsanzeige
display.clearDisplay();
display.setTextSize(3);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.print(geschwindigkeit, 1);
display.setCursor(50, 0);
display.setTextSize(2);
display.print(" Km/h");
display.display();
// Serielle Ausgabe
Serial.println("geschwindigkeit:");
Serial.println(geschwindigkeit);
Serial.println("sensor:");
Serial.println(sensorsig);
}
void time() {
unsigned long currentTime = millis();
unsigned long deltaTime = currentTime - lastInterruptTime;
// Zeit in Sekunden umrechnen
if (deltaTime > 0) {
geschwindigkeit = (((radumfang / 1000.0) / magnetCount) / (deltaTime / 1000.0)) * 3.6;
}
// Zeitpunkt des letzten Interrupts aktualisieren
lastInterruptTime = currentTime;
}