Ich krame das Teil mal wieder hoch. Ich denke, es passt soweit ganz gut hierher.
Seit geraumer Zeit, bin ich nebenbei dran die Software für das eFH-Steuergerät in Eigenregie neu zu schreiben. Wie einigen eventuell bekannt ist, hat mein Kumpel sich aus dem Projekt zurückgezogen und den Datensatz verkaufen, wollte er damals auch nicht. Ich hatte aber auch keinen Bock dafür einen Kniefall zu machen. Also begann ich mir das Proggen, so weit wie nötig selbst beizubringen. Nach dem VSR und Spoiler-Steuergerät dachte ich noch, das mit dem Fensterheber ist eine andere Nummer, das wird nix, aber wenn auch mit vielen und teils monatelangen Pausen dazwischen, habe ich mich trotzdem immer wieder aufgerafft und am Code weiter gearbeitet. Teils habe ich 2 Wochen lang ein und dasselbe Problem versucht zu lösen. Dann entnervt in die Ecke gelegt und dann Monate später wieder angefasst. Wenn ich wegen des Steuergerätes angeschrieben wurde, habe ich dem einen oder anderen gesagt, dass ich dran arbeite, aber nicht weiß, ob es jemals fertig werden würde. Groß an die Glocke habe ich das Projekt auch nicht gehangen, da es wirklich relativ komplex ist.
Ich verdeutliche das mal an einem Codeschnipsel, der nur den Taster für das Fahrerfenster in Richtung hoch abfragt:
/**
* Fenstersteuerung (FS) Taster-Logik
*
* Zustandsübersicht varSW1state:
* 0 = Idle
* 1 = UP Debounce läuft
* 2 = UP Motor aktiv
* 3 = UP Lang gehalten (> 22 Ticks)
* 4 = DN Debounce läuft
* 5 = DN Motor aktiv
* 6 = DN Lang gehalten (> 22 Ticks)
*/
#include <stdint.h>
#include <stdbool.h>
/* ── Externe Variablen / Hardware-Abstraktionen ──────────────────────────── */
extern uint32_t timer(void); /* Gibt aktuellen Systemtimer zurück */
extern void high(int pin); /* Setzt GPIO-Pin auf HIGH */
extern void low(int pin); /* Setzt GPIO-Pin auf LOW */
/* GPIO-Pins */
#define outFSup 4 /* Port Nummer*/
#define outFSdn 6 /* Port Nummer */
/* ── Systemzustand ───────────────────────────────────────────────────────── */
extern int sysState; /* Globaler Systemzustand (3 = gesperrt) */
extern int fs_handled; /* 0 = Taster-Logik ausführen */
/* Eingangssignale */
extern int fs_upNow; /* 1 = UP-Taste aktuell gedrückt */
extern int fs_dnNow; /* 1 = DN-Taste aktuell gedrückt */
extern int fs_blockUp; /* 1 = UP gesperrt (z. B. Endschalter) */
extern int fs_blockDn; /* 1 = DN gesperrt (z. B. Endschalter) */
/* ── Interne Zustandsvariablen ───────────────────────────────────────────── */
static int varSW1state = 0;
static uint32_t varSW1dbTime = 0;
static uint32_t varSW1time = 0;
static int varFSMotorState = 0;
static uint32_t varFSMotorTime = 0;
static uint32_t varFSIlimStart = 0;
/* ── Main-loop ───────────────────────────────────────────────────────── */
void FS_TasterLogik(void)
{
uint32_t tmpW1;
/* Guard: Systemzustand 3 → gesamte Logik überspringen */
if (sysState == 3) {
goto SkipTasterFS;
}
if (fs_handled == 0) {
/* ── UP (Aufwärts) ──────────────────────────────────────────────── */
if (fs_upNow == 1 && varSW1state == 0 && fs_blockUp == 0) {
/* Taste frisch gedrückt → Debounce starten */
varSW1state = 1;
varSW1dbTime = timer();
} else if (fs_upNow == 1 && varSW1state == 1) {
/* Debounce läuft → Zeit prüfen */
tmpW1 = timer() - varSW1dbTime;
if (tmpW1 >= 2) {
varSW1state = 2;
varSW1time = timer();
varFSMotorState = 2;
high(outFSup);
low(outFSdn);
varFSIlimStart = timer();
}
} else if (fs_upNow == 1 && varSW1state == 2) {
/* Motor läuft → auf Langdruck prüfen */
tmpW1 = timer() - varSW1time;
if (tmpW1 > 22) {
varSW1state = 3;
}
} else if (fs_upNow == 0 && varSW1state == 3) {
/* Langdruck losgelassen → Motor sofort aus */
varSW1state = 0;
varFSMotorState = 0;
low(outFSup);
low(outFSdn);
} else if (fs_upNow == 0 && varSW1state == 2) {
/* Kurzdruck losgelassen → Kurz- oder Langdruck-Ende? */
tmpW1 = timer() - varSW1time;
if (tmpW1 <= 22) {
/* Kurzdruck: Motor per Timer nachlaufen lassen */
varSW1state = 0;
varFSMotorState = 1;
varFSMotorTime = timer();
} else {
/* Zu lang → Motor aus */
varSW1state = 0;
varFSMotorState = 0;
low(outFSup);
low(outFSdn);
}
}
Alles anzeigen
Im Grunde werden damit nur die 2 Dinge hier erfüllt, die Erkennung eines langen, oder eines kurzen Tastendrucks. Ich habe den Code-Schnippsel hier im Video mal auf einem BreadBoard ausgeführt:
Demovideo kurzer und langer Tastendruck
Die grüne LED symbolisiert den laufenden Motor auf der Fahrerseite. Hier zwar nach unten und nicht wie im Code nach oben, aber das spielt für die Verdeutlichung keine Rolle.
Der Ablauf ist komplex. Das Programm durchläuft vollständig eine endlose Schleife und hält nie an. Es darf nicht anhalten, sonst bekommt es z.B. einen Tastendruck nicht mit oder erkennt nicht, dass das Fenster zu ist und stoppt den Motor nicht. Daher muss das Programm immer laufen.
Wenn man die Taste drückt, wird zunächst ein aktueller Zeitstempel vom Timer abgefragt und in eine Variable geschrieben, die anschließend um 20 ms erhöht wird. In einer weiteren Variable wird dann eine 1 geschrieben, was bedeutet, dass der Taster gedrückt wurde, der Tastendruck aber noch nicht bestätigt ist.
Der Code läuft derweil weiter und kommt alle paar ns wieder an dieser Stelle vorbei. Irgendwann sind die 20 ms vorbei, der Timer hat den Wert des tmpTimers erreicht und nun wird geprüft, ob der Taster nach 20 ms immer noch gedrückt ist. Ist das der Fall, wird die Tastervariable von 1 auf den Wert 2 aktualisiert. Wenn nicht, bekommt die Variable den Zustand 0.
Wir gehen jetzt aber von 2 aus. Das bedeutet, dass schon sicher ist, dass ein Fenster gefahren werden soll. Ob nun im Komfortlauf oder nur so lange, wie der Taster gedrückt ist, ist noch nicht klar, aber nach 20 ms steht fest, dass etwas bewegt werden muss.
Im ersten Moment geht das Programm von einem Komfortlauf aus und setzt eine Motorvariable von 0 auf 1. Irgendwann kommt das Programm an einer Abfrage vorbei, in der steht: Wenn Motor = 1, dann schalte das Relais für den Motor durch und der Motor beginnt sich zu bewegen.
Derweil prüft der hier abgebildete Code, ob nach 220 ms der Taster immer noch gedrückt ist. Ist er das nicht, geht der Taster im Zustand 0 und die Variable für den Motor bleibt bei 1. Das Fenster fährt bis zur Endlage und wird dann durch Messen der Stromaufnahme gestoppt. Wird der Taster jedoch länger als 220 ms gedrückt, wechselt die Tastervariable in den Zustand 3 und die Motorvariable in 2. Der Motor wird nur noch so lange gefahren, wie der Taster tatsächlich gehalten wird. Nach Loslassen des Tasters geht alles in 0
Es ist, wie geschrieben, alles sehr komplex
und das ist auch noch nicht alles, was da drin steckt, denn man kann den Komfortlauf ja jederzeit stoppen.
Ist jemand nicht mitgekommen? Irgendwelche Fragen? 😅
Das war ein kurzer Exkurs in die Welt der Bits & Bytes. Natürlich steckt noch viel mehr dahinter, denn es gibt ja nicht nur den einen Taster, sondern sechs für die Fenster direkt und zwei Signale vom Türschloss (ZV auf und zu), ein Schiebedach, einen Piepser und ein Signalhorn, Motoren, deren Richtung umgepolt werden muss, die Zündung und auch die Information, ob die Fahrertür geöffnet wird. Das alles muss ständig ausgewertet werden.
Alles muss immer und gefühlt gleichzeitig passieren.
Stand der Dinge:
Sooo, lange Rede kurzer Sinn: Ich habe die Software soweit fertig. Zumindest hoffe ich das. Jetzt muss ich mich an die Arbeit machen, die mir nicht so liegt. Aber ich habe niemanden, der das für mich macht, also muss ich selbst ran. Falls es da doch jemanden gibt, der Bock hat das Gehäuse zu zeichen, bitte melden, gibt dann einen Satz Steuergeräte für lau.
Im nächsten Schritt muss ich ein Gehäuse entwerfen. Ein komplettes also: eine Steckerleiste kompatibel zum originalen Steuergerät, plus einen weiteren Stecker für die Sonderfunktionen und natürlich den Rest vom Gehäuse inklusive Halterung. Ziel ist, dass man das Steuergerät so weit wie technisch möglich 1 zu 1 tauschen kann. Danach passend dazu eine Platine entwerfen, fräsen und bestücken, dann baue ich mir das neue Steuergerät ein und werde es im Betrieb testen.
So, was meint ihr: Lohnt es sich, das Projekt fertigzustellen, oder braucht das heute eh niemand mehr?