Zitat von
Searcher
Im Mikrocontroller.net fand ich eine Schaltung zur einfachen Zündimpulsabnahme mit einem Draht vom Zündkabel:
https://www.mikrocontroller.net/topic/81838#685809
Nachgebaut (27k an Pin 12 gegen 47k getauscht und um eine Zenerdiode an Pin 8 erweitert -> mein Meßbereich damit 1000Upm bis ca. 17000Upm - 2700min bis 13500max benötigt) und zur Berechnung der Drehzahl einen ATtiny2313 über einen 1k Widerstand an Pin 3 des (TC)4093 angschlossen. Es soll später noch eine Siebensegmentanzeige angeschlossen werden. In der Testphase sende ich die gemessene Drehzahl über
RS232 an einen PC.
Mit der Schaltung hab ich so meine Probleme. Eigentlich kann sie nicht funktionieren, eine Spannung kann man nicht mit einem Anschluß Messen bzw. weiterverarbeiten. Man braucht immer zwei Anschlüsse. Eine Spannung ist per Definition eine Potentialdifferenz, es gehören also zwei Potentiale dazu. Die Masse der Schaltung müsste mit der Masse des Motors verbunden werden, so wie auch der andere Anschluß der Zündspule. In Praxis kann es natürlich durch kapazitive Kopplung der Massen trotzdem gehen. Zum Zweiten enthält sie ein Monoflop. Diese sind nicht umsonst in professionellen Schaltungen verpönt bis verboten, da sie notorische Störimpuls-Verstärker und Verlängerer sind. Aber auch das muß im Einzelfall keine Rolle spielen.
Die professionellen Zündimpulsabnehmer, die ich kenne (ist aber schon eine Weile her), arbeiten Induktiv. Dazu wird ein geschlossener Ferritkern um das Zündkabel gelegt, auf dem eine Abnehmerspule ist. Für den praktischen Betrieb ist das ein Klappkern in einer Zange. Das Ganze hat den Vorteil, daß der Ausgang galvanisch vom Motor getrennt und niederohmig ist. Auch kann man ein abgeschirmtes Kabel verwenden, seine Kapazität würde bei einem kapazitiven Abnehmer das Signal kurzschließen. Zum Ausprobieren kann man eine Entstördrossel auf einem Ringkern nehmen, durch den das Zündkabel passt.
Wenn das Signal bei deinem Aufnehmer bei allen Drehzahlen auf dem Scope sauber aussieht, vergiss meinen Text wieder, dann ist alles gut.
Funktioniert soweit ABER die gemessenen Werte schwanken doch relativ stark um den angepeilten einzustellenden Wert. Bei einer neuen Maschine, noch vom Werk eingestellt auf hoffentlich auf 2700Upm messe ich zB 2500 bis 3100Upm. Das ist mir deutlich zu unruhig und kann damit keine befriedigende Einstellung vornehmen.
Blauäugig hatte ich zunächst per ICP mit dem, mit 1MHz laufenden 16Bit Timer die Zeit zwischen den Zündimpulsen auf 1µs genau gemessen, Drehzahl auf eine Minute hochgerechnet (Upm=60000000/Meßwert in µs) und die zur Displayupdatezeit (jede 1/2 Sekunde) den gerade aktuellen Wert angezeigt: Sehr, sehr unruhige Anzeige
Nach ein paar Versuchen die angezeigte Drehzahl ruhiger zu bekommen, zB auch mit Zählung der Zündimpulse innerhalb einer feste Torzeit von zB einer Sekunde,
Das Signal ist für eine Torzeitmessung zu langsam. Die Einheit, um die es geht ist U/min. Um eine Auflösung von 10 Umdrehungen zu bekommen, muß man eine Torzeit von mindestens 1/10 Minute, also 6 Sekunden haben. In der Zeit kann sich aber die Drehzahl des Motors geändert haben, Es ist also prinzipiel keine stabile Anzeige möglich.
bin ich nun bei folgender Lösung angelangt:
Displayupdate von etwas über einer Sekunde. Innerhalb dieser Sekunde werden die Zeiten zwischen den Zündimpulsen per ICP gemessen und aufaddiert
Ich habe mal einen gebaut und das auch so gemacht. Ein kleines Problem dabei ist, daß der Timer ab und an mal überläuft. Das kann man bei der Bestimmung der Zeit berücksichtigen. Im ersten Versuch hab ich den Fall einfach ignoriert. Wenn also der aktuelle Timerwert kleiner als der vorige war, ein Überlauf aufgetreten ist, hab ich den Wert verworfen. Ich war zu faul mir zu Überlegen, wie das mit Überläufen mit unsigned Variablen (ich benutze C) so geht. Am Ende hab ich das nie korrigiert. Hier mal der Code (in C):
Code:
long Time = 1;
volatile int Tout;
void _ISR __attribute__((no_auto_psv)) _IC3Interrupt(void) {
static long old_timer = 0;
unsigned long new_timer;
_IC3IF = 0; // das Interruptflag muß händisch gelöscht werden
new_timer = IC3BUF; // das Inputcapture Register
if (new_timer > old_timer) { // kein Überlauf
Time = new_timer - old_timer;
}
if (Time <= 0) { // Time nie 0 werden lassen
Time = 1;
}
old_timer = new_timer;
Tout = 0;
}
Bei meinem µC hab ich einen 32-Bit Timer, daher long Variable. Falls beim Weiterverarbeiten mal durch Time geteilt wird, vermeide ich den Wert 0, reine Paranoia. Zur Variable Tout sag ich später noch was.
Mit der Anzahl der aufgetretenen ICP-Interrupts (Anzahl der Zünimpulse) wird dann der einfache Mittelwert ausgerechnet und zu Anzeige gebracht. Zu Beginn des nächsten Anzeigeintervalls sind alle Meßwerte gelöscht und es beginnt eine komplett neue Drehzahlmessung und Berechnung.
Das ist eigentlich suboptimal. Man muß viele Messwerte speichern und die Anzeige wird langsam. Eigentlich braucht man einen Tiefpass auf die Messwerte, so wie es früher analoge Anzeigen inherent hatten. In Software lässt sich das leicht realisieren. Man nimmt einfach den letzten Messwert, addiert den aktuellen und teilt durch zwei. Das Ergebniss zeigt man an und merkt es sich als letzten Messwert. Das geht sehr schnell (eine Addition und teilen durch zwei) und benötigt nur eine Variable. Ich bin nicht so der große DSP Experte, das nennt sich wohl IIR-Filter. Wenn ich Messwerte im Interrupt bekomme, rechne ich das häufig gleich mit und entscheide später, ob ich mit dem Originalwert oder dem geglätteten weiterarbeite. Das mal so als Pseudocode (in meinem Drehzahlmesser hab ichs nicht gebraucht)
Code:
int Messwert;
int Geglättet;
void Messinterrupt()
static AlterWert;
Messwert = GetMesswer();
Geglättet = (AlterWert + Messwert) / 2;
AlterWert = Geglättet;
}
Ich hab das bei meinem Drehzahlmesser nicht gebaucht, daher ist das ohne Gewähr aus dem Kopf aufgeschrieben. Aber hier der Rest meines Drehzahlmessers.
Code:
int TachoMain(){
Tout = 0;
while (1) {
Tout++;
if (Tout > 50) {
ShowValue(UNDEFINED, 0); // keine Drehzahl messbar
Time = 1;
} else {
ShowValue(INT, (int)(375300L / Time));
}
delay(50);
}
}
Gut, ShowValue() geht auf die Anzeige und ist hier nicht zu sehen, da beliebig HW-abhängig. Wenn lange kein Interrupt gekommen ist, läuft Tout hoch und zeigt, daß kein gültiger Messwer vorliegt. Als "undefined" zeige ich alle horizontalen Segmente, das kann man auch gut aus den Augenwinkel erkennen, wenn man gerade irgend etwas einstellt. Im Wert "375300L" stecken die CPU Clock und alle Prescaler. Den Wert müsste man ändern, wenn mehr als ein Puls pro Umdrehung kommt. Da der µC sonst nichts zu tun hat, hab ich einfach ein Delay von 50ms in die Mainloop gesetzt, Als Hardware benutze ich eine Reflexlichtschranke und weißes bzw. schwarzes Klebband.
Ich hoffe, ich konnte dir ein paar Anregungen geben.
MfG Klebwax
Lesezeichen