Hallo Leutz Seid längerem schon beschäftige ich mich mit einem Projekt, das das entscheidene Fünkchen Leistung aus meinem Kart Motor kitzeln soll. Leider bin ich nun auf ein Software-Problem gestoßen auf das mir keine Antwort einfällt. Hier erstmal die Rahmenbedingungen. Atiny2313 Kontroller Hallgeber ( funktioniert auch über die 5v Spannung des Atmel und muss so nicht mehr per Optokoppler vom Atmel getrennt werden) Transistorschaltung mit einem Optokoppler zur Schaltung des Primärstroms. Softwareseitig ist nun folgendes Problem aufgetreten Wie messe ich am besten die Drehzahl des Motors bei Verwendung eines 32/2 Triggerrads. Timer auf einen festen Wert einstellen und volatile Variable erhöhen. Timer dann nullen wenn die Zahnlücke im Rad auftaucht und Zündzeitpunkt entsprechend einstellen( per Kennfeld) . Das Problem welches dabei aufgetaucht ist ist die Auflösung des Systems. Bei einer Motordrehzahl von max 14000 Umdrehungen pro Minute muss man sehr genau zünden sonst geht die ganze Motorleistung wieder flöten. Hier ein Rechenbeispiel: 14000 1/min = 233,33 1/sek 0,004285 sek pro Motorumdrehung 4,285 ms pro Motorumdrehung Annahme ich will auf 1 Grad genau zünden. 4,285 ms / 360 = 0,0119 ms pro Grad Das heißt der Timer müsste alle 0,0119 Sek den trigger auslösen damit ich dann genau zünde. Ist der Timer dazu in der Lage? Zweites Problem bleibt das Triggerrad bei einem 32/2 Triggerrad ist mir Softwaretechnisch ein Rätsel wie ich per Atmel die Zahnlücke für den Ot erkennen soll. Könnt ihr mir da helfen ? Programmiersprache soll wenn möglich Gcc sein Assembler beherrsche ich kaum. mfg Jan
> Timer auf einen festen Wert einstellen und volatile Variable erhöhen. >Timer dann nullen wenn die Zahnlücke im Rad auftaucht und > Zündzeitpunkt entsprechend einstellen( per Kennfeld) . Wozu die volatile-Variable? Warum stellst du, wenn die Zahnlücke kommt, nicht einfach den Timer auf den Zündzeitpunkt ein? > 4,285 ms / 360 = 0,0119 ms pro Grad Sind also knapp 12 µs. > Das heißt der Timer müsste alle 0,0119 Sek den trigger auslösen > damit ich dann genau zünde. Ist der Timer dazu in der Lage? Vielleicht gerade so, wenn du maximalen CPU-Takt verwendest. Der Timer ist nicht das Problem, sondern die Prozessor-Auslastung durch die 84.000 Interrupts pro Sekunde. > Zweites Problem bleibt das Triggerrad bei einem 32/2 Triggerrad ist > mir Softwaretechnisch ein Rätsel wie ich per Atmel die Zahnlücke für > den Ot erkennen soll. Könnt ihr mir da helfen ? Das würde ich mit einem Interrupt-Eingang machen. > Programmiersprache soll wenn möglich Gcc sein Assembler > beherrsche ich kaum. Für so kritische Timing-Aufgaben wäre zumindest stellenweise Assembler von Vorteil.
Hallo Jan, zum Timing kann ich nicht viel sagen, da ich mit dem Tiny noch nichts gemacht habe und nicht weiß, wie man den takten kann. Aber: 14000 1/min ist eine Ansage. Das sind nur 12 µS um die Motorstellung zu interpolieren und Schließzeit und Zündzeitpunkt aus einem Kennfeld zu berechnen. Zum 32-2-Geberrad: Ich gehe mal davon aus, dass Du ein Geberrad mit 32 Zähnen hast, bei dem 2 aufeinanderfolgende Zähne fehlen. Du musst jetzt die Zeit zwischen zwei gleichen Flanken am Geberrad messen. Ist die Zeit länger (bei gleichmäßigem Motorlauf 3x so lang wie die vorangehende), dann hast Du die Lücke erkannt und kannst die aktuelle Position auf Null setzen. Dein Wunsch von 1° Genauigkeit beim Zünden erfordert, dass Du die jeweilig gemessene Zeit zwischen zwei regulären Zähnen nutzt, um die Kurbelwellenstellung damit zu interpolieren. Ein Problem kann der Verlust der Synchonisation bei hohen Drehzahlgradienten sein. Du musst sicherstellen, dass Du auch im worst case (Start, Motorhochdrehen aus dem Leerlauf) die Lücke im Geberrrad finden kannst. Viel Spass, klingt spannend! Nils
Nachtrag: Ich gehe davon aus, dass Du einen Zweitaktmotor hast! Bei Viertaktmotor solltest Du auch noch die Position der Nockenwelle erfassen, wenn Du nicht doppelt so häufig wie nötig zünden möchtest. Pass auf klopfende Verbrennung auf, Nils
Hallo Rolf erstmal danke für deine Antwort. Um nen glatten Wert zu nennen wäre eine Auflösung des timers von 10mycrosekunden ( hmm wie kriegt man das Zeichen hin) schon ganz praktisch. Das Programm soll so ablaufen Initialisierung Endlosschleife Interrupts auf das Rechtecksignal vom Hallgeber und alle 10 mycrosekunden einer vom Timer. Das Problem mit der Prozessorlast durchs ablaufen des Interrupts hab ich mir schon gedacht. Bei der zweiten Frage ging es mir nicht um die Erkennung der Umdrehung sondern das erkennen der Zahnlücke. Zähne zählen und dann errechnen ? oder gibt es eine Möglichkeit die Zahnlücke selber zu erkennen ( laufzeit des Timers während der Zahnlücke, obwohl diese nicht konstant ist beschleunigung usw). Auch hier tragen die 32 Interrupts des Hallgebers wieder erheblich zu der Prozessorlast bei. Daher war ich auf der Suche nach der Antwort ob der Atmel diese hohe Rechenlast bringt oder ob es irgendeine bessere Möglichkeit der Berechnung gibt.
Es ist ein Viertakt Einzylindermotor. Für erste Tests kann er ruhig einmal in die Ventilüberschneidung zünden. Das mit der klopfenden Verbrennung krieg ich schon in den Griff das ist kein Problem.
> 10mycrosekunden ( hmm wie kriegt man das Zeichen hin) schon AltGr+M. Auf meiner Tastatur steht das auch drauf. Übrigens sind es Mikrosekunden mit "i". > Interrupts auf das Rechtecksignal vom Hallgeber und alle 10 > mycrosekunden einer vom Timer Wie schon gesagt, würde ich den Timer anders verwenden. Wenn ich es richtig verstanden habe, möchtest du, wenn die Lücke vorbeikommt, für eine bestimmte von der Drehzahl und der Kennlinie abhängige Zeit warten und dann zünden. Dazu muß dein Timer aber nicht alle 10 µs einen Interrupt auslösen, sondern eigentlich erst dann, wenn gezündet werden soll. > Bei der zweiten Frage ging es mir nicht um die Erkennung der > Umdrehung sondern das erkennen der Zahnlücke. > oder gibt es eine Möglichkeit die Zahnlücke selber zu erkennen ( > laufzeit des Timers während der Zahnlücke, obwohl diese nicht > konstant ist beschleunigung usw). Die ist zwar nicht konstant, wird sich aber nicht so sprunghaft ändern, oder? > Daher war ich auf der Suche nach der Antwort ob der Atmel diese > hohe Rechenlast bringt Da würde ich sagen: Nein.
Hallo Jan, zu Deiner Frage > Bei der zweiten Frage ging es mir nicht um die Erkennung der Umdrehung > sondern das erkennen der Zahnlücke. Zähne zählen und dann errechnen ? > oder gibt es eine Möglichkeit die Zahnlücke selber zu erkennen > (laufzeit des Timers während der Zahnlücke, obwohl diese nicht konstant > ist beschleunigung usw). hatte ich die Antwort ja schon vorgeschlagen. Zahnzeit messen (Zeit zwischen zwei gleichen Flanken) und die Abweichung (Faktor 3) erkennen. Da ist dann die Lücke. So machen es zumindest alle Motorsteuerungssysteme, die ich kenne. Klar, etwas Hirnschmalz zu hohen Grehzahlgradienten und sonstigen Sonderfällen ist noch erforderlich. Gruß, Nils
Vielen dank für eure hilfreichen Antworten. Eventuell muss ich die Grundstruktur des Programms doch nochmal über den Haufen werfen. Was haltet ihr von der abgeänderten Form ? Initialisieren Endlosschleife Drehzahl über Interrupts erfassen --- > Timer einstellen und bei erreichen des Compare Interrupts Zündung auslösen Verbleibt noch das Problem mit dem Triggerrad, welches bei 32 Interrupts pro Motorumdrehung auslöst. - Hohe Rechenlast - Lokalisierung der Zahnlücke Eine Lösung wäre natürlich ein Triggerrad mit nur einer Zahnflanke auf OT zu nehmen, aber eventuell wäre eine Erweiterung mit einer Erkennung von Motorklopfen über die Winkelgeschwindigkeit der Kurbelwelle denkbar und da wäre es schon sinnvoll gleich mit einem 32/2 Triggerrad anzufangen. Für die Drehzahlerfassung wäre eine Erfassung der Zeit natürlich super. Daher würde man in meiner ersten Idee zwei Fliegen mit einer Klappe schlagen( Zündverzögerung in ms oder µs und die Erfassung der Drehzahl und der Winkelgeschwindigkeit ) Kennt ihr eine Lösung dieses Problems ? Jesses wie machen das denn die Hersteller. mfg Jan
14000/60*32 sind doch gerade mal 7466 Interrupts pro Sec. Bei 20MHz sind das 2876 Clocks per IRQ. Sollte der AVR schaffen. Das Triggerrad würde ich mit dem Input Capture vom 16 Bit Timer vermessen. Der ICF1 IRQ kommt dann halt 7466 mal pro Sec. Zuzüglich 305 Overflow IRQs. Mit dem T0 die Zündung ausgeben. Von der CPU Last her sehe ich keine Probleme. Habe schon ein Steuergerät für nen V8 mit einem Mega8 drin laufen gesehen.
Evtl kannst du dir (wenn nicht schon gemacht) von Megasquirt etwas abkupfern. Das ist ein Open Source Motorsteuergerät. (ich kenn den Algo zur Drehzahlerfassung jetzt nicht, aber die werden wohl ähnliche Probleme haben) Gruß Roland
Wäre es nicht einfacher einen anderen OT-Geber zu wählen der nur 1 Signal bei OT gibt ? Nachrüst Zündungen mit Lichtschranke (Lumination) arbeiten so. Bei 14000 U/min vielleicht keine schlechte Idee. Grüße Michael
Hallo Jan, zunächst mal wirst Du nur 30 Interrupts pro Motorumdrehung auslösen (denn zwei Zähne fehlen ja). Dein ursprüngliches Ziel, auf 1° Kurbelwelle (KW) genau den Zündzeitpunkt (ZZP) einstellen zu können, wirst Du damit nicht erreichen, denn 360°/30(+2) sind ja etwa 11° KW. Das ist viel zu grob für den ZZP, denn hier genügen bei hoher Last nur wenige Grad KW um von optimaler Leistung in den Bereich motorschädigenden Klopfens zu kommen. Nimmst Du an, die Motordrehzahl bliebe während der gesamten Motorumdrehung konstant, würde Dir theoretisch die Information reichen, dass der obere Totpunkt (OT) erreicht ist. Mit einer Zeit (die Du dann aus einem Kennfeld nimmst) nach OT würdest Du die Zündung auslösen. By the way: Welches Signal nimmst Du zur Lasterfassung? Da die Motordrehzahl aber definitiv während eines Arbeitsspieles (2 Umdrehungen KW) nicht konstant ist (Beispiel Kompessionstakt zu Verbennungstakt), machst Du dabei einen nicht unerheblichen Fehler. Nimmst Du diesen Fehler in Kauf, wirst Du den ZZP so sicher (spät) legen müssen, dass von der geplanten Leistungssteigerung nichts mehr bleibt. Dann ist es nur ein schönes Hobbyelektronikprojekt. Wie kommst Du darauf, dass man klopfende Verbrennung über die Winkelgeschwindigkeit KW detektieren kann? Das ist Blödsinn. Normalerweise kommen hier Körperschallsensoren, Drucksensoren oder Ionenstrommessung zum Einsatz. Was machst Du mit der Schließzeit (die Zeit, in der der Primärstrom durch die Zündspule fließt)? Die musst Du auch mit dem µC steuern. Ich will Dir ja nicht den Spaß nehmen, aber so einfach, wie Du Dir das anscheinend vorstellst, ist es nicht ganz. Gruß, Nils.
Hallo ! habe etwas ähnliches gemacht... Im original stand da ein Hako Multifunktionsding mit einem 1 Zylinder 4Takter. Verbaut war eine Magnetzündung mit WastedSpark ohne jegliche Verstellung. Den Unterbrecherkontakt habe ich als Referenz benutzt. Ein ATMega8 hat für mich gerechnet. Ein Zündmodul+Spule aus einem Corsa c14nz haben die Zündenergie Transformiert. Dwelltime der Zündspule habe ich bei const 2ms gehalten. (im Opel zwischen 3-4ms) Erster Versuch: Auslösen der Zündung bei der Bezugsmarke. Funktioniert auf anhieb, nur hat die 2ms-Spätzündung keine hohen Drehzahlen gebracht. Die Abgastemperatur war böse - gleichmassige Leistungsabgabe !!! Aber die Hardware Funktionierte. Danach habe ich per Timer die Zeit zwischen den Impulsen gemessen. Beim zweiten durchlauf konnte ich die Beschleunignung in ms errechnen. Zum letzten gemssenen Wert addiert und man kennt den Zündzeitpunkt. Davon die Dwelltime abgezogen und hier muss mit dem Laden der ZS begonnen werden... ^ --- so dachte ich mir das ! Ging aber nicht. Denn der Motor wird während einer Umdrehung verzögert+beschleunigt, und die nächste verzögert+verzögert. Der ZZP liegt also einmal zu spät, das andere Mal zu früh. Nun habe ich obiges zweimal aufgesetzt und immer zwischen Zählwerk1 und Zählwerk2 nach jeder Umdrehung gewechselt. Nun Funktionierte das ganze. Zwar hatte ich immer noch einen Drift aber der war minimal. Mit der Zündpistole war es nicht mehr zu erkennen, nur der Abgleich mit der tatsächlichen Laufzeit brachte den minimalen Fehler zum vorschein. Du kannst das ganze mit dem Inkrementenrad viel genauer machen... Ich habe nur ein ref-Signal pro Umdrehung auswerten könnten. Da du aber bis kurz vor die Zündung gehen kannst und nur die 11Grad Kw interpolieren musst... ...sollte das ganze entsprechend genauer werden. Leider habe ich von dem Projekt nur noch einen Source der nach modifikation nicht mehr Funktionierte. (habe den Fehler nicht mehr gefunden) Werde die Reste wenn ich sie finde posten. Also lass Dich nciht entmutigen ! Die Probleme die Lösbar...
Hallo Nils Du hast da sehr interessante Einwände, vor allem mein Denkfehler mit der Winkelgeschwindigkeit.( In irgendeiner Weise wird diese aber auch mit der klopfenden Verbrennung in Verbindung gebracht.) Die 1 Grad Genauigkeit funktioniert natürlich nicht mit den Zähnen, hier wird die Zeit benutzt die für eine Umdrehung gebraucht wird + eine zusätzliche Addition mit einer konstanten Ladezeit der Zündspule über den gesamten Drehzahlbereich. Es handelt sich um einen Rennmotor, daher benutze ein zweidimensionales Kennfeld in dem der ZZp nur über die Drehzahl verstellt wird. @ HakoManipulator Sehr interessant, dass sich schonmal jemand mit dem Thema beschäftigt hat. Die Frage ist natürlich ob der Hallgeber auch jeden Zahn mitbekommt. ( bei hohen Drehzahlen). Wieviel machte denn der Unterschied zwischen Arbeitsumdrehung und Gaswechselumdrehung aus ? Ich dachte eventuell einen Mittelwert zu errechnen. Das Megasquirt Projekt hab ich mir auch schonmal angeschaut, allerdings wenn ich ganz ehrlich bin .... nicht verstanden. mfg Jan
MegaSquirt ist schon recht heftig. Aus deren Details ist schon manschmal schwer abzuleiten. (ist auch noch teilweise in Assembler geschrieben) Zum Hallgeber : Bei früheren Kfz wurde im Verteiler Hallgeber mit 4 Blenden benutzt. Damit waren Drehzahlen bis 7.000upm abgedeckt. Von Bosch kenne ich aktuell nur Hallgeber für die Pos.bestim. an der Nw, die sind nur mit so um die 4.500 upm angeben. (erkennt nur Segment) Mittlerweile benutzt man bei uns auch Hallgeber für die Kw. Die gehen dann natürlich bis Max Upm. (bei vielen "Zähnen") Bei "älteren" Systemen benutzt oft Induktivgeber (z.B. Bosch Motronic). (Auswertung des Signalwechsel) Was für einen Hallgeber hast Du verbaut ? Was schafft deiner ? Klopfneigung : Ich würde erstmal so entwickeln das eine Grundlegende Funktion gegeben ist. Danach das Kennfeld mit einbauen. Je nachdem wie gut das ganze werden soll, wäre ein Drehzahl/Zw oder gar ein Drehzahl/Last/Zw Kennfeld sinnvoll. Die Klopfneigung nimmt mit höherer Drehzahl je nach Motor ab. (Gibt Motoren die Klopfen ab 7.000Upm nicht mehr -- hat was mit den Vorreaktionen und der für die klopfende Verbrennung notwendige Zeit zu tun) Detektieren kann man das ganze durch die Druckspitzen im Zylinder bzw state-of-art per Körperschall. Ich weiss was Motorklopfen bedeutet bzw bin auch schon mit Klopfender Verbrennung gefahren. Kann mir nicht vorstellen das man das im Kart hört... Inkrementenrad: Entweder Du detektierst den OT mit einem zweiten Sensor und stimmst so auf die Kw ab (bei dir laube ich eine blöde Idee). (so könntest Du aber WastedSpark vermeiden) Oder Du machst es wie vom Vorredner beschrieben. t von Lücke zu Lücke messen bis fehlender Impuls auftritt. Danach fängst Du an zu Zählen... Jeder Zahn entspricht nun einem bestimmten Kurbelwinkel. Die Zeit von Zahn zu Zahn und die Beschleunigung die dabei Messbar ist lässt schon recht genau auf den Nächsten Zahn schliessen. Bzw auf einen Bruchteil des zurück gelegten Winkel. Quasi Grobes anfahren per Zähne zählen, Punktlandung durch Zeitmessung. (So wird es im übrigen auch gemacht) Vergiss die Plausibelität nicht. Die Lücke kommt immer nach x Zähnen. Somit kannst Du schonmal Fehlercode 0001 definieren -- LostSync ;) Was für eine Endstufe und Zündspule benutzt du ?
Das war schon mod. und lief nicht mehr...
1 | #include "timer.h" |
2 | |
3 | volatile _ign_tab ign_tab; |
4 | |
5 | |
6 | |
7 | |
8 | void timer_init() |
9 | {
|
10 | TCCR2 = (1<<WGM21) | (1<<CS21); // Timer auf 10Khz == 0.0001s == 0.1 ms TBase @ 16Mhz Quarztakt. |
11 | OCR2 = 200; |
12 | TIMSK = (1<<OCIE2); |
13 | |
14 | ign_tab.first_ign = 1; // Wenn der TimerInit -> dann erste Umdrehung |
15 | |
16 | return; |
17 | }
|
18 | |
19 | |
20 | ISR (TIMER2_COMP_vect) |
21 | {
|
22 | if (ign_tab.counter < 65535) ign_tab.counter++; // Laufvariable um die Zeit der Umdrehung zu messen. |
23 | |
24 | |
25 | |
26 | |
27 | // Hier wird die Zündung getriggert, nach dem Laden wird durch das unterbrechen der Zündfunke erzeugt.
|
28 | if (ign_tab.ign == 1) // Soll eine Zündung getriggert werden ? |
29 | {
|
30 | if (ign_tab.ign_timer > 0) // So lange der Timer über 0 ist, wird die Zündspule "geladen". |
31 | {
|
32 | IGNPort &= ~(1<<IGN); // Transistor am µC invertiert 0 == Zündendstufe an ! |
33 | LEDPort |= (1 << LEDrt); // Dabei können wir auch die Kontroll-LED einschalten |
34 | |
35 | ign_tab.ign_timer--; // Timer-dec. nicht vergessen |
36 | } else // Wen der Timer abgelaufen ist, wird unterbochen und somit gezündet. |
37 | {
|
38 | IGNPort |= (1<<IGN); // Endstufe und |
39 | LEDPort &= ~(1<<LEDrt); // LED abschalten. |
40 | |
41 | ign_tab.ign = 0; // Warten auf die nächste Zündung |
42 | }
|
43 | } else |
44 | {
|
45 | IGNPort |= (1<<IGN ); // Wenn kein IgnTrigger da ist, |
46 | LEDPort &=~(1<<LEDrt); // Schalten wir zur Sicherheit ab ! |
47 | }
|
48 | |
49 | |
50 | // Hier wird der Unterbrecherkontakt "entprellt"
|
51 | if (PIND & (1<<PD3)) // Entprellung des Unterbrecherkontakt. Debounce mitzählen. |
52 | {
|
53 | if (ign_tab.breaker_high >= debounce) ign_tab.breaker_high=debounce; |
54 | else ign_tab.breaker_high++; |
55 | } else // bzw. zurücksetzen |
56 | {
|
57 | ign_tab.breaker_high = 0; |
58 | }
|
59 | |
60 | |
61 | // Hier wird der Trigger erzeugt.
|
62 | if (ign_tab.breaker_high == debounce) // Hier wird aus dem Unterbrecherkontakt (debounced) der Trigger bei |
63 | { // Der steigenden Flanke erzeugt. |
64 | if (ign_tab.breaker_last_state == 0) // sollte das nicht andersrum sein ? |
65 | {
|
66 | ign_tab.trigger = 1; |
67 | ign_tab.breaker_last_state = 1; |
68 | }
|
69 | } else |
70 | {
|
71 | ign_tab.breaker_last_state = 0; |
72 | }
|
73 | |
74 | |
75 | // Schauen wir doch mal nach, ob das "Drehzahlsignal" noch aktuell ist.
|
76 | if (ign_tab.counter > low_turn_time) // Wird die nächste Unterbrechung schon Überfällig ? |
77 | {
|
78 | ign_tab.first_ign = 1; // Es ist wieder eine erste Zündung, da wir nicht den Countdown, |
79 | // sondern direkt das UnterbrecherSignal für die Zündung nenutzen müssen.
|
80 | }
|
81 | |
82 | // Bei jedem Trigger wird der Counter bearbeitet und das delta von Umdrehung zu Umdrehung ermittelt
|
83 | if (ign_tab.trigger == 1) |
84 | {
|
85 | |
86 | if ((ign_tab.akt_delta != 1) && (ign_tab.akt_delta != 2)) ign_tab.akt_delta=1; |
87 | if (ign_tab.akt_delta == 1) |
88 | {
|
89 | ign_tab.delta1 = ign_tab.counter - ign_tab.last_counter1; |
90 | ign_tab.last_counter1 = ign_tab.counter; |
91 | |
92 | ign_tab.counter = 0; |
93 | ign_tab.akt_delta = 2; |
94 | |
95 | if (ign_tab.first_ign == 0) // OK, hier wird der countdown gesetzt... |
96 | {
|
97 | ign_tab.countdown = 1; |
98 | ign_tab.countdown_time = ign_tab.last_counter1 + ign_tab.delta1 - dwelltime - ign_offset; |
99 | |
100 | ign_tab.trigger = 0; |
101 | LEDPort |= (1<<LEDge); |
102 | } else // Bei der ersten Zündung machen |
103 | { // wir eine Spätzündung ! |
104 | ign_tab.countdown = 1; |
105 | ign_tab.countdown_time = ign_start_delay; |
106 | |
107 | ign_tab.trigger = 0; |
108 | |
109 | ign_tab.first_ign = 0; |
110 | LEDPort &= ~(1<<LEDge); |
111 | }
|
112 | } else //dann ist es delta2 |
113 | {
|
114 | ign_tab.delta2 = ign_tab.counter - ign_tab.last_counter2; |
115 | ign_tab.last_counter2 = ign_tab.counter; |
116 | |
117 | ign_tab.counter = 0; |
118 | ign_tab.akt_delta = 1; |
119 | |
120 | if (ign_tab.first_ign == 0) // OK, hier wird der countdown gesetzt... |
121 | {
|
122 | ign_tab.countdown = 1; |
123 | |
124 | ign_tab.countdown_time = ign_tab.last_counter2 + ign_tab.delta2 - dwelltime - ign_offset; |
125 | |
126 | ign_tab.trigger = 0; |
127 | LEDPort |= (1<<LEDgn); |
128 | |
129 | |
130 | } else // Bei der ersten Zündung machen |
131 | { // wir eine Spätzündung ! |
132 | ign_tab.countdown = 1; |
133 | ign_tab.countdown_time = ign_start_delay; |
134 | |
135 | ign_tab.trigger = 0; |
136 | |
137 | ign_tab.first_ign = 0; |
138 | LEDPort &= ~(1<<LEDgn); |
139 | }
|
140 | }
|
141 | }
|
142 | |
143 | |
144 | |
145 | |
146 | // Hier wird der Countdown bis zum Laden der Zündspule gezählt...
|
147 | if (ign_tab.countdown_time > 0) // Wenn der Countdown noch runtergezählt wird |
148 | {
|
149 | ign_tab.countdown_time--; // ^-- Tun wir das ! |
150 | } else |
151 | {
|
152 | if (ign_tab.countdown == 1) // Sind wir bei 0 angekommen && noch Aktiv |
153 | {
|
154 | ign_tab.ign = 1; // Initieren wir die Zündung |
155 | ign_tab.ign_timer = dwelltime; // und setzen den Zähler um die Zündspule zu laden |
156 | ign_tab.countdown = 0; // ...und beenden den Countdown |
157 | }
|
158 | }
|
159 | |
160 | return; |
161 | }
|
Interessantes Projekt. Habe was ähnliches mit einem R8C13 gemacht
Also ich rechne jetzt mal ein bisschen 233 /min * 32 = 7456 Interrupts / sek ( ok 2 Zähne fehlen) Ein 16 MHz-AVR führt da rund 2145 Behfehle aus. d.h. die Interrupt-Routine darf im Worst Case keine 2145 AVR-Takte benötigen. (deshalb auch mit 32 Zähnen gerechnet) Vermutlich müssen es sogar noch weniger sein, da die Winkelgeschwindigkeit pro UPM nicht konstant ist. Aber es sollte zu schaffen sein, dass man unter 2000 Takten bleibt. Nun zum eigentlichen Problem. Angenommen du willst bei Winkel X zünden. (ich würde übrigens nicht in echten Grad rechnen, sondern z.B. mit 10 Bit oder mehr Auflösung) also 0 = 0 Grad 512 = 180 Grad 1024 = 360 Grad Sei X also eine Zahl zwischen 0 und 1023 Die Zähne liegen somit 1024 / 32 = 32 Schritte auseinander. Die oberen 5 Bit von X geben dir also schon mal direkt den Zahn an. Die unteren musst du dann über die Winkelgeschwindigkeit interpolieren, hierzu brauchst du einen Timer. Angenommen du nimmst den 16 Bit Timer mit Prescaler / 8. Dann hast 0,5 µS Auflösun bei 16 MHz. Der Timer läuft dann aber alle 32 ms über d.h. zwischen 2 Zähnen dürfen keine 32 ms vergehen. -> 1 Umdrehung pro Sekunde muss der Motor schaffen. Wie oben schon erwähnt, bestimmst du duch die oberen 5 Bit von X deinen Zahn. Bist du einen Zahn davor, so liest du den Timerwert aus und berechnest aus den unteren 5 Bit von X wie weit der Timer beim nächsten Zahn zählen muss und schreibst den Wert ins OCR-Register, welcher dann den Interrupt für die Zündung auslöst: OCR = TCNTR * ( X & 0x1F) / 32 Da wir nicht mit "echten" Grad sondern mit 10 Bit rechnen ist die Division (da 2er Potzenz) praktisch kostenlos, die Multiplikation auf neueren AVR's auch in wenigen Takten abgewickelt. Und wie schon von HakoManipulator angedeutet, nicht zu viel Aufwand in die OT-Erkennung investieren, die fehlenden Zähne kommen immer nach 30 Interrupts, wenn man die Zahnlücke einmal erkannt hat. Ob und wie du die Klopferkennung über die Winkelgeschwindikeit machen kannst, weiß ich allerdings nicht. Ich denke aber, dass du erkennen kannst, ob du einen WasteSpark gemacht hast und den Prozi dann kurz darauf synchronisieren kannst und nur noch jedes zweite Mal zündest, dann hast mehr Zeit um die Zündspule zu laden. Gruß Roland
Es gibt mehrer "arten" von Klopfender Verbrennung. Es gibt da etwas das nennt sich Zündverzug. Der Funke an der Kerze entzündet im besten fall das homogene Gemisch. Da die Flammfront "nur" mit ein paar Meter pro Sekunde (je nach Gemisch und Brennraumform) dauert es eine kurze weile bis der Maximaldruck (= komplette Verbennung) stattgefunden hat. Deshalb die Frühzündung. Bei standard Wald-und-Wiesen Motoren sind das im Leerlauf so ca 10°Kw v OT. Dieser Wert ist nun abhängig von der Drehzahl, Last, Zündenergie, Lambda, Brennraumform, Verwirbelung/Drall, Betriebstemperatur, ... und hat starke auswirkungen auf Spez.Kraftstoffverbrauch, Leistung, Spitzentemperaturen, Abgaswerte... Wenn Du es gerne richtig extrem hat, empfehle ich dir noch einen EGT. Dann kannst Du anhand der Abgastemperatur bis an die Kotzgrenze des Motors gehen. (Kurzbevor du ein "loch" im Kolben hast -- das ist übrigens nur eine Redewendung die Schäden sehen meist anders aus) Nun zum Klopfen: Viel zu frühe Zündung überlastet den Kurbeltrieb. Da reisst dann gerne mal der Ölfilm in den Lagerstellen und an der Zylinderwand. Sorgte für mächtig Reibung und hohen Temperaturen. Versaut dir die Leistung, da die Kinematische Energie vom Kurbeltrieb erstmal gegen die Gaskraft arbeiten muß. (Quasi ein "rückdreher" muss überwunden werden) Es kann aber auch sein das durch die Frühzündung der Motor Thermisch auf ein Niveau kommt, bei dem sich unabhängig von Deiner Zündung Flammnester bilden. (Kraftstoff entzündet sich an heissen Teilen oder Rückständen) Ab gewissen Drehzahlen kann man das nicht mehr hören und je nach stärke braucht es nicht lange bis der Motor ernsthafte Schäden nimmt. Dabei enstehen starke Druckwellen im Zylinder mit kurzzeitigen Peaks. Bei einer normalen Verbrennung hat man einen weichen Druckanstieg. Bei längerem Klopfen kann man auf den Kolben und ev, dem Metallring der Kopfdichtung sogar kleine Krater erkennen... Spätestens wenn dein Kolbenboden Alu-farben schimmert, weisst Du bescheid ...der sollte schon dunkel sein ;) Erkennen kann man diese (kurzzeitigen-) Druckspitzen nur: -Akustisch/Körperschall -- Klopfsensor (ein "umgebautes" PiezoMikrofon) -Die Ionenstrommessung -- bei der durch das Ionisiert Gas quasi die Leitfähigkeit gemssen wird (man erkennt die Dichteschwankungen) - Drucksensoren (tut weh, Sensor in den Verbrennungsraum bringen der so ca 40-70 bar aushält und die Flammfront ist dann auch mal so 2500°C warm) schliesse ich mal für den Rennbetrieb aus. Der Kurbeltrieb erfährt durch diese Peaks keine nennenswerte Beschleunigung, da es sich nicht um den "real" wirksamen mittleren Innendruck handelt sondern nur um eine partielle Druckschwankung. Interessanterweise gibt es einen Effekt durch den bei hohen Drehzahlen sich die Klopfneigung vermindert. Die Jungs von MegaSquirt haben einen extra Controller für die Auswertung des Klopfsensors verwendet.. Aber bis jetzt haben wir nur über den Normalbetrieb geredet. Anlassen/Anziehen Zündung muss Spät verstellen. Ein Rückschlagen der Kw hat sogar schon Beine beschädigt... Ich müsste mal suchen was da noch für "Sonderfälle" existieren... Wegen Rolands Rechnerei. Das hört sich doch schon recht brauchbar an. Nur mit dem Timer bin ich nicht einverstanden. Da muss noch die Dwelltime für die Zündspule mit rein... Die übrigens Bordnetzspannungsbezogen konstant gehalten wird. (Die Spule braucht immer gleich lange um kurz vor die Sättigung zu kommen...) Ich würde auch erstmal die detektion von dem Wasted aussen vor lassen. Lerne erstmal laufen... Löse am besten erstmal das Problem mit der Lücke und Sync. Zum Prüfen kannst Du wunderbar einfach mit einer LED auf Deine OT-Markierung "blitzen". - dann eine Abfrage bei welchem Zahn er steht - die Zeit von Zahn zu Zahn messen. - die Änderungsrate/Zahn errechnen - Darüber erkennst Du dann den Ansaugen/Verdichten Hub, und kannst den Timer für den nächsten Spark auslösen... - Dann kannst Du den Code für das Kennfeld einbauen. und immer wieder Prüfen ! Die Drehzahl zum Kennfled auslesen würde ich für jede Umdrehung neu berechnen, nicht von Zahn zu Zahn. Wieviel Stützstellen willst Du verwenden ? Ich würde vielleicht noch versuchen ein Drosselklappenpoti oder Saugrohrdrucksensor zur Lasterfassung zu verbauen. Vielleicht kommen mir noch ein paar ideen...
Hi Leutz Sorry das ich mich erst jetzt wieder zurückmelde^^. Die Arbeit nimmt mich gerade sehr in Beschlag. Vielen dank für eure Anregungen. Ich habe auf jedenfall vor das Projekt auch zu Ende zu bringen und werde euch regelmäßig berichten. Hab aber noch eine Frage Hacko Manipulator nutzt deine Timer noch einen zusätzlichen trigger für einen Unterbrecherkontakt ? Wollte eigentlich eine ruhende Zündung bauen. Roland Praml: 16bit timer mit prescaler 8 auf auflösung von 0,5 µs. Da müsste ich ja dann OCRx auf 20 setzen geht das denn von der Cpu Last. Wie kommt man auf die 2145 befehle bei 16 mhz ? mfg Jan
16000000 / 7456 = 2145 Den Timer setzt du auf 0 wenn der richtige Zahn vorbei kommt und berechnest wie lange du nun noch warten musst und setzt den Wert ins OCRx-Register, dann wird der Timerint pro Umdrehung genau einmal aufgerufen. Hier geht es im Wesentlichen darum, eine stabile Verzögerung hinzubekommen. (Allerdings muss im Vorfeld ja noch die dwelltime berücksichtigt werden, damit die Spule 'optimal voll' ist)
Jepp, da ich nur eine Bezugsmarke hatte habe ich es einfacher ghabt als Du. Ich musste nur die Zeit durchzählen. Also sowas wie LadeZeitPunkt = Umlaufzeit - Frühzündung - Dwelltime. Wenn der Ladezeitpunkt kommt, wird die Zündendstufe angesteuert und somit der Strom durch die Spule aufgebaut. Durch das abschalten wird die Spannung induziert... Allerdings musst Du deine Berechnung mit jedem neuen Zahn der kommt abgleichen. Das ist deine einzigste Schwierigkeit. Ruhend ist bei deinem SetUp kein Problem, einfach Klemme 4 auf die Zündkerze legen. Allerdings begrenzt der WastedSpark deine Frühzündung. (Zünden in den Ansaugtakt ist blöd !) Aber auch das lässt sich lösen ;)
Hi ! Warum nicht einfach einen Hallsensor mit 2 Magneten auf der KW . Die Magneten sollten unterschiedliche Stärke haben , so ist auch ein Fenster erkennbar , da der Hallsensor unterschiedliche Signalstärken abgeben wird . Beim 2 Takter allemal ausreichend , zumal man die unterschiedlichen Signalstärken auch zur Drehrichtungserkennung nutzen kann , 2 Takter springen auch gern mal entgegengesetzt an , zumindest bei Modellflugmotoren ist es so , wenn der Schwung über OT zu zaghaft war .^^ Der notwendige Rechenaufwand sollte sich dabei in Grenzen halten .
Hallo, die Sache interessiert mich ebenfalls sehr, da ich etwas ähnliches vorhabe. Seid ihr da noch dran? Macht da noch einer was? Was ist daraus geworden, läuft das GoKart damit? Gruß Manni
Das ganze Thema ist nicht so ganz ohne. In der Autoindustrie werden die Zähne gezählt, also ein Timer wird durch den Hallsensor hochgezählt (beim AVR T0 z.B.). Ein Overflow-Int dieses Zählers wird bei Erreichen der max. Zähnezahl ausgelöst. In diesem Interrupt wird ein zweiter Zähler gestartet, der die Umlaufzeit, also die Zeit zwischen zwei Interrupts des ersten Timers mittels ICP misst (Drehzahlerkennung). Nun kann der zweite Timer beim gewünschten Zündzeitpunkt einen Overflow-INT (OCR mit Wert aus Kennfeld-Tabelle beschreiben)auslösen und zünden. Das Ganze kann für beliebig viele Zylinder wiederholt werden. Es empfiehlt sich, das Ganze immer eine Umdrehung voraus zu berechnen (1 Umdrehung später zünden), um die Zündspule (wie schon gesagt) optimal laden zu können, bzw. dadurch die Zündspannung beeinflussen zu können. Wie gesagt, nicht ganz einfach, da die Timer des AVRs mehrfach genutzt werden müssen (Tiny ist eher ungeeignet), Taktfrequenz min. 16MHz. Die meiste Arbeit macht die Aufnahme des Kennfeldes über verschiedene Leistungsabgaben. Die OT-Erkennung (Lücke im Zahnrad) wird bei abnehmendem Drehzahlgradienten gemacht, also bei größer werdendem Zählerstand des zweiten Timers für einen Umlauf (beim 'vom Gas gehen', wenn keine Leistung gefordert wird). Beim PkW werden sogar die Beschleunigungszeiten (Durchlaufgeschwindigkeiten der zugehörigen Zähne zum jeweiligen Zylinder) gemessen, um Rückschlüsse auf die Verdichtung der einzelnen Zylinder zu bekommen. Ich hoffe, man kann meinen Ausführungen halbwegs Folgen, darüber gibt es ganze Bücher zu lesen. ;-)
Interessantes Thema. Thilo M. schrieb: > Die OT-Erkennung (Lücke im Zahnrad) wird bei > abnehmendem Drehzahlgradienten gemacht, also bei größer werdendem > Zählerstand des zweiten Timers für einen Umlauf (beim 'vom Gas gehen', > wenn keine Leistung gefordert wird). ?? Das verstehe ich auch nicht. Wenn die Zahnlücke da ist, dann kann ich sie erkennen und habe den OT. Warum soll das nur bei abnehmender Drehzahl gemacht werden? Thilo M. schrieb: > Beim PkW werden sogar die Beschleunigungszeiten > (Durchlaufgeschwindigkeiten der zugehörigen Zähne zum jeweiligen > Zylinder) gemessen, um Rückschlüsse auf die Verdichtung der einzelnen > Zylinder zu bekommen. a) Du willst sagen, dass die Kurbelwelle Drehzahlschwankungen unterliegt, die von der Verdichtung herrühren? Ich glaub ich hab das falsch verstanden. b) Was hilft es mir, wenn ich die Verdichtung kenne? Wird dann der Zündzeitpunkt noch etwas verschoben? Vor allem ist solch eine Messung genau genug? Wenn der Motor nicht total ausgelutscht ist, dann sollte die Verdichtung doch einigermaßen identisch sein.
900ss D. schrieb: > ?? Das verstehe ich auch nicht. Wenn die Zahnlücke da ist, dann kann ich > sie erkennen und habe den OT. Warum soll das nur bei abnehmender > Drehzahl gemacht werden? Das wird auch nicht überall so gemacht. Die Erkennung der Lücke ist nicht immer notwendig, sie dient nur zur Synchronisation. Da beim 'vom Gas gehen' keine Zündung und keine Einspritzung benötigt wird, steht der Timer eher zur Verfügung. Diese Methode macht den ganzen Ablauf etwas weniger zeitkritisch und man vermeidet eventuelle Fehler. Hat der µC genügend Rechenleistung wird man die Erkennung mit Sicherheit bei jeder Umdrehung machen. 900ss D. schrieb: > a) Du willst sagen, dass die Kurbelwelle Drehzahlschwankungen > unterliegt, die von der Verdichtung herrühren? Ich glaub ich hab das > falsch verstanden. Nein, das hast du schon richtig verstanden. Bei der Zündung des Zylinders wird der Kolben nach unten beschleunigt, die Geschwindigkeit nimmt ungefähr bis zur Mitte des Weges zu, dann wieder ab. Durch Messen der Durchlaufzeiten der zuhörigen Zähne kann man Rückschlüsse auf den Zustand des Zylinders gewinnen. Dieser Effekt wird in Werkstätten zur Motordiagnose verwendet, hat weniger mit der Motorsteuerung zu tun.
Thilo M. schrieb: > Das wird auch nicht überall so gemacht. Die Erkennung der Lücke ist > nicht immer notwendig, sie dient nur zur Synchronisation. Da beim 'vom > Gas gehen' keine Zündung und keine Einspritzung benötigt wird, steht der > Timer eher zur Verfügung. Diese Methode macht den ganzen Ablauf etwas > weniger zeitkritisch und man vermeidet eventuelle Fehler. > Hat der µC genügend Rechenleistung wird man die Erkennung mit Sicherheit > bei jeder Umdrehung machen. OK, so leuchtet mir das ein. > 900ss D. schrieb: >> a) Du willst sagen, dass die Kurbelwelle Drehzahlschwankungen >> unterliegt, die von der Verdichtung herrühren? Ich glaub ich hab das >> falsch verstanden. > > Nein, das hast du schon richtig verstanden. Bei der Zündung des > Zylinders wird der Kolben nach unten beschleunigt, die Geschwindigkeit > nimmt ungefähr bis zur Mitte des Weges zu, dann wieder ab. Durch Messen > der Durchlaufzeiten der zuhörigen Zähne kann man Rückschlüsse auf den > Zustand des Zylinders gewinnen. Dieser Effekt wird in Werkstätten zur > Motordiagnose verwendet, hat weniger mit der Motorsteuerung zu tun. Sehr interessant das alles. Danke für die Infos.
ich habe mir die Sache etwa so vorgestellt: 1 Zyl Viertakter, Hall-Sensor auf der Nockenwelle, 1 Impuls pro Nockenwellenumdrehung im OT. (oder ca. 5-10° vor OT, entsprechend der Spätzündung der Orginalzündung), Kickstarter ! d.h. besondere Startprozedur Beim Starten wird die Zündspule beim 1. Erreichen des OT geladen und ca. 3 ms später gezündet. Zwar ist das dann etwas zu spät, macht bei Startdrehzahl max. 100/min aber nur ca. 2° aus - beim Starten unerheblich. Das bleibt so, bis der Motor läuft, dann wird gerechnet. Etwa so, wie das Hakomanipulator weiter oben beschrieben hat. Das Problem wird sein, daß die Sache dann beim Beschleunigen, vor allem bei kleiner Schwungmasse ungenau wird, auch wenn man eine Korrektur einrechnet. Beim Verzögern ist das m.E. unerheblich. Eine Alternative wäre ein 2. Impuls vom Hallgeber, so etwa 45° Nockenwelle = 90° Kurbelwelle vor OT, also etwa Mitte Verdichtungshub. Das würde die Sache dann wesentlich genauer machen. Mann könnte als Sensor auch eine Lichtschranke mit rotierender Blendenöffnung von 45° verwenden und die ON/OFF Zeitpunkte auswerten. Was meint Ihr dazu ? Wie ist euere Erfahrung mit der Störsicherheit der AVRs? Bei den älteren AT90S1200 oder S2313 war die nicht besonders! Jetzt denke ich an den ATmega88, da passen auch mehrere Kennlinien rein.
Manfred Häfner schrieb: > Wie ist euere Erfahrung mit der Störsicherheit der AVRs? Bei den älteren > AT90S1200 oder S2313 war die nicht besonders! Ist auch bei den Neueren nicht besonders. Grundregel: was wenig Strom aufnimmt (wo wenig Strom fließt) ist anfällig gegen äußere Einflüsse. Dort sind Schutzmaßnahmen nötig.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.