Forum: Compiler & IDEs Einzylinderzündung mit dem Avr


von Jan (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Nils (Gast)


Lesenswert?

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

von Nils (Gast)


Lesenswert?

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

von Jan (Gast)


Lesenswert?

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.

von Jan (Gast)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Nils (Gast)


Lesenswert?

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

von Jan (Gast)


Lesenswert?

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

von Tim (Gast)


Lesenswert?

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.

von Roland P. (pram)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

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

von Nils (Gast)


Lesenswert?

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.

von HakoManipulator (Gast)


Lesenswert?

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...

von Jan (Gast)


Lesenswert?

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

von HakoManipulator (Gast)


Lesenswert?

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 ?

von HakoManipulator (Gast)


Lesenswert?

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
}

von Klippi (Gast)


Lesenswert?

Interessantes Projekt. Habe was ähnliches mit einem R8C13 gemacht

von Roland P. (pram)


Lesenswert?

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

von HakoManipulator (Gast)


Lesenswert?

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...

von Jan (Gast)


Lesenswert?

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

von Roland P. (pram)


Lesenswert?

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)

von HakoManipulator (Gast)


Lesenswert?

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 ;)

von Old-Man (Gast)


Lesenswert?

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 .

von Manfred H. (mhelectronics)


Lesenswert?

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

von Thilo M. (Gast)


Lesenswert?

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. ;-)

von 900ss (900ss)


Lesenswert?

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.

von Thilo M. (Gast)


Lesenswert?

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.

von 900ss (900ss)


Lesenswert?

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.

von Manfred H. (mhelectronics)


Lesenswert?

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.

von Thilo M. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.