Forum: Fahrzeugelektronik Moped-Zündung mit Arduino


von Robert S. (efyzz)


Lesenswert?

Nabend,

das Thema Zündung wurde hier zwar schon oft diskutiert, jedoch geht's 
meist eher um die Hardware. Ich habe jedoch Probleme mit der 
Zündzeitpunkt-Berechnung und konnte bisher keinen passenden Beispielcode 
finden.

Der Arduino Nano soll per Interrupt0 an D2 auf einen Hallsensor 
reagieren, der einmal pro Umdrehung getriggert wird. Verzögert (mit 
konstantem Winkel) soll dann die Zündung auslösen auf D3. Die Zeit 
zwischen zwei Triggern wird per micros() gemessen und entsprechend dem 
vorgegeben ZZP (vorerst als Konstante) die benötigte Verzögerung 
berechnet (IgnDelay). Mit delayMicroseconds() wird die berechnete Zeit 
gewartet und dann auf D3 der Zündpuls ausgegeben.

Ich habe das einerseits mit einer rotierenden Winkelscheibe getestet, an 
der ein Target für den Hallsensor angebracht ist und eine LED über der 
Winkelskala, die über D3 angesteuert wird, sodass die Scheibe quasi 
"abgeblitzt" wird. Bei einigen Drehzahlbereichen funktioniert das super 
(stehendes Bild auf der Skala), in anderen Bereichen kommen jedoch wirre 
Werte raus.

Also habe ich einen zweiten Arduino als Signalgenerator benutzt, um die 
Hallsensor-Pulse zu simulieren. Die berechneten Werte des ersten Arduino 
schaue ich mir dann auf der Konsole an. Auch hier ist zu erkennen, dass 
die berechnete Drehzahl in manchen Bereichen schwankt und 
interessanterweise auch die Pausendauer, die mit delayMicroseconds() 
generiert wird.

Es macht den Eindruck, als würde einfach zu viel Zeit in der ISR 
verbracht werden, sodass irgendwas überläuft. Da aber eigentlich das 
ganze Programm nur aus der ISR besteht, dürfte das eigentlich nicht 
kritisch sein?!

Die ISR wird beispielsweise bei 3000 rpm alle 20 ms aufgerufen. Das 
Delay vor dem Zündimpuls hat dann aber gerade mal ca. 1500 us, also 
nicht mal 1/10. Wenn ich die Pausendauer durch einen festen Wert 
ersetze, stelle ich fest, dass es ab etwa 1000 us zu Problemen kommt.

Hier der Sourcecode:
1
const int ZZP = 30; // Standard ZZP in Grad bei Drehzahl 0.
2
int Pickup = 0; // Pin2
3
int IgnOut = 3; // Pin3
4
unsigned long Timestamp0 = 0;
5
unsigned long Timestamp1 = 0;
6
unsigned long Timestamp2 = 0;
7
unsigned long Timestamp3 = 0;
8
unsigned long TimeDiff = 0;
9
unsigned long IgnDelay = 0;
10
int Drehzahl = 0;
11
12
void setup() {
13
 
14
  Serial.begin(9600);
15
  pinMode(IgnOut, OUTPUT);
16
  pinMode(Pickup, INPUT_PULLUP);
17
  attachInterrupt(Pickup, InterruptFunction, FALLING);
18
}
19
 
20
void loop() {
21
22
  while(true){
23
      Serial.print("TimeDiff: ");
24
      Serial.print(TimeDiff);
25
      Serial.print("   Drehzahl: ");
26
      Serial.print(Drehzahl);
27
      Serial.print("   Timestamp2: ");
28
      Serial.print(Timestamp2);
29
      Serial.print("   Timestamp3: ");
30
      Serial.print(Timestamp3);
31
      Serial.print("   IgnDelay: ");
32
      Serial.println(IgnDelay);
33
34
      delay(1000);
35
36
  }  
37
}
38
 
39
void InterruptFunction() {
40
  Timestamp1 = Timestamp0;
41
  Timestamp0 = micros();
42
  TimeDiff = (Timestamp0 - Timestamp1);
43
  Drehzahl = 60000000 / TimeDiff;
44
45
  IgnDelay = TimeDiff * ZZP / 360;
46
47
  Timestamp2 = micros() - Timestamp0; // for debug only
48
  
49
  delayMicroseconds(IgnDelay);
50
51
  Timestamp3 = micros() - Timestamp0; // for debug only
52
  
53
  digitalWrite(IgnOut, HIGH);
54
  delayMicroseconds(20);
55
  digitalWrite(IgnOut, LOW);
56
}

Die Ausgabe auf der Konsole sieht beispielsweise so aus:


TimeDiff: 17416   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 512 
IgnDelay: 1451
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451
TimeDiff: 18440   Drehzahl: 3253   Timestamp2: 80   Timestamp3: 1620 
IgnDelay: 1536
TimeDiff: 17416   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 512 
IgnDelay: 1451
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451
TimeDiff: 18436   Drehzahl: 3254   Timestamp2: 84   Timestamp3: 600 
IgnDelay: 1451
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451
TimeDiff: 18440   Drehzahl: 3253   Timestamp2: 80   Timestamp3: 1620 
IgnDelay: 1536
TimeDiff: 18440   Drehzahl: 3253   Timestamp2: 80   Timestamp3: 1620 
IgnDelay: 1536
TimeDiff: 17416   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 512 
IgnDelay: 1451
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451
TimeDiff: 18436   Drehzahl: 3254   Timestamp2: 84   Timestamp3: 1624 
IgnDelay: 1536
TimeDiff: 17420   Drehzahl: 3444   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1452
TimeDiff: 17416   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 512 
IgnDelay: 1451
TimeDiff: 18440   Drehzahl: 3253   Timestamp2: 84   Timestamp3: 1624 
IgnDelay: 1536
TimeDiff: 18440   Drehzahl: 3253   Timestamp2: 84   Timestamp3: 1620 
IgnDelay: 1536
TimeDiff: 18436   Drehzahl: 3254   Timestamp2: 84   Timestamp3: 1624 
IgnDelay: 1536
TimeDiff: 17416   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 1536 
IgnDelay: 1536
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451
TimeDiff: 17412   Drehzahl: 3445   Timestamp2: 84   Timestamp3: 516 
IgnDelay: 1451

Die Drehzahl von ca. 3253 wäre korrekt, bei 3445 ist etwas schief 
gegangen. Das ist auch daran zu erkennen, dass bis zu TimeStamp3 viel zu 
wenig Zeit vergangen ist. Etwa 1500 us wären hier korrekt, so wie es in 
IgnDelay auch immer korrekt berechnet wird.

Nur die Ausführung von delayMicroseconds() scheint manchmal 
"überzulaufen", was dann auch zu einem falschen TimeDiff führt. Wie 
gesagt treten keine Fehlmessungen auf, wenn ich für delayMicroseconds() 
eine Konstante unter 1000 nehme.

Ich habe auch schon versucht, nur noch die Timestamps in der ISR zu 
setzen und alles Andere in der main zu machen, führte aber zum selben 
Ergebnis. Auch ein deaktivieren aller Interrupts mit cli() am Anfang und 
sei() am Ende der ISR nützt nichts. Ebenso habe ich delayMicroseconds 
durch eine eigene Routine mit For-Schleife ersetzt, trotzdem kein 
Unterschied im Verhalten.

Und jetzt danke für eure Hinweise!

: Verschoben durch User
von Robert S. (efyzz)


Lesenswert?

Lösung gefunden! Nachdem ich nun den ganzen Tag gesucht habe ...

Während der ISR wird der Überlauf des Timers, der für micros() verwendet 
wird, nicht detektiert, da der dafür zuständige Interrupt dann 
deaktiviert ist. Ein sei() am Anfang der ISR führt endlich zu korrekten 
Timings :)

von Istan (Gast)


Lesenswert?

Das ist nicht dein einziges Problem.

Die ISR ist zu lang und dann kommt auch noch ein unzuverlässiges Delay 
darin vor.

NOGO!

Der Code ist Murks!

von H.Joachim S. (crazyhorse)


Lesenswert?

Istan schrieb:
> Der Code ist Murks!

Jo.
Nutze die OutputCompare-Register für Beginn Ladung Zündspule und Zündung 
selbst.

von Robert S. (efyzz)


Lesenswert?

Istan schrieb:
> Der Code ist Murks!

Da kann ich erstmal nicht widersprechen ;)

Könnt ihr mir mal grob skizzieren, was in der ISR zu tun ist (vermutlich 
nur den Timer lesen) und wie ich das dann in der main verarbeite? Woher 
weiß die main, dass ein Interrupt aufgetreten ist? Dass könnte man ja 
nur pollen ... und wie kriegt man dann noch präzises Timing hin?

H.Joachim S. schrieb:
> Nutze die OutputCompare-Register für Beginn Ladung Zündspule und Zündung
> selbst.

Hast Du dafür mal ein Beispiel? Und wie gehe ich mit Überlauf der Timer 
um? Bei langsamen Drehzahlen kann zwischen zwei Pulsen schon mal mehr 
als eine Sekunde liegen.

Zündspule laden brauch ich nicht. Ist eine Kondensatorzündung, da muss 
nur der Thyristor getriggert werden.

von Istan (Gast)


Lesenswert?

Atmega Handbuch studieren.


Eigentlich benötigst Du nur ein retriggerbares Monoflop.
Das geht auch in Hardware?!

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Schraubst Du einfach Auspuff ab und montierst Du großen SLS-SRB,
schon hast Du schnellstens Mopped im Dorf.

von Robert S. (efyzz)


Lesenswert?

Moin,

ok, nach einer schlaflosen Nacht habe ich nun eine grobe Vorstellung:

Die ISR misst die Zeit für eine Umdrehung und berechnet die Zeit bis zur 
Zündung (wie bisher auch). Damit wird ein Compare-Timer aufgezogen, der 
dann seinen Interrupt auslöst und darin wird gezündet. Das macht Sinn 
oder?

Bleibt die Frage nach dem Überlauf des Timers ...

Und spricht etwas dagegen, zur Zeitmessung (für die Drehzahlermittlung) 
weiterhin micros() zu verwenden? Oder gibt's da auch noch irgendwelche 
Schweinereien?

Istan schrieb:
> Eigentlich benötigst Du nur ein retriggerbares Monoflop.
> Das geht auch in Hardware?!

Naja, dann kann ich bei der Original-Zündung bleiben. Es geht ja 
letztlich darum, drehzahlabhängige Zündzeitpunkte zu konfigurieren.

Ben B. schrieb:
> Schraubst Du einfach Auspuff ab und montierst Du großen SLS-SRB,
> schon hast Du schnellstens Mopped im Dorf.

Keine Angst, hab ich schon längst. Aber mit Feststoffboostern kommt eher 
schwierig durch den TÜV.

von H.Joachim S. (crazyhorse)


Lesenswert?

Robert S. schrieb:
> Bei langsamen Drehzahlen kann zwischen zwei Pulsen schon mal mehr
> als eine Sekunde liegen.

Ist das ein Lanz?
Aber nehmen wir ruhig mal die 1s.
ATMega mit 16MHz, 16bit-Timer mit 62,5kHz clk: >1s Laufzeit, Auflösung 
16µs. Wenn das reicht, brauchst du dich um den Überlauf gar nicht 
kümmern.
2 Möglichkeiten:
ICP setzt den Zähler zurück, berechnet OCR für die Zündung aus dem 
Messwert. Es tritt niemals ein Overflow auf (bzw. wenn der kommt, steht 
der Motor).

Noch besser: gar nicht am Zählerstand manipulieren, also durchlaufen 
lassen und mit Differenzen arbeiten. Dann stört der OV auch nicht.

Beispiel: Sensor auf OT (oder irgendwo anders, völlig egal, Hauptsache 
bekannt). Du bildest nun einfach die Differenz zwischen dem letzten und 
dem aktuellen ICP-Wert.
alt: 4000, neu 8000 -> Differenz 4000
alt: 65000, neu 3465 (also mit Überlauf), liefert mit 
unsigned-Subtraktion ebenfalls 4000, spielt also keine Rolle.
Genaus so geht es mit der Zündzeitpunkt berechnung: OCR auf aktuellen 
ICP + x setzen (x=2000 wären bei der gemessenen Geschwindigkeit also 
180°). Passt auch ohne Berücksichtigung EINES evtl. zwischenzeitlichen 
Überlaufs. Berücksichtigen musst du also nur, wenn der Zähler zweimal 
überläuft. Kommt aber bei 62,5kHz Takt nicht vor.

von Robert S. (efyzz)


Lesenswert?

Mahlzeit,

ah danke, mit den Erläuterungen kann ich arbeiten :) Ich fang dann mal 
an zu fummeln ...

H.Joachim S. schrieb:
> Ist das ein Lanz?

Nee, aber wenn man den Kickstarter nur streichelt ... Eine Fehlzündung 
wäre dann doof. Das kann dann schon mal weh tun im Fuß.

H.Joachim S. schrieb:
> Auflösung 16µs

Das wären dann beispielsweise bei 10.000 rpm noch 0,96 °. Müsste 
reichen.

von Thomas (kosmos)


Lesenswert?

Du brauchst denn Zündzeitpunkt und den Schließwinkel bzw. Schließzeit 
also 2 Interrupts oder muss diese eine Interrupt Routine immer 
umkonfigurieren bzw. ein Bit setzen damit du dann auf "ein"  oder "aus" 
verzweigst.

von H.Joachim S. (crazyhorse)


Lesenswert?

Ne, steht oben. Kondensatorzündung. Es gibt weder Schliesswinkel noch 
Ladezeit.

von Robert S. (efyzz)


Lesenswert?

ES FUNKTIONIERT! :) :) :)

Und zwar wie erwartet bis runter auf etwa 57 rpm.

Hier der Code:
1
const int ZZP = 30; // Standard ZZP in Grad bei Drehzahl 0.
2
int Advance = 0; // ZZP Verschiebung
3
const int CalcCorrection = 0;
4
int IgnOut = 3; // Pin3
5
int Timestamp1 = 0;
6
7
unsigned long TimeDiff = 0;
8
unsigned long IgnDelay = 0;
9
int Drehzahl = 0;
10
 
11
void setup() {
12
 
13
  Serial.begin(9600);
14
  pinMode(IgnOut, OUTPUT);
15
  initTimer();
16
}
17
 
18
void loop() {
19
20
  while(true){
21
      Serial.print("TimeDiff: ");
22
      Serial.print(TimeDiff);
23
      Serial.print("  Drehzahl: ");
24
      Serial.print(Drehzahl);
25
      Serial.print("  Timestamp1: ");
26
      Serial.print(Timestamp1);
27
      Serial.print("  IgnDelay: ");
28
      Serial.println(IgnDelay);
29
30
      delay(1000);
31
32
  }  
33
}
34
35
36
 void initTimer(void) { 
37
38
 // Input Capture setup
39
40
  TCCR1A = 0;
41
  TCCR1B = (1<<CS12);
42
  TCCR1C = 0;
43
  
44
  // Interrupt setup
45
  // ICIE1: Input capture 
46
  // OCIEA: Timer1 compare A
47
  TIFR1 = (1<<ICF1) | (1<<OCF1A);    // clear pending
48
  TIMSK1 = (1<<ICIE1) | (1<<OCIE1A); // and enable
49
50
  // Set up the Input Capture pin, ICP1, which corresponds to Arduino D8
51
  pinMode(8, INPUT);
52
  digitalWrite(8, 1);     // enable pullup
53
}
54
55
56
// Interrupt capture handler
57
//
58
ISR(TIMER1_CAPT_vect) {
59
60
  TimeDiff = (ICR1 - Timestamp1);
61
  Timestamp1 = ICR1;
62
63
  IgnDelay = TimeDiff * (ZZP-Advance) / 360 - CalcCorrection; 
64
65
  OCR1A = IgnDelay + ICR1;
66
67
  Drehzahl = 3750000 / TimeDiff;
68
69
70
}
71
72
// Interrupt compare handler
73
//
74
ISR(TIMER1_COMPA_vect) {
75
  digitalWrite(IgnOut, HIGH);
76
  digitalWrite(LED_BUILTIN, HIGH);
77
  delayMicroseconds(20);
78
  digitalWrite(IgnOut, LOW);
79
  digitalWrite(LED_BUILTIN, LOW);
80
}

Das einzige, wo ich mich noch unwohl fühle, sind die Datentypen für 
TimeDiff und IgnDelay. Aber so funktioniert zumindest die Berechnung:

IgnDelay = TimeDiff * (ZZP-Advance) / 360 - CalcCorrection;


Aber ich vermute, da könnte man noch eleganterweise den ein oder anderen 
Typecast einbauen?!

Sonst noch Verbesserungsvorschläge?

Nochmals vielen Dank!

von H.Joachim S. (crazyhorse)


Lesenswert?

Robert S. schrieb:
> int Timestamp1 = 0;

das müsste dir eigentlich um die Ohren fliegen, muss unsigned int sein.

von H.Joachim S. (crazyhorse)


Lesenswert?

Die 20µs delay kannst du auch noch raussschmeissen. Macht in deinem Fall 
zwar wahrscheinlich nichts, ist aber trotzdem bäh in einer ISR. Immerhin 
rund 300 Takte, in denen der MC komplett blockiert ist - gar nicht erst 
angewöhnen. So ein vermeidbarer Kram holt einen irgendwann immer ein.

Und es gibt für weitere Verbesserungen auch noch die Möglichkeit, dass 
ein OCR-Ereignis direkt auf einen Pin wirkt (set, clear, toggle) ohne 
Zutun der Software. Vermeidet Latenzen/Jitter, falls sich der MC gerade 
in einer anderen ISR+delay befindet :-)

ISR(TIMER1_CAPT_vect) {

  TimeDiff = (ICR1 - Timestamp1);
  Timestamp1 = ICR1;

  IgnDelay = TimeDiff * (ZZP-Advance) / 360 - CalcCorrection;

  OCR1A = IgnDelay + ICR1;
  OCR1B=OCR1A+PULS_LENGTH;
}

ISR(TIMER1_COMPA_vect) {
  digitalWrite(IgnOut, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(IgnOut, LOW);
  digitalWrite(LED_BUILTIN, LOW);
}

von Robert S. (efyzz)


Lesenswert?

Danke für Tipps, bin begeistert!
Werde das einbauen ...

H.Joachim S. schrieb:
> int Timestamp1 = 0;
>
> das müsste dir eigentlich um die Ohren fliegen, muss unsigned int sein.

Habe ich geändert. Ging aber trotzdem, vermutlich wegen 
Zweierkomplement-Subtraktion?!

Außerdem führe ich die Berechnungen in Grad jetzt als float durch, damit 
auch kleinere Werte als 1° verwendet werden können und damit die 
Berechnung von IgnDelay genauer wird. Hatte zuerst Angst, dass die 
Berechnung mit float zu langsam wird, aber es scheint problemlos zu 
gehen.

Kannst Du vielleicht nochmal drüber schauen, ob die Datentypen so alle 
Sinn machen?
1
const float ZZP = 36.3; // Standard ZZP in Grad bei Drehzahl 0.
2
float Advance = 0.0; // ZZP Verschiebung
3
const int CalcCorrection = 7;
4
const int IgnOut = 3; // Pin3
5
unsigned int Timestamp1 = 0;
6
7
unsigned long TimeDiff = 0;
8
unsigned int IgnDelay = 0;
9
int Drehzahl = 0;
10
11
...
12
13
ISR(TIMER1_CAPT_vect) {
14
15
  TimeDiff = ICR1 - Timestamp1;
16
  Timestamp1 = ICR1;
17
  
18
  IgnDelay = int(TimeDiff * (ZZP-Advance) / 360.0) - CalcCorrection; 
19
20
  OCR1A = IgnDelay + ICR1;
21
22
  Drehzahl = 3750000 / TimeDiff; 
23
}

Wenn ich Deine Tipps von oben befolge, kann ich vermutlich auch das 
CalcCorrection raus schmeißen, das ich in praktischen Versuchen mit 7 
ermittelt habe. :)

von Philipp G. (geiserp01)


Lesenswert?

Ich würde die ganzen Delays rausschmeissen und stattdessen mit der cpu 
time arbeiten.

von H.Joachim S. (crazyhorse)


Lesenswert?

float bringt dir nicht viel, du bekommst den Messsignal mit 16µs 
Auflösung und kannst auch Zeitpunkte nur in eben dieser Quantelung 
ausgeben, also nur Ganzzahlen.

1000 Rpm -> Messwert 3750, ZZP 36,3° -> float-Ergebnis 378,125, also 378 
für OCR.
Kannst genausogut 3750*363/3600 in Ganzzahl rechnen.
Einen Vorteil hätte float: wenn du vor der int-Umwandlung noch 0.5 
addierst bekommst du eine Rundung, sonst nur stumpf den Ganzzahlteil.

edit: wenn der Motor einmal läuft, kannst du auch auf 250kHz Takt 
umschalten, damit bist du dann bei 4µs Auflösung (Mindestdrehzahl 230 
rpm)

: Bearbeitet durch User
von Robert S. (efyzz)


Lesenswert?

Moin,

H.Joachim S. schrieb:
> Kannst genausogut 3750*363/3600 in Ganzzahl rechnen.

Ja richtig, das hatte ich sogar kurzzeitig so implementiert. Dann muss 
man als "Anwender" halt nur wissen, dass man alles in 1/10 Grad 
eintragen muss.

H.Joachim S. schrieb:
> Einen Vorteil hätte float: wenn du vor der int-Umwandlung noch 0.5
> addierst bekommst du eine Rundung, sonst nur stumpf den Ganzzahlteil.

Jo, ist mir auch aufgefallen. Eigentlich wäre mir der Ganzzahlteil sogar 
lieber, als im Zweifelsfall eine Aufrundung. Lieber ein bisschen zu früh 
als zu spät zünden ;)

Von daher werde ich wohl zu der Lösung mit 1/10 Grad zurück gehen.

H.Joachim S. schrieb:
> wenn der Motor einmal läuft, kannst du auch auf 250kHz Takt
> umschalten

Au ja! Es kommen nach und nach immer bessere Ideen :)
Allerdings wäre die eine Zündung, in der der Teiler umgeschaltet wird, 
dann falsch. Schließlich muss erst die Drehzahl berechnet und erst dann 
entschieden werden, ob der Teiler umgeschaltet wird. In der Zeit ist der 
Timer ja schon wieder weiter ... Oder hast Du dafür womöglich auch noch 
eine elegante Lösung?

Nochmals besten Dank!

von H.Joachim S. (crazyhorse)


Lesenswert?

Das geht ohne nennenswerte Fehler/grob daneben liegenden Zündfunken. 
Aber da kannst du dir selbst Gedanken machen, ist nicht schwer :-)

Du hast an anderer Stelle viel grössere Fehler: die Kurbelwellendrehung 
ist trotz Schwungmasse nicht gleichförmig, sondern hat ständige 
Beschleunigungs- und Bremsphasen, abhängig von Zylinderzahl, Hubraum, 2 
oder 4Takt, Schwungmasse, Last und sicher noch ein paar andere.
Das ist auch der Grund, warum ausser in Einfachstmotoren der 
Kurbelwellensensor eine viel bessere Position der Kurbelwelle liefert, 
besonders häufig das 60-2 Polrad, also alle 6° einen Impuls, die 2 
fehlenden Zähne für die OT-Erkennung. Das machen die nicht zum Spass 
:-), sondern weil eben eine Messung pro Umdrehung nicht ausreicht, dem 
Rechner ein halbwegs reales Abbild der Kurbelwellenposition zu liefern.

von Robert S. (efyzz)


Lesenswert?

Stimmt allerdings ...

Na gut, denn nochmals vielen Dank! Habe jetzt zumindest mal eine solide 
Basis :)

von Thomas (kosmos)


Lesenswert?

mich würden mal ein paar Bilder von dem ganzen interessieren, kann mir 
die Verkabelung mit einem Arduino gar nicht vorstellen.

von npn (Gast)


Lesenswert?

H.Joachim S. schrieb:
> abhängig von Zylinderzahl, Hubraum, 2 oder 4Takt

Dann rate ich mal:
6 Zylinder, 5 Liter Hubraum, 4-Takt

müsste doch passen für ein Moped, oder? ;-)

Robert S. schrieb:
> Moped-Zündung mit Arduino

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.