Hello.
I am building an electronic ignition system for my VW aircooled beetle engine with carburator. I have tried it on my wasted spark coilpack and it seems to work. Read my attached report. Could anyone please take a look at my code and give me some feedback on improvements and ideas to make it more realiable?
Edit: The last uppdated code is further down in this thread!
The breadboard demonstration is here:- YouTube
#include <Avr/interrupt.h>
#include <Avr/io.h>
//Pin definitions:
const byte HallPin1 = 2; // Pin nr 2 is conected to Hall sensor DO
const byte HallPin2 = 3; // Pin nr 3 is also conected to Hall sensor DO
const int Ign1Pin = 8; // (PORTB,0)
const int Ign2Pin = 11; // (PORTB,3)
volatile byte milliseconds; // The millisecondcounter value.
volatile unsigned int cranktime; // Time from 3 degrees to where the coil should start to load.
volatile unsigned int cranktimeStart; // Variable to measure real cranktime.
volatile unsigned int cranktimeStop; // Variable to measure real cranktime.
volatile unsigned int realcranktime; // Measured real cranktime.
volatile byte IgnSystem; // Statusword for active ign system.
volatile byte dwellTime; // The time the coil should charge (default is 0,004 seconds.
// RPM variables:
volatile byte half_revolutions;
volatile unsigned int rpm;
volatile unsigned int timeold;
/************************************/
void setup() {
dwellTime = 3; // Runningdwell: 3ms. (Crankingdwell: 4ms.)
half_revolutions = 0;
rpm = 0;
timeold = 0;
IgnSystem = 0; // No ignition system is active.
pinMode(Ign1Pin, OUTPUT); // Initialize the Ignition 1 pin as an output.
pinMode(Ign2Pin, OUTPUT); // Initialize the Ignition 2 pin as an output.
bitClear(PORTB, 3); // (digitalWrite(Ign2Pin, LOW);) Turn the ignition off in case it's on
bitClear(PORTB, 0); // (digitalWrite(Ign2Pin, LOW);) Turn the ignition off in case it's
attachInterrupt(digitalPinToInterrupt(HallPin1), SensorOn, RISING); //Hall sensor DO for Ignition 1
attachInterrupt(digitalPinToInterrupt(HallPin2), SensorOff, FALLING); //Hall sensor DO for Ignition 2
/*************** Setup timer2******************/
noInterrupts();
TCCR2A = 0; // Turn off Control register for waveform generation
TCCR2B = 0; // Turn off noise cancelling, turn off edge select, waveform gen mode 0, no clock source
TCCR2A |= (1 << WGM21); // Turn on CTC mode (so it will start again) automatically
TIMSK2 |= (1 << OCIE2A); // Set interrupt on compare match.
OCR2A = 249; // ((0, 001 / 0.0000000625) / 64 ) - 1; //(0,001s=249)
TCNT2 = 0; // Reset timer counter to 0
milliseconds = 0; // Reset the ms counter variable.
interrupts();
}
//===============
/* The interrupt action for magnet 1: The Timer starts to count up 1 ms at a time.
***************/
void SensorOn () {
if ((rpm < 300) & (IgnSystem == 0)) { // When cranking (starting), the coil nr 2 will charge at once.
bitSet(PORTB, 3); //Turn on coil 1 charging immediately, Cranking dwell will then be 1ms longer than normal.
IgnSystem = 2; // Statusword to know witch system is to be hot.
}
if ((rpm >= 300) & (IgnSystem == 2) ) { // When running (not starting), the coil nr 1 will charge after cranktime in the ISR below.
IgnSystem = 1; //Statusword to know witch system is to be hot.
}
TCCR2B |= (1 << CS22); // Load 64 prescaler / And this starts the timer2!
cranktimeStart = micros(); // For monitoring.
/********* RPM calculations: **********/
half_revolutions++; //For the RPM calculations
if (half_revolutions >= 2) {
rpm = 60 * 1000000 / (micros() - timeold) * half_revolutions;
timeold = micros();
half_revolutions = 0;
realcranktime = (cranktimeStop - cranktimeStart);
}
}
/*================
The interrupt action for magnet 2: The Timer starts to count up 1 ms at a time.
********************/
void SensorOff () {
if ((rpm < 300) & (IgnSystem == 0)) { // When cranking (starting), the coil nr 1 will charge at once.
bitSet(PORTB, 0); //Turn on coil 2 charging immediately, Cranking dwell will then be 1ms longer than normal.
IgnSystem = 1; //Statusword to know witch system is to be hot.
}
if ((rpm >= 300) & (IgnSystem == 1) ) { // When running (not starting), the coil nr 2 will charge after cranktime in the ISR below.
IgnSystem = 2; //Statusword to know witch system is to be hot.
}
TCCR2B |= (1 << CS22); // Load 64 prescaler / And this starts the timer2!
cranktimeStart = micros(); //For diagnostics
/********* RPM calculations: **********/
half_revolutions++; //For the RPM calculations
if (half_revolutions >= 2) {
rpm = 60 * 1000000 / (micros() - timeold) * half_revolutions;
timeold = micros();
half_revolutions = 0;
realcranktime = (cranktimeStop - cranktimeStart);
}
}
/*====================
The Interrupt Service Routine for Timer2 that will be executed each time the timer reach the compare match register (1ms).
*********Milliseconds***********/
ISR(TIMER2_COMPA_vect) {
/*********Counting milliseconds******************/
milliseconds++; // Increases the variable "milliseconds" by 1 at each ms (every time the ISR is executed).
/************ coil charging**********/
if (milliseconds >= cranktime) { //When the timer reaches the cranktime, then do this:
if (IgnSystem == 1) { //If ignitionsystem 1 is selected and not on, then:
bitSet(PORTB, 0); //Turn on coil 1 charging.
} if (IgnSystem == 2) { //If ignitionsystem 2 is selected and not on, then:
bitSet(PORTB, 3); //Turn on coil 2 charging.
}
cranktimeStop = micros(); //Stop recording the crank time
}
/***********Discharge coilspark********/
//If the milliseconds has reached the cranktime and dwelltime, then:
if (milliseconds >= (cranktime + dwellTime)) {
milliseconds = 0; // reset the ms counter variable
//Turn off timer.
TCCR2B &= ~ (1 << CS22); //clear the prescaler .
TCNT2 = 0; // Reset the timer count to 0
bitClear(PORTB, 0); //Stop charging coil 1. (Gives spark)
bitClear(PORTB, 3); //Stop charging coil 2. (Gives spark)
}
// If the engine has stopped or are still cranking, the IgnSystem is set to starting advance degrees.
if (rpm < 300) {
IgnSystem = 0;
}
}
/****************************************************/
void loop() {
//Calculate the cranktime dependent on the rpm. (cranktime= advance time - dwellTime)
/********Cranktime calculations ***
RPM Advance Degrees Cranktime Time change
-degrees BTDC from Sensor for each RPM (ms)
300 -3 180 100 -100
400 9 171 71,25 -0,2875
600 8 172 47,77777778 -0,117361111
1000 7 173 28,83333333 -0,047361111
1700 17 163 15,98039216 -0,018361345
2800 26 154 9,166666667 -0,006194296
3100 28 152 8,172043011 -0,003315412
4000 29 151 6,291666667 -0,002089307
4100 0 180 7,317073171 0,010254065
*/
if (rpm <= 300) {
cranktime = 0;
} if ((rpm > 300) && (rpm <= 400)) {
cranktime = (100 - (rpm - 300) * 0.288) - dwellTime;
} if ((rpm > 400) && (rpm <= 600)) {
cranktime = (71.25 - (rpm - 400) * 0.117) - dwellTime;
} if ((rpm > 600) && (rpm <= 1000)) {
cranktime = (47.778 - (rpm - 600) * 0.047) - dwellTime;
} if ((rpm > 1000) && (rpm <= 1700)) {
cranktime = (28.833 - (rpm - 1000) * 0.018) - dwellTime;
} if ((rpm > 1700) && (rpm <= 2800)) {
cranktime = (15.980 - (rpm - 1700) * 0.006) - dwellTime;
} if ((rpm > 2800) && (rpm <= 3100)) {
cranktime = (9.167 - (rpm - 2800) * 0.003) - dwellTime;
} if ((rpm > 3100) && (rpm <= 4000)) {
cranktime = (8.172 - (rpm - 3100) * 0.002) - dwellTime;
}
}
Anders Arduino EIS 151204.pdf (599 KB)
Arduino_EIS_151202.ino (9.35 KB)