I've created a sketch which takes the output from the 36-1 trigger wheel simulator and detects the missing pulse and after a delay fires a 2ms pulse to the coil packs, one being 180 degrees after the first.
The position of the trigger wheel sensor is 90 degrees before TDC, to spark with an advance of 10 degrees BTDC, there needs to be a delay of 80 degrees before triggering the spark
I've used the mega as it has more that one 16 bit timer - one timer for cylinders 1&4 the other for cylinders 2&3. On the version shown below, I've not used a map table of advance vs RPM - that is my next step - I've just used a pot to enable me to adjust the timing and visualise the output on a scope
Again I've lifted most of the code from Nick Gammon and because I've modified it, I'd appreciate any input
// read squarewave on pin 2 and calc ignition timing
//
#include <digitalWriteFast.h>
const byte interruptPin = 2;
const byte SPARKPLUG_1_4 = 10;
const byte SPARKPLUG_2_3 = 11;
// volatile byte state = LOW;
volatile unsigned long timeSinceMissingTooth = 0;
volatile unsigned long timeToFire = 0;
volatile unsigned long toothGap = 0;
volatile unsigned long lastTime = 0;
volatile unsigned long lastGap = 0 ;
volatile byte missingTooth = 0 ;
volatile float timePerDegree = 0;
byte signalToothOffSet = 90; // in degrees - the sensor being fitted 90 degrees before TDC
byte defaultAdvance = 10; // in degrees
// float frequency = 0;
volatile unsigned int sparkDelayTime_1_4 = 10; // microseconds
volatile unsigned int sparkDelayTime_2_3 = 10; // microseconds
volatile unsigned int sparkOnTime = 2000; // microseconds
// allow for time taken to enter ISR (determine empirically)
const unsigned int isrDelayFactor = 200; // microseconds
// is spark currently on?
volatile boolean sparkOn_1_4;
volatile boolean sparkOn_2_3;
void setup()
{
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_missing_Tooth, FALLING);
noInterrupts(); // disable all interrupts
TCCR1A = 0; // Timer 1 normal mode
TCCR1B = 0; // Timer 1 stop timer
TIMSK1 = 0; // Timer 1 cancel timer interrupt
TCCR3A = 0; // Timer 3 normal mode
TCCR3B = 0; // Timer 3 stop timer
TIMSK3 = 0; // Timer 3 cancel timer interrupt
interrupts(); // enable all interrupts
pinMode (SPARKPLUG_1_4, OUTPUT);
pinMode (SPARKPLUG_2_3, OUTPUT);
}
void loop()
{
defaultAdvance = map(analogRead(A0), 0, 1023, 0, 45);
if (missingTooth = 1) {
// if timesincemissing tooth eq or greater than ignition and off set
// fire sparkplug
timeToFire = (signalToothOffSet - defaultAdvance) * timePerDegree;
if (timeSinceMissingTooth >= timeToFire) {
timeSinceMissingTooth = 0;
// fire 1,4 sparkplugs
sparkDelayTime_1_4 = timeToFire;
timeToFire = (signalToothOffSet - defaultAdvance + 180) * timePerDegree;
sparkDelayTime_2_3 = timeToFire;
fireSparkPlugs_1_4(); // fire now on cylinders 1 and 4
fireSparkPlugs_2_3(); // fire now on cylinders 2 and 3
}
timePerDegree = lastGap / 10; // lastGap period covers 10 degrees
// frequency = 1/((timePerDegree / 1000000) * 360 ) * 60; /// need to rename this RPM
missingTooth = 0 ;
}
}
void ISR_missing_Tooth() {
toothGap = micros() - lastTime;
if (toothGap > 1.8 * lastGap) {
// missing tooth detected
timeSinceMissingTooth = micros();
missingTooth = 1;
}
lastGap = toothGap;
lastTime = micros();
}
void fireSparkPlugs_1_4() // pass parameter of offset time
{
sparkOn_1_4 = false; // make sure flag off just in case
// set up Timer 1
noInterrupts();
TCCR1A = 0; // normal mode
TCNT1 = 0; // count back to zero
TCCR1B = bit(WGM12) | bit(CS11); // CTC, scale to clock / 8
// time before timer fires - zero relative
// multiply by two because we are on a prescaler of 8
OCR1A = (sparkDelayTime_1_4 * 2) - (isrDelayFactor * 2) - 1;
TIMSK1 = bit (OCIE1A); // interrupt on Compare A Match
interrupts();
}
// interrupt for when time to turn spark on then off again
ISR (TIMER1_COMPA_vect)
{
// if currently on, turn off
if (sparkOn_1_4)
{
digitalWriteFast (SPARKPLUG_1_4, LOW); // spark off
TCCR1B = 0; // stop timer
TIMSK1 = 0; // cancel timer interrupt
}
else
// hold-off time must be up
{
digitalWriteFast (SPARKPLUG_1_4, HIGH); // spark on
TCCR1B = 0; // stop timer
TCNT1 = 0; // count back to zero
TCCR1B = bit(WGM12) | bit(CS11); // CTC, scale to clock / 8
// time before timer fires (zero relative)
// multiply by two because we are on a prescaler of 8
OCR1A = (sparkOnTime * 2) - (isrDelayFactor * 2) - 1;
}
sparkOn_1_4 = !sparkOn_1_4; // toggle
} // end of TIMER1_COMPA_vect
//////////////////////////////////////////////////////////////////////////////////
void fireSparkPlugs_2_3() // pass parameter of offset time
{
sparkOn_2_3 = false; // make sure flag off just in case
// set up Timer 3
noInterrupts();
TCCR3A = 0; // normal mode
TCNT3 = 0; // count back to zero
TCCR3B = bit(WGM32) | bit(CS31); // CTC, scale to clock / 8
// time before timer fires - zero relative
// multiply by two because we are on a prescaler of 8
OCR3A = (sparkDelayTime_2_3 * 2) - (isrDelayFactor * 2) - 1;
TIMSK3 = bit (OCIE3A); // interrupt on Compare A Match
interrupts();
}
// interrupt for when time to turn spark on then off again
ISR (TIMER3_COMPA_vect)
{
// if currently on, turn off
if (sparkOn_2_3)
{
digitalWriteFast (SPARKPLUG_2_3, LOW); // spark off
TCCR3B = 0; // stop timer
TIMSK3 = 0; // cancel timer interrupt
}
else
// hold-off time must be up
{
digitalWriteFast (SPARKPLUG_2_3, HIGH); // spark on
TCCR3B = 0; // stop timer
TCNT3 = 0; // count back to zero
TCCR3B = bit(WGM32) | bit(CS31); // CTC, scale to clock / 8
// time before timer fires (zero relative)
// multiply by two because we are on a prescaler of 8
OCR3A = (sparkOnTime * 2) - (isrDelayFactor * 2) - 1;
}
sparkOn_2_3 = !sparkOn_2_3; // toggle
} // end of TIMER3_COMPA_vect
I've seen comments that an Arduino is not up to the job of ignition control but as this engine was designed for clockwork ignition, it doesn't need or respond to timing to the fractions of a degree
Once running (or not) I'll keep you updated on my progress
Thanks in advance