diff --git a/decoders.ino b/decoders.ino index 42e454a..e598306 100644 --- a/decoders.ino +++ b/decoders.ino @@ -1191,4 +1191,102 @@ int getCrankAngle_MazdaAU(int timePerDegree) return crankAngle; } +/* +Name: Non-360 Dual wheel +Desc: 2 wheels located either both on the crank or with the primary on the crank and the secondary on the cam. +Note: There can be no missing teeth on the primary wheel +*/ +void triggerSetup_non360() +{ + triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth + toothCurrentCount = 255; //Default value + triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise + triggerSecFilterTime = (int)(1000000 / (MAX_RPM / 60 * 2)) / 2; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + secondDerivEnabled = false; + decoderIsSequential = true; + MAX_STALL_TIME = (3333UL * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) +} + + +void triggerPri_non360() +{ + curTime = micros(); + curGap = curTime - toothLastToothTime; + if ( curGap < triggerFilterTime ) { return; } //Pulses should never be less than triggerFilterTime, so if they are it means a false trigger. + toothCurrentCount++; //Increment the tooth counter + addToothLogEntry(curGap); + + toothLastMinusOneToothTime = toothLastToothTime; + toothLastToothTime = curTime; + + if ( !currentStatus.hasSync ) { return; } + + if ( toothCurrentCount == 1 || toothCurrentCount > configPage2.triggerTeeth ) + { + toothCurrentCount = 1; + toothOneMinusOneTime = toothOneTime; + toothOneTime = curTime; + startRevolutions++; //Counter + //if ((startRevolutions & 63) == 1) { currentStatus.hasSync = false; } //Every 64 revolutions, force a resync with the cam + } + + setFilter(curGap); //Recalc the new filter value + + +} + +void triggerSec_non360() +{ + curTime2 = micros(); + curGap2 = curTime2 - toothLastSecToothTime; + if ( curGap2 < triggerSecFilterTime ) { return; } + toothLastSecToothTime = curTime2; + + if(!currentStatus.hasSync) + { + toothCurrentCount = 0; + + toothLastToothTime = micros(); + toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage2.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place + + currentStatus.hasSync = true; + } +} + +int getRPM_non360() +{ + if( !currentStatus.hasSync || toothCurrentCount == 0 ) { return 0; } + if(currentStatus.RPM < configPage2.crankRPM) { return crankingGetRPM(configPage2.triggerTeeth); } + return stdGetRPM(); +} + +int getCrankAngle_non360(int timePerDegree) +{ + //This is the current angle ATDC the engine is at. This is the last known position based on what tooth was last 'seen'. It is only accurate to the resolution of the trigger wheel (Eg 36-1 is 10 degrees) + unsigned long tempToothLastToothTime; + int tempToothCurrentCount; + //Grab some variables that are used in the trigger code and assign them to temp variables. + noInterrupts(); + tempToothCurrentCount = toothCurrentCount; + tempToothLastToothTime = toothLastToothTime; + interrupts(); + + //Handle case where the secondary tooth was the last one seen + if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage2.triggerTeeth; } + + int crankAngle = (tempToothCurrentCount - 1) * triggerToothAngle + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth. + //Estimate the number of degrees travelled since the last tooth} + long elapsedTime = micros() - tempToothLastToothTime; + if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime + else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } + + + if (crankAngle >= 720) { crankAngle -= 720; } + if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } + if (crankAngle < 0) { crankAngle += 360; } + + return crankAngle; +} + + diff --git a/reference/speeduino.ini b/reference/speeduino.ini index fcfd16f..d6e60f0 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -234,14 +234,14 @@ page = 4 TrigAng = scalar, S16, 0, "Deg", 1, 0, -360, 360, 0 FixAng = scalar, U08, 2, "Deg", 1, 0, 0, 80, 0 CrankAng = scalar, U08, 3, "Deg", 1, 0, -10, 80, 0 - IgHold = scalar, U08, 4, "", 1, 0, 0, 100, 0 + TrigAngMul = scalar, U08, 4, "", 1, 0, 0, 100, 0 ; Multiplier for tooth counts that don't evenly divide into 360 TrigEdge = bits, U08, 5[0:0], "Leading", "Trailing" TrigSpeed = bits, U08, 5[1:1], "Crank Speed", "Cam Speed" IgInv = bits, U08, 5[2:2], "Going Low", "Going High" oddfire = bits, U08, 5[3:3], "No", "Yes" - TrigPattern= bits, U08, 5[4:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" - IdleAdv = scalar, U08, 6, "Deg", 0.352,-28.4, -10, 80, 0 - IdleAdvTPS = scalar, U08, 7, "ADC", 1, 0, 0, 255, 0 + TrigPattern= bits, U08, 5[4:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "INVALID", "INVALID", "INVALID", "INVALID" + unused4-6 = scalar, U08, 6, "Deg", 0.352,-28.4, -10, 80, 0 + unused4-7 = scalar, U08, 7, "ADC", 1, 0, 0, 255, 0 IdleAdvRPM = scalar, U08, 8, "RPM", 100, 0, 0, 1200, 0 #if CELSIUS IdleAdvCLT = scalar, U08, 9, "C", 1, -40, -40, 102, 1 @@ -625,6 +625,7 @@ menuDialog = main TrigSpeed = "Primary trigger speed." onetwo = "Number of Missing teeth on Primary Wheel." TrigAng = "The Angle ATDC when tooth No:1 on the primary wheel passes the primary sensor." + TrigAngMul = "A multiplier used by non-360 degree tooth wheels (i.e. Wheels where the tooth count doesn't divide evenly into 360. Usage: (360 * ) / tooth_count = Whole number StgCycles = "The number of revolutions that will be skipped during cranking before the injectors and coils are fired." TrigEdge = "The Trigger edge of the primary sensor.\nLeading.\nTrailing." TrigFilter = "Tuning of the trigger filter algorithm. The more aggressive the setting, the more noise will be removed, however this increases the chance of some true readings being filtered out (False positive). Medium is safe for most setups. Only select 'Aggressive' if no other options are working" @@ -824,10 +825,11 @@ menuDialog = main dialog = triggerSettings,"Trigger Settings",4 topicHelp = "http://speeduino.com/wiki/index.php/Decoders" field = "Trigger Pattern", TrigPattern - field = "Primary base teeth", numteeth, { TrigPattern == 0 || TrigPattern == 2 } + field = "Primary base teeth", numteeth, { TrigPattern == 0 || TrigPattern == 2 || TrigPattern == 11 } field = "Primary trigger speed", TrigSpeed, { TrigPattern == 0 } field = "Missing teeth", onetwo, { TrigPattern == 0 } field = "Secondary teeth", onetwo, { TrigPattern == 2 } + field = "Trigger angle multiplier", TrigAngMul, { TrigPattern == 11 } field = "Trigger Angle ", TrigAng field = "This number represents the angle ATDC when " field = "tooth #1 passes the primary sensor." diff --git a/speeduino.ino b/speeduino.ino index 4259e13..4d78e2c 100644 --- a/speeduino.ino +++ b/speeduino.ino @@ -424,6 +424,17 @@ void setup() else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_MazdaAU, FALLING); break; + + case 11: + triggerSetup_non360(); + trigger = triggerPri_non360; + getRPM = getRPM_non360; + getCrankAngle = getCrankAngle_non360; + + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) + else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to + attachInterrupt(triggerInterrupt2, triggerSec_non360, FALLING); + break; default: trigger = triggerPri_missingTooth;