Unruhige Anzeige bei Drehzahlmesser für Zweitaktmotor
Hallo,
ich habe eine Motorsense und eine Motorsäge. Beide mit einem Zweitakt Benzinmotor angetrieben. Die sind schon in die Jahre gekommen und nach einem Membran- und Dichtungstausch im Vergaser möchte ich die nun wieder einstellen bzw Einstellung kontrollieren.
Das geht für den Leerlauf indem man mit der L Schraube auf maximale Drehzahl im Leerlauf einstellt und dann das Gemisch noch eine Idee fetter einstellt. Mit Standgasschraube die Drehzahl senken bis auskuppeln plus Sicherheitsabstand. Problem ist die Maximaldrehzahl bei Vollgas richtig einzustellen. Dazu bräuchte man eigentlich einen Drehzahlmesser. Die sind heute gar nicht mehr so teuer aber warum nicht selber bauen?
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.
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, 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. 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. Probeweise ist da noch eine SW-Hysterese aktiv, die eine veränderte Drehzahl von einer zur anderen Sekunde nur anzeigt, wenn sich der Wert um 10Upm gegenüber der vorherigen geändert hat.
Das Ganze ist mir aber immer noch zu unruhig. Nach vielen Versuchen mit der Abnahme des Zündimpulses würde ich ein Problem dort fast ausschließen. Timingfehler im Programm auch, da mit Frequenzgenerator überprüft und dort im Bereich von 1000Upm bis 16000Upm stabile Werte angezeigt werden. Die Motoren laufen im Leerlauf leicht unruhig (mit Oszi den Zündimpuls beobachtet) und mit der Messung über Sekundenintervalle auf Umdrehungen pro Minute umzurechnen erkläre ich mir die unruhige Anzeige des Drehzahlmessers.
So, Luftholen für die Fragen nach dem vielen Text:
Wie krieg ich eine ruhige aber doch aktuelle Anzeige für eine Vergasereinstellung hin? Wie wird das bei den professionellen Drehzahlmessern gemacht? Wird da einfach über einen größeren Zeitraum gemittelt und/oder Ausreißer ignoriert? Hat jemand konkrete Werte dazu?
Gruß
Searcher
gegenwärtiges Testprogramm:
Code:
$regfile = "ATtiny2313.DAT"
$framesize = 24
$swstack = 24
$hwstack = 34
$crystal = 8000000
$baud = 57600
$lib "mcsbyteint.lbx"
Dim Icr_new As Word
Dim Icr_old As Word
Dim Icr_difference As Word
Dim Upmd As Dword
Dim Upm As Word
Dim Tov_count As Byte
Dim Accumul_difference As Dword
Dim Averaged_ign_time As Dword
Dim Icp_events As Word
Dim Icp_alive As Byte
Dim Upm_o As Word 'Upm old
Dim Upm_h As Integer 'Upm Hysteresis
Print "Drehzahlmessung Upm"
Tccr1b = Bits(cs11 , Ices1) 'prescaler = 8, 1µs timer steps, icp event on rising edge
On Timer1 Update_display 'timer1 overflow
Enable Timer1
On Icp1 Get_icr 'ignition spark occured
Enable Icp1
Enable Interrupts
Do
Loop
Get_icr:
Icr_new = Icr1
Icr_difference = Icr_new - Icr_old
Icr_old = Icr_new
Accumul_difference = Accumul_difference + Icr_difference
Incr Icp_events
Icp_alive = 1
Return
Update_display:
Incr Tov_count
If Tov_count = 15 Then '15 makes about 1s display interval
Averaged_ign_time = Accumul_difference / Icp_events
Upmd = 60000000 / Averaged_ign_time 'Icr_difference
Upm_h = Upmd - Upm_o
If Abs(upm_h) > 10 Then 'SW-hysteresis
Upm_o = Upmd
If Icp_alive = 0 Then Upm_o = 0 'no ignition detected -> Upm=0
Print " " ; Chr(13) ; Upm_o ; Chr(13);
End If
Accumul_difference = 0
Tov_count = 0
Icp_events = 0
Icp_alive = 0
End If
Return
Liste der Anhänge anzeigen (Anzahl: 5)
Hallo,
ich habe mal ein paar Messungen gemacht. Zunächst die verwendete Schaltung, die den Zündimpuls für den µC aufbereitet. (Mittlerweile fand ich im MC net weitere Kritiken dazu, die auch gar nicht gut aussehen).
Bild hier
Abblockkondensatoren sind am 4093er und ATtiny2313 vorhanden. Versorgungsspannung ist sauber.
Das Programm wurde nur dahingehend verändert, daß man vom PC Terminal die Messungen untereinander geschrieben werden und wurden von dort kopiert. SW Hysterese testet auf >-1 statt auf >10, so das von einer Sekunde zur anderen jede Änderung geschrieben wird. Außerdem wird am Anfang einer Zeile eine Meßsequenznummer ausgegeben und am Ende einer Zeile steht die Anzahl der Zündimpulsabstände, die innerhalb einer Sekunde addiert wurden und durch die dann zur Mittelwerterzeugung geteilt wurde. Zum Start einer Meßreihe wurde die Versorgungsspannung für den stromlosen Drehzahlmesser eingeschaltet.
Hier die Meßwerte mit dem Sinusgenerator (alter analoger Pegelsender von Siemens, ein W2040).
Anhang 45Hz_Sinus_1Min_lang_60Updates.txt
Anhang 283Hz_Sinus_1Min_lang_60Updates.txt
Und Oszillogramme:
45Hz_Sinus_Pin8.png, Kanal 1 - Generatorsignal wie in Schaltung an C3, Kanal 2 - von Pin 8 des CD4093
Bild hier
45Hz_Sinus_µC.png, Kanal 1 - Generatorsignal wie in Schaltung, Kanal 2 - rechte Seite von R4
Bild hier
283Hz_Sinus_Pin8.png
Bild hier
283Hz_Sinus_µC.png
Bild hier
Hier Messungen an einer Motorsäge im Leerlauf, die vom Werk auf 2700Upm eingestellt ist. Dazu muß man sagen, daß je nach Temperatur die Leerlaufdrehzahl anders ist. Abweichungen davon sind also normal. Ich wüßte nur zu gerne in welchem Maße die Drehzahl zB im Sekundentakt abweicht. Im Oszi erkennt man deutlich Abweichungen von einem Zündungsabstand zum anderen. Der Zündimpuls wurde einmal einadrig mit Krokoklemme am Zündkabel abgenommen und an C2=220pF angeschlossen. Bei den beiden anderen Meßreihen wurde der Draht mit 3 Windungen um das Zündkabel gelegt und mit C2=220pF und mit C2=1nF gemessen. (Meßreihe mit Kroko an 1nF ist verschwunden :-( )
Anhang Kroko_220pF.txt
Anhang 3Wdg_220pF.txt
Anhang 3Wdg_1nF.txt
Die Oszillogramme zeigen Kanal 1 an Pin 8 vom CD4093, Kanal 2 an rechter Seite von R4, also das Signal daß zum µC geht. Kanal 1 ict AC gekoppelt. +5V Gleichspannungsanteil dazu rechnen.
Kroko_220pF.png
Bild hier
Kroko_1nF.png
Bild hier
3Wdg_220pF.png
Bild hier
3Wdg_1nF.png
Bild hier
Und noch das Zündabnahmedrahtsignal Kanal 1 (Kein Gleichstromanteil) direkt vor C2 und Kanal 2 nach R4.
raw.png
Bild hier
Alles erstmal ohne Kommentar, da selbst noch nicht genauer analysiert. Jedoch sind die Schwankungen geringer als bei meinen ersten Versuchen - warum auch immer? Subjektiv funktioniert es mit Wicklung um das Zündkabel besser..
Gruß
Searcher
Liste der Anhänge anzeigen (Anzahl: 3)
Guten Morgen Searcher,
dein Oszilloskopbild habe ich mal vergrößert und ausgedruckt und mit dem Lineal gemessen.
Anhang 34204
Hier ist eindeutig zu erkennen, dass die Messwerte erheblich schwanken.
Da Du anscheinend wenig RAM zur Verfügung hast, wäre ein Softwarefilter (Tiefpass) angebracht.
Ich hab mal in mühsamer Kleinarbeit einen Tiefpass geschrieben, der ohne Floats auskommt
und auch keinen Puffer benötigt, da er in Echtzeit (Samplegenau) funktioniert.
Der Code ist absolut trivial, aber entspricht exakt einem RC-Tiefpass und lässt sich sehr einfach anpassen.
Zunächst mal einige Erläuterungen dazu:
Das Entscheidende ist die Abtastrate (Samplerate) also wieviele Messwerte kommen pro Sekunde
und die Centerfrequenz (Fc) des Filters.
Beispiel bei mir:
Mein ADU liefert 1000 Messwerte pro Sekunde, das ist also die Abtastrate
Die Centerfrequenz (Fc) ist die Frequenz an dem die Amplitude um 3 Dezibel fällt wenn man eine
Sinusschwingung durch den Filter schickt.
Um sich unnötige (komplizierte) Berechnungen zu ersparen, kann mein Controller eh nicht
habe ich "vorab" einen Faktor benannt mit "D" berechnet.
Dieser Wert wird nur einmal (extern, Taschenrechner) berechnet und abgelegt.
Da ich keine floats habe, wird der Wert vorher noch mit 65536 multipliziert
So kann ich auch Nachkommastellen berücksichtigen
Ich habe den Code inzwischen in Pascal und C implementiert, aber ich denke das sollte kein Problem sein
ihn nach (sieht aus wie Basic ?) zu konvertieren.
Die Funktion ist für 32 Bit Integer ausgelegt
In Basic musst Du vermutlich den Typ long nehmen für 32 Bit
Dreh und Angelpunkt ist die Vorabberechnung bzw. der Wert von "D"
D:=1-exp(-(2*pi*Fc) / Samplerate);
Hier kannst Du aber auch ganz experimentell Werte probieren und schauen wie es sich verhält.
Die "C" Variante
Code:
/*---------------------------------------------------------------------------*/
/* Siro's Spezialfunktion für einen Softwarefilter Tiefpass */
/* simuliert exakt ein ganz normales R/C Glied */
/* D:=1-exp(-(2*pi*Fc) / Samplerate); */
/* Fc ist die Centerfrequenz, der -3dB Punkt */
/* dann den Wert noch mit 65536 multiplizieren, wegen Integer Berechnungen < 0 */
/* Bezogen auf eine Abtastrate von 1000 Hz (1KHz) ergeben sich folgende Werte */
/* D = 21 ==> Fc = 0.05 Hz */
/* D = 41 ==> Fc = 0.1 Hz */
/* D = 206 ==> Fc = 0.5 Hz */
/* D = 410 ==> Fc = 1 Hz */
/* D = 818 ==> Fc = 2 Hz */
/* D = 2026 ==> Fc = 5 Hz */
/* D = 3991 ==> Fc = 10 Hz */
/* D = 7739 ==> Fc = 20 Hz */
/* D = 17668 ==> Fc = 50 Hz */
/* D = 30573 ==> Fc = 100 Hz */
/* D = 46884 ==> Fc = 200 Hz */
/* D = 62704 ==> Fc = 500 Hz */
S32 flowFilter(S32 value)
{ const S32 d = 206; // LowPassFilter Fc=0.5 Hz at 1000 Hz Samplerate
static S32 n = 0;
static S32 rest = 0;
S32 xx;
value = value - n;
xx = value * d;
rest = (xx+rest) % 65536; // % ist MOD Modulo (Divisionsrest) in "C"
xx = (xx+rest) / 65536;
n = n + xx;
return n;
}
/*---------------------------------------------------------------------------*/
Die "Pascal" Variante:
Code:
{------------------------------------------------------------------------------}
// !!!!! die mit const deklarierten Variablen
// müssen "statisch lokal" sein oder "global"
// sie müssen also erhalten bleiben nach dem Verlassen der Funktion
// in Pascal kann man das mit Const erzwingen.
Function FilterTP(value:Integer):Integer; // Tiefpass
const d : Integer = 206; // LowPassFilter Fc=0.5 Hz at 1000 Hz Samplerate
const n : Integer = 0;
const rest : Integer = 0;
var xx : Integer = 0;
begin
value:= value - n;
xx := value * d; // d ist ja schon mit 65536 multipliziert
rest := (xx + rest) MOD 65536; // wir muessen jetzt durch 65536 teilen
xx := (xx + rest) DIV 65536; // und den jeweiligen rest uns merken
n := n + xx;
result:=n;
end;
{------------------------------------------------------------------------------}
Der Aufruf erfolgt mit
Messwert:=FilterTP(Messwert); // durch den Filter jagen
Ausgabe(Messwert); // hier dann anzeigen
Du kannst einfach mit dem Wert für "D" herum experimentieren,
je kleiner der Wert wird, umso ruhiger wird auch deine Anzeige, aber auch träger.
PS.: Die Variablen innerhalb der Funktion solltest Du vermutlich "GLOBAL" definieren, ich hab nicht gefunden dass Basic statische lokale Variablen kann...
Einfach mal den D Wert irgendwie setzen und vor deiner Anzeige des Messwertes diesen durch den Filter schicken.
Siro
Hier mal ein Beispiel was er aus meinem verrauschten Signal macht: die grüne Kurve ist die gefilterte mit obigen Code.
Anhang 34205
Hier habe ich den D-Wert vergößert: es wird etwas unruhiger, aber dafür schnellere Reaktionszeit
Anhang 34206
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat von
Searcher
Filter hab ich noch nicht gemacht.
Doch, sicher. Einen Buffer mit Messwerten füllen und daraus den Mittelwert bilden, ist ein Filter. Ich hatte in meinem vorigen Beitrag schon ein einfaches Tiefpassfilter angedeutet. Ich will das hier noch mal etwas ausführlicher beschreiben.
Damit das folgende besser verständlich ist, erläutere ich hier mal die von mir verwendeten Begriffe. Erstens der Messwert. Dieses ist das ungefilterte Ergebnis einer Messung: ein ADC-Wert (Spannung), der Temperaturwert aus einem digitalen Sensor, die Messwerte aus einem Accelerometer oder Gyrosensor oder, wie hier, die Zeit aus einem Input Capture. Und zweitens der Anzeigewert. Dies ist der Wert nach dem Filter und hat die selbe Einheit und Skalierung wie der Messwert. Der Messwert wird regelmäßig ermittelt, hier im Capture-Interrupthandler. Es könnte genausogut ein ADC im Timerinterrupt sein.
Die allgemeine Formel für einen Tiefpass ist: (neuer) Anzeigewert = k * (alter) Anzeigewert + (1 - k) * Messwert
k ist ein Koeffizient zwischen 0 und 1. Da einmal mit k und einmal mit 1-k multipliziert wird, bleibt die Skalierung von Messwert und Anzeigewert gleich. Der neue Anzeigewert ist also ein gewichtetes Mittel aus dem alten Anzeigewert und dem aktuellen Messwert.
Zur Abschätzung, was diese Formel bewirkt, kann man mal Extremwerte für k wählen: für k = 0 erhält man immer den aktuellen Messwert, das Filter hat keine Wirkung. Für k = 1 erhält man den Anzeigewert und der bleibt konstant. Zusammen mit der Frequenz, mit der die Messungen erfolgen, gibt k die Grenzfrequenz des Filters. Siro hat das dargestellt und ausgerechnet, ich kneife mir typisch die Rechnung und probiere einfach.
Wie kann man die Rechnung eines solchen Filters für einen µC leicht gestalten? Nun man verwendet Intergermathematik. Damit kann man k im Bereich 0 - 1 aber nicht darstellen. Wenn ich die Formel aber so schreibe : (k * Anzeigewert + (k - 1) * Messwert) / 1, kann man diesen Bruch so erweitern, daß sich sowohl das erweiterte k als auch (erweitert) 1 - k als Integer darstellen lassen. Wenn ich dann auch noch mit einer Potenz von 2 erweitere, wird aus dem Teilen ein Rightshift. Ein besonders einfacher Fall egibt sich für k = 0,5: (Anzeigewert + Messwert)/2. Ähnlich einfach ist auch k = 0,75: (3 * Anzeigewert + Messwert) / 4. Wobei man für µC, die keine HW-Multiplikation haben auch (Anzeigewert + Anzeigewert + Anzeigewert + Messwert) / 4 schreiben kann. Wie man hier auch erkennen kann, tragen bei k = 0,75 die alten Messwerte stärker zum Ergebnis bei als der neue Wert. Die Grenzfrequenz liegt also tiefer.
Da bei diesem Filter alle alten Messwerte (hier Anzeigewert genannt) zum neuen Wert beitragen, nennt man diese Filter IIR (Infinite Impulse Response). Infinite daher, weil jeder Messwert "für immer" mit im Anzeigewert steckt, jedoch entsprechend gering gewichtet. Wenn man im Gegensatz dazu auf einem Buffer rechnet, nennt man das ein FIR (Finite Impulse Response) Filter. Dabei kann der Buffer gleitend oder hintereinander gefüllt werden. Die Filtertypen haben unterschiedliche Eigenschaften. Ich zeig mal ein Bild, das ich aus dem Mikrocontroller.net Forum habe. Da hat Yalu X, der von digitaler Signalverarbeitung viel mehr Ahnung als ich hat, den Frequenzgang der beiden Filter mal geplottet.
Anhang 34208
In der roten Kurve erkennt man den klassischen Tiefpass, das IIR Filter. Den gleitenden Mittelwert (grüne Kurve) benutzt man gerne, um feste Störfrequenzen wie 50Hz auszublenden. Man dimensioniert es dann mit Bufferlänge und Samplingrate so, daß z.B. das erste Minimum auf diese 50Hz fällt und diese Störsignal nur sehr gering zum Ergebnis beiträgt. Da ein solcher Fall hier nicht vorliegt, sind die aufwändigere Rechnung und der größere Speicher für ein FIR nicht nötig.
Mit der Anzeige der Messwerte hat das nichts zu tun. Wenn die serielle Ausgabe kürzer ist, als die Zeit zwischen zwei Capture-Interrupts, wie du berechnet hast, kann die Ausgabe aus dem Capture-Interrupt selbst erfolgen. Das vermeidet jeglichen Konflikt. Da der Mensch nicht mehr als ca. 5 Werte pro Sekunde wirklich erfassen kann, muß man die Anzeige nicht bei jedem Interrupt updaten.
MfG Klebwax
P.S. irgendwie ist das Bild nicht angekommen, versuche es nochmal
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat von
wkrug
Und wie Du in deiner Signatur schreibst:
Zitat:
Hoffentlich liegt das Ziel auch am Weg
______________________________________:pray::pray::pray:
Jetzt habe ich schon mal einen Simulator gebastelt um die Zündimpulse nachzubilden. Ist ein ATmega88pa auf dem folgendes Programm läuft.
Code:
$regfile = "m88pdef.dat"
$framesize = 32
$swstack = 32
$hwstack = 38
$crystal = 8000000
$baud = 57600
Const Sample_count = 256 'number of samples to take
Dim Icr_old As Word
Dim Icr_new As Word
Dim Ignition_seq As Word
Dim Ignition_seq_old As Word
Dim Ocr1a_calc As Word
Dim Idx As Word
Dim Firing_interval(sample_count) As Word
Dim Intervals(sample_count) As Eram Word 'EEPROM variable
Dim Flag_rec_complete As Byte
Dim Flag_playback_running As Byte
Dim Flag_icp_dead As Byte 'indicates no pulses at ICP1 pin while recording
Config Portb.pb1 = Output 'OC1A pulse output
Config Portc.pc5 = Output 'green playback led
Config Portc.pc4 = Output 'red record led
Config Portd.pd5 = Output 'red led for playback
Portd.pd6 = 1 'pullup for "playback" button
Portd.pd7 = 1 'pullup for "start record" button
Portb.pb0 = 1 'pullup icp1 pin - stable level
On Timer1 Check_icp_alive
On Icp1 Isr_get_icr 'icp interrupt vector
On Compare1a Isr_send_pulses
Enable Interrupts
Print "Simulator start"
Do
Debounce Pind.pd7 , 0 , Start_record , Sub 'record ignition intervals
Debounce Pind.pd6 , 0 , Play_intervals , Sub 'start - stop playback
If Flag_rec_complete = 1 Then
For Idx = 1 To Sample_count
Intervals(idx) = Firing_interval(idx) 'copy sram variable to eeprom variable
Next
Print "samples copied to eram"
Flag_rec_complete = 0
Portc.pc4 = 0
Tccr1b = 0
End If
If Flag_icp_dead = 1 Then Gosub No_record
Loop
Start_record:
Tccr1a = 0 'init timer1
Tcnt1 = 0
Ignition_seq = 0
Flag_rec_complete = 0
Tifr1.tov1 = 1
Enable Timer1 'enable timer1 overflow interrupt
Icr_old = Icr1
Enable Icp1
Tccr1b = Bits(cs11 , Ices1) 'prescaler=8 timer1 clocked with 1MHz
Portc.pc4 = 1 'rec LED on
Return
No_record:
Disable Icp1
Tccr1b = 0 'stop timer1
Print "No pulses on ICP pin"
Portc.pc4 = 0
Flag_icp_dead = 0
Return
Play_intervals:
If Flag_playback_running = 1 Then 'button operated and playback running -> stop playback
Disable Compare1a
Tccr1b = 0 'stop timer1
Flag_playback_running = 0
Portc.pc5 = 0
Else
For Idx = 1 To Sample_count
Firing_interval(idx) = Intervals(idx) 'copy eeprom variable to sram variable
Next
Ignition_seq = 1
Ocr1a = Firing_interval(ignition_seq)
Print Ignition_seq ; " " ; Firing_interval(ignition_seq)
Tccr1a = Bits(com1a0) 'toggle oc1a on ocr1a compare match
Tcnt1 = 0
Tifr1.ocf1a = 1 'clear eventually set compare1a flag
Enable Compare1a
Tccr1b = Bits(cs11) 'start timer1, presacaler = 8
Flag_playback_running = 1 'green playback led on
Portc.pc5 = 1
End If
Return
Isr_send_pulses:
If Pinb.pb1 = 1 Then 'if pin is high make pulse length
Ocr1a = Ocr1a + 4000 'pulse length 4ms
Else 'else make time until next ignition
Incr Ignition_seq
Ocr1a_calc = Firing_interval(ignition_seq) - 4000
Ocr1a = Ocr1a + Ocr1a_calc
Print Ignition_seq ; " " ; Firing_interval(ignition_seq) 'visualise time in termial
End If
If Ignition_seq >= Sample_count Then Ignition_seq = Rnd(sample_count) 'continue playback with random start '
Return
Isr_get_icr:
Incr Ignition_seq
Icr_new = Icr1
If Icr_old = 0 And Ignition_seq = 1 Then
Ignition_seq = 0
Else
Firing_interval(ignition_seq) = Icr_new - Icr_old
End If
Icr_old = Icr_new
If Ignition_seq >= Sample_count Then
Disable Icp1
Tccr1b = 0 'init, stop timer1
Flag_rec_complete = 1
Ignition_seq = 0
End If
Return
Check_icp_alive:
If Ignition_seq_old = Ignition_seq Then
Flag_icp_dead = 1
Else
Ignition_seq_old = Ignition_seq
End If
Return
Das Programm kann 256 Zündimpulsabstände (limitiert durch die Größe des internen EEROMs mit 512Byte), die von der CD4093B Schaltung kommen können, aufzeichnen. Gemessen wie gehabt mit der Input Capture Funktion in µs Auflösung.
Abspielen der Impulse geschieht über den OC1A Pin. Die Impulslänge ist auf 4ms eingestellt, ähnlich wie in der CD4093B Schaltung.
Es gibt eine "Record" Taste, die die Aufzeichnung der 256 Werte startet und die rote Rec-LED einschaltet. Die ICR Daten werden erst in einem Array im RAM abgelegt. Ist das Array voll, wird es in den internen EEPROM geschrieben. Das Ende der Aufzeichnung wird durch das Erlöschen der Rec-LED angezeigt.
Über die "Playback" Taste werden die Impulse über den OC1A Pin elektrisch nachgebildet und der Impulsabstand in µs als Zahl auch über RS232 ausgegeben. Eine grüne LED leuchtet während des Abspielens. Nachdem der letzte Wert aus dem Speicherarray abgespielt wurde, wird eine Zufallszahl erzeugt, die als Index für ein Element aus dem Array als Startelement dient um wieder die restlichen Werte der Reihe nach aus dem Array auszugeben. Nochmaliges Drücken der Playback stoppt das Abspielen.
Im Anhang noch 256 Zündimpulsabstände (Einheit = µs) mit Ordnungsnummer, die bei noch kalter Maschine über etwa 5 Sekunden aufgezeichnet wurden. In einem Graph dargestellt ergab sich ein echt unerwartet interessantes Bild :-)
Gruß
Searcher
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Zitat von
Klebwax
Leider sind in der Tabelle die schon verrechneten Werte. Schöner wäre es gewesen, wenn du einfach die Werte des Capture Register aufgezeichnet hättest
Hab ich jetzt gemacht. Die ISR "Isr_get_icr" zum Sichern des ICR-Werte verändert, so daß jetzt der echte Inhalt aufgezeichnet wird. siehe Code. Der Rest des Simulatorprogramms von weiter oben im thread ist unverändert. Samples wieder im Anhang.
Code:
Isr_get_icr:
Incr Ignition_seq
Firing_interval(ignition_seq) = Icr1
If Ignition_seq >= Sample_count Then 'array full, stop recording
Disable Icp1 'disable ICP1
Tccr1b = 0 'init, stop timer1
Flag_rec_complete = 1
Ignition_seq = 0
End If
Return
Zitat:
Zitat von
Ceos
Ich vermute dein Problem immernoch beim Messaufnehmer oder eventuell im "debounce"
Wenn du nochmal Daten sammeln kannst und zusätzlich eine Info ob und wieviel Überläufe zwischen den Samples liegen? (eventuell einfach den Zeitwert nehmen und die unteren beiden Bits maskieren und überschreiben, Bit 1 für timer einmal übergelaufen und Bit 0 für Timer mehr als einmal übergelaufen)
Es sollten eigentlich kein Meßfehler vorliegen. Der Debounce Befehl in Bascom nutzt keinen Interrupt. Wenn die Hauptschleife dort vorbeikommt, wird erst nur der Pin auf gedrückte Taste, in diesem Fall nur einmal auf LOW-Pegel getestet. Wenn kein Tastendruck, also kein Low-Pegel erkannt wird, wird sofort in der Haupschleife weitergemacht. Während der Aufzeichnung ist keine Taste gedrückt. Wenn auf gedrückte Taste erkannt wurde, kann die Hauptschleife, wenn nichts anderes konfiguriert wurde, bis zu 25ms aufgehalten werden. Sprung zu Interrupts würden dadurch aber nicht behindert werden. Im Dateianhang "icr_werte.txt" sind die ICR Werte abgelegt. Man kann dort die Überläufe erkennen wenn nach einem hohen Wert ein kleinerer auftaucht. Falls noch mehr Daten gebraucht werden - kein Problem ...
An der Impulsaufnahme zweifle ich auch nicht, da mehrfach direkt am Abnahmedraht und mehreren Stellen in der CD4093 Schaltung mit Oszi überprüft. Halte meine Augen aber trotzdem auch in der Richtung noch offen.
Ich denke, der Motor läuft wirklich so wie die Daten es zeigen. Das Laufgeräusch im Leerlauf bei Standgas ist alles andere als rund und "schnurrend". Typisches Zweitaktergeräusch; scheint normal zu sein. Ganz am Anfang vom Video https://youtu.be/d9_J9TI6dx8 läuft auch eine im Standgas. Anwerfen und Laufgeräusch meiner Säge als MP3 mit 7zip in der zip Datei im Anhang.
Gruß
Searcher
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat von
Ceos
Overflow sollte einen eigenen interrupt haben
Hat Timer1. Erklärung s.u.
Zitat:
Zitat von
Ceos
kannst du mal ein paar bits opfern um den timerüberlauf mit zu erfassen wie ich es oben beschrieben habe?!
Zitat:
Kannst du mir mal aufschlüsseln wie dein capture timer konfiguriert hast?! 8Mhz F_CPU sehe ich ja aber bei der timer init komm ich ins schleudern
Die Programmteile stammen aus dem Simulator Programm.
Code:
On Timer1 Check_icp_alive 'on timer1 overflow -> ISR Check_icp_alive
On Icp1 Isr_get_icr 'on icp1 interrupt -> ISR isr_get_isr
Start_record:
Tccr1a = 0 'init timer1
Tcnt1 = 0
Ignition_seq = 0
Flag_rec_complete = 0
Tifr1.tov1 = 1 'reset eventually set TOV1 Flag
Enable Timer1 'enable timer1 overflow interrupt
Icr_old = Icr1 'not nessecary. artifact ?
Enable Icp1 'enable ICP1 Interrupt
Tccr1b = Bits(cs11 , Ices1) 'prescaler=8 timer1 clocked with 1MHz, ICP Interrupt on rising edge
Portc.pc4 = 1 'rec LED on
Return
Isr_get_icr:
Incr Ignition_seq
Word_variable = Icr1 / 10
Firing_interval(ignition_seq) = Word_variable * 10 'letzte Dezimalstelle auf Null
If Ignition_seq >= Sample_count Then 'array full, stop recording
Disable Icp1 'disable ICP1
Tccr1b = 0 'init, stop timer1
Flag_rec_complete = 1
Ignition_seq = 0
End If
Return
Check_icp_alive:
Firing_interval(ignition_seq) = Firing_interval(ignition_seq) + 1 'bei timer1 überlauf wird zum letzten gespeicherten ICR wert Eins addiert
If Ignition_seq_old = Ignition_seq Then
Flag_icp_dead = 1
Else
Ignition_seq_old = Ignition_seq
End If
Return
Mit zB "on timer1 check_icp_alive" werden die Interrupt Vektoren initialisiert
Die "Start_record" ist ein Unterprogramm und wird mit Drücken der Record Taste aufgerufen.
Dort wird der Timer1 initialisiert und mit Vorteiler 8 gestartet. Läuft bei Systemtakt von 8MHz dann mit 1MHz, Periodendauer = 1µs. Vorteil: Den ausgelesenen Wert aus ICR1 kann man mit Einheit µs versehen. Hab noch ein paar Remarks im Code eingefügt. Mit den Interrupts scharf machen (enable) und Starten des Timers beginnt die Meßwertaufnahme.
Die ISR_get_icr ist eine ISR und wird durch den ICP Interrupt aufgerufen. Dort wird jetzt die letzte Dezimalstelle auf Null gesetzt. Wenn 256 Werte aufgenommen sind wird Timer1 gestoppt mit tccr1b=0 und der ICP Interrupt wieder disabled.
Die ISR Check_icp_alive wurde und wird bei Timer1 Überlauf aufgerufen und dient eigentlich dazu festzustellen, ob überhaupt ICP Interrupts (Zündimpulse) auftreten. Aussetzen kann passieren, wenn zB das Impulsabnehmerkabel nichts liefert. In dieser ISR wird jetzt zusätzlich dem letzten, vor dem Overflow gespeicherten ICR Wert, Eins aufaddiert. Falls sich da was verschluckt müßte an der letzten Stelle mal eine Zwei auftauchen. Eine Eins immer dann, wenn nach einer großen Zahl eine kleinere auftauscht.
Im Anhang die Werte mit diesem Programm.
Zitat:
Worum es mir geht ist eine inkonsistenz deiner werte alle ~10 messungen, irgendwas passiert da dass das timing durcheinanderbringt!
Ich glaube, daß die Meßwerte stimmen. Die Ausreißer könnten von der Drehzahlregelung der Maschine kommen: Die Drehzahl sinkt langsam ab. Dann wird schnell auf höhere Drehzahl geregelt. Ein Ausreißer ist die Zündung auf dem Weg nach "oben". Dann sinkt die schnelle Drehzahl wieder langsam ab bis das Spiel von vorne beginnt.
Gruß
Searcher