Fully working scheduler (With 2 schedules), initial crank timing work.
This commit is contained in:
parent
feff0b244d
commit
1537249958
|
@ -11,8 +11,10 @@ Need to calculate the req_fuel figure here, preferably in pre-processor macro
|
||||||
#define engineInjectorSize 100 // In cc/min
|
#define engineInjectorSize 100 // In cc/min
|
||||||
#define engineStoich 14.7 // Stoichiometric ratio of fuel used
|
#define engineStoich 14.7 // Stoichiometric ratio of fuel used
|
||||||
#define engineStrokes 4 //Can be 2 stroke or 4 stroke, any other value will cause problems
|
#define engineStrokes 4 //Can be 2 stroke or 4 stroke, any other value will cause problems
|
||||||
|
#define engineDwell 3000 //The spark dwell time in uS
|
||||||
#define triggerTeeth 12 //The full count of teeth on the trigger wheel if there were no gaps
|
#define triggerTeeth 12 //The full count of teeth on the trigger wheel if there were no gaps
|
||||||
#define triggerMissingTeeth 1 //The size of the tooth gap (ie number of missing teeth)
|
#define triggerMissingTeeth 1 //The size of the tooth gap (ie number of missing teeth)
|
||||||
|
#define triggerAngle 110 // The angle (Degrees) from TDC that No 1 cylinder is at when tooth #1 passes the sensor
|
||||||
|
|
||||||
//The following lines are configurable, but the defaults are probably pretty good for most applications
|
//The following lines are configurable, but the defaults are probably pretty good for most applications
|
||||||
#define engineInjectorDeadTime 1.5 //Time in ms that the injector takes to open
|
#define engineInjectorDeadTime 1.5 //Time in ms that the injector takes to open
|
||||||
|
@ -24,8 +26,6 @@ Need to calculate the req_fuel figure here, preferably in pre-processor macro
|
||||||
#include "testing.h"
|
#include "testing.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
|
||||||
//#include "TimerThree.h" //Enable this when switching to Mega
|
|
||||||
#include "TimerOne.h" //Enable this when using Leo based test board
|
|
||||||
|
|
||||||
//
|
//
|
||||||
float req_fuel = ((engineCapacity / engineInjectorSize) / engineCylinders / engineStoich) * 100; // This doesn't seem quite correct, but I can't find why. It will be close enough to start an engine
|
float req_fuel = ((engineCapacity / engineInjectorSize) / engineCylinders / engineStoich) * 100; // This doesn't seem quite correct, but I can't find why. It will be close enough to start an engine
|
||||||
|
@ -47,11 +47,14 @@ volatile unsigned long toothLastMinusOneToothTime = 0; //The time (micros()) tha
|
||||||
|
|
||||||
int rpm = 0; //Stores the last recorded RPM value
|
int rpm = 0; //Stores the last recorded RPM value
|
||||||
struct table fuelTable;
|
struct table fuelTable;
|
||||||
|
struct table ignitionTable;
|
||||||
|
|
||||||
unsigned long injectTime[engineCylinders]; //The system time in uS that each injector needs to next fire at
|
unsigned long injectTime[engineCylinders]; //The system time in uS that each injector needs to next fire at
|
||||||
boolean intjectorNeedsFire[engineCylinders]; //Whether each injector needs to fire or not
|
boolean intjectorNeedsFire[engineCylinders]; //Whether each injector needs to fire or not
|
||||||
|
|
||||||
unsigned long counter;
|
unsigned long counter;
|
||||||
|
unsigned long scheduleStart;
|
||||||
|
unsigned long scheduleEnd;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
|
||||||
|
@ -80,6 +83,7 @@ void setup() {
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
|
|
||||||
dummyFuelTable(&fuelTable);
|
dummyFuelTable(&fuelTable);
|
||||||
|
dummyIgnitionTable(&ignitionTable);
|
||||||
initialiseScheduler();
|
initialiseScheduler();
|
||||||
counter = 0;
|
counter = 0;
|
||||||
}
|
}
|
||||||
|
@ -102,12 +106,25 @@ void loop()
|
||||||
//Get the current MAP value
|
//Get the current MAP value
|
||||||
int MAP = 20; //Placeholder
|
int MAP = 20; //Placeholder
|
||||||
|
|
||||||
|
//Begin the fuel calculation
|
||||||
//Perform lookup into fuel map for RPM vs MAP value
|
//Perform lookup into fuel map for RPM vs MAP value
|
||||||
int VE = getTableValue(fuelTable, MAP, rpm);
|
int VE = getTableValue(fuelTable, MAP, rpm);
|
||||||
|
//Calculate an injector pulsewidth form the VE
|
||||||
//From all of the above, calculate an injector pulsewidth
|
|
||||||
int pulseWidth = PW(req_fuel, VE, MAP, 100, engineInjectorDeadTime); //The 100 here is just a placeholder for any enrichment factors (Cold start, acceleration etc). To add 10% extra fuel, this would be 110
|
int pulseWidth = PW(req_fuel, VE, MAP, 100, engineInjectorDeadTime); //The 100 here is just a placeholder for any enrichment factors (Cold start, acceleration etc). To add 10% extra fuel, this would be 110
|
||||||
|
|
||||||
|
//Perform a lookup to get the desired ignition advance
|
||||||
|
int advance = getTableValue(ignitionTable, MAP, rpm);
|
||||||
|
|
||||||
|
//Determine the current crank angle
|
||||||
|
int crankAngle = (toothCurrentCount - 1) * triggerToothAngle + triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is from TDC
|
||||||
|
if (crankAngle > 360) { crankAngle -= 360; } //Not sure if this is actually required
|
||||||
|
|
||||||
|
//Determine next firing angles
|
||||||
|
|
||||||
|
|
||||||
|
//Finally calculate the time (uS) until we reach the firing angles
|
||||||
|
|
||||||
|
|
||||||
//Serial.println(VE);
|
//Serial.println(VE);
|
||||||
//Serial.print("VE: ");
|
//Serial.print("VE: ");
|
||||||
//Serial.println(VE);
|
//Serial.println(VE);
|
||||||
|
@ -117,15 +134,20 @@ void loop()
|
||||||
//Serial.println(req_fuel * (float)(VE/100.0) * (float)(MAP/100.0) * (float)(100/100.0) + engineInjectorDeadTime);
|
//Serial.println(req_fuel * (float)(VE/100.0) * (float)(MAP/100.0) * (float)(100/100.0) + engineInjectorDeadTime);
|
||||||
//Serial.println( (float)(req_fuel * (float)(VE/100)) );
|
//Serial.println( (float)(req_fuel * (float)(VE/100)) );
|
||||||
//Serial.println( (float)(VE/100.0));
|
//Serial.println( (float)(VE/100.0));
|
||||||
//920 out
|
|
||||||
if (counter > 100000) {
|
if (counter > 100000) {
|
||||||
Serial.print("Calling schedule at: ");
|
scheduleStart = micros();
|
||||||
Serial.println(micros());
|
|
||||||
setSchedule1(openInjector2, 1000000);
|
setSchedule1(openInjector2, 1000000);
|
||||||
counter = 0;
|
counter = 0;
|
||||||
}
|
}
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
|
if (scheduleEnd != 0) {
|
||||||
|
Serial.print("The schedule took (uS): ");
|
||||||
|
Serial.println(scheduleEnd - scheduleStart);
|
||||||
|
scheduleEnd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ getSync(); }
|
{ getSync(); }
|
||||||
|
@ -153,7 +175,7 @@ void getSync()
|
||||||
//Interrupts
|
//Interrupts
|
||||||
|
|
||||||
//These 2 functions simply trigger the injector driver off or on.
|
//These 2 functions simply trigger the injector driver off or on.
|
||||||
void openInjector2() { Serial.print("Interrupt finished at: "); Serial.println(micros());}
|
void openInjector2() { scheduleEnd = micros();}
|
||||||
void openInjector() { digitalWrite(pinInjector, HIGH); } // Set based on an estimate of when to open the injector
|
void openInjector() { digitalWrite(pinInjector, HIGH); } // Set based on an estimate of when to open the injector
|
||||||
void closeInjector() { digitalWrite(pinInjector, LOW); } // Is called x ms after the open time where x is calculated by the rpm, load and req_fuel
|
void closeInjector() { digitalWrite(pinInjector, LOW); } // Is called x ms after the open time where x is calculated by the rpm, load and req_fuel
|
||||||
|
|
||||||
|
|
47
scheduler.h
47
scheduler.h
|
@ -3,11 +3,10 @@ This scheduler is designed to maintain 2 schedules for use by the fuel and ignit
|
||||||
It functions by waiting for the overflow vectors from each of the timers in use to overflow, which triggers an interrupt
|
It functions by waiting for the overflow vectors from each of the timers in use to overflow, which triggers an interrupt
|
||||||
|
|
||||||
//Technical
|
//Technical
|
||||||
Currently I am prescaling the 8-bit timers to 256. This means that the counter increments every 16us and will overflow every 2017mS
|
Currently I am prescaling the 16-bit timers to 256. This means that the counter increments every 16us and will overflow every 1048576uS
|
||||||
Max Period = (Prescale)*(1/Frequency)*(2^17)
|
Max Period = (Prescale)*(1/Frequency)*(2^17)
|
||||||
(See http://playground.arduino.cc/code/timer1)
|
(See http://playground.arduino.cc/code/timer1)
|
||||||
Because the maximum overflow occurs roughly every 2 seconds, you cannot schedule anything to be more than 2 seconds in the future.
|
This means that the precision of the scheduler is 16uS (+/- 8uS of target)
|
||||||
This also means that the precision of the scheduler is 16uS
|
|
||||||
|
|
||||||
/Features
|
/Features
|
||||||
This differs from most other schedulers in that its calls are non-recurring (IE You schedule an event at a certain time and once it has occurred, it will not reoccur unless you explicitely ask for it)
|
This differs from most other schedulers in that its calls are non-recurring (IE You schedule an event at a certain time and once it has occurred, it will not reoccur unless you explicitely ask for it)
|
||||||
|
@ -27,25 +26,32 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|
||||||
#define clockspeed 16000000
|
//#define clockspeed 16000000
|
||||||
|
|
||||||
int schedule1Active;
|
int schedule1Active;
|
||||||
int schedule2Active;
|
int schedule2Active;
|
||||||
void (*schedule1Callback)();
|
void (*schedule1Callback)(); //Callback function for schedule1
|
||||||
void (*schedule2Callback)();
|
void (*schedule2Callback)();
|
||||||
|
|
||||||
void initialiseScheduler()
|
void initialiseScheduler()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Much help in this from http://arduinomega.blogspot.com.au/2011/05/timer2-and-overflow-interrupt-lets-get.html
|
// Much help in this from http://arduinomega.blogspot.com.au/2011/05/timer2-and-overflow-interrupt-lets-get.html
|
||||||
//Timer 2, which is actually timer 1
|
//Schedule 1, which is uses timer 3
|
||||||
TCCR3B = 0x00; //Disbale Timer2 while we set it up
|
TCCR3B = 0x00; //Disbale Timer2 while we set it up
|
||||||
TCNT3 = 130; //Reset Timer Count to 130 out of 255
|
TCNT3 = 0; //Reset Timer Count
|
||||||
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||||
TIMSK3 = 0x01; //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
|
TIMSK3 = 0x01; //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
|
||||||
TCCR3A = 0x00; //Timer2 Control Reg A: Wave Gen Mode normal
|
TCCR3A = 0x00; //Timer2 Control Reg A: Wave Gen Mode normal
|
||||||
TCCR3B = (1 << CS12); //Timer2 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
TCCR3B = (1 << CS12); //Timer2 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
||||||
//TCCR3B = (1 << CS11) | (1 << CS10); //Timer2 Control Reg B: Timer Prescaler set to 64
|
|
||||||
|
//Schedule 2, which is uses timer 4
|
||||||
|
TCCR4B = 0x00; //Disbale Timer2 while we set it up
|
||||||
|
TCNT4 = 0; //Reset Timer Count
|
||||||
|
TIFR4 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||||
|
TIMSK4 = 0x01; //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
|
||||||
|
TCCR4A = 0x00; //Timer2 Control Reg A: Wave Gen Mode normal
|
||||||
|
TCCR4B = (1 << CS12); //Timer2 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -67,7 +73,16 @@ void setSchedule1(void (*callback)(), unsigned long timeout)
|
||||||
schedule1Active = 1; //Turn this schedule on
|
schedule1Active = 1; //Turn this schedule on
|
||||||
}
|
}
|
||||||
|
|
||||||
//Timer2 (schedule 1) Overflow Interrupt Vector
|
//As above, but for schedule2
|
||||||
|
void setSchedule2(void (*callback)(), unsigned long timeout)
|
||||||
|
{
|
||||||
|
//TODO: Need to add check for timeout > 1048576 ????
|
||||||
|
TCNT4 = 65536 - (timeout / 16); //Each tick occurs every 16uS with a 256 prescaler so divide the timeout by 16 to get ther required number of ticks. Subtract this from the total number of tick (65536 for 16-bit timer)
|
||||||
|
schedule2Callback = callback; //Name the callback function
|
||||||
|
schedule2Active = 1; //Turn this schedule on
|
||||||
|
}
|
||||||
|
|
||||||
|
//Timer3 (schedule 1) Overflow Interrupt Vector
|
||||||
//This needs to call the callback function if one has been provided and rest the timer
|
//This needs to call the callback function if one has been provided and rest the timer
|
||||||
ISR(TIMER3_OVF_vect)
|
ISR(TIMER3_OVF_vect)
|
||||||
{
|
{
|
||||||
|
@ -79,5 +94,17 @@ ISR(TIMER3_OVF_vect)
|
||||||
|
|
||||||
TCNT3 = 0; //Reset Timer to 0 out of 255
|
TCNT3 = 0; //Reset Timer to 0 out of 255
|
||||||
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||||
|
}
|
||||||
|
|
||||||
|
//AS above for schedule2
|
||||||
|
ISR(TIMER4_OVF_vect)
|
||||||
|
{
|
||||||
|
if (schedule2Active > 0) //Check to see if this schedule is turn on
|
||||||
|
{
|
||||||
|
schedule2Callback(); //Replace with user provided callback
|
||||||
|
schedule2Active = 0; //Turn off the callback
|
||||||
|
}
|
||||||
|
|
||||||
|
TCNT3 = 0; //Reset Timer to 0 out of 255
|
||||||
|
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||||
}
|
}
|
||||||
|
|
32
testing.h
32
testing.h
|
@ -73,3 +73,35 @@ void dummyFuelTable(struct table *myFuelTable)
|
||||||
for (int x = 0; x< myFuelTable->xSize; x++) { myFuelTable->values[7][x] = tempRow8[x]; }
|
for (int x = 0; x< myFuelTable->xSize; x++) { myFuelTable->values[7][x] = tempRow8[x]; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Populates a table with some reasonably realistic ignition advance data
|
||||||
|
*/
|
||||||
|
void dummyIgnitionTable(struct table *mySparkTable)
|
||||||
|
{
|
||||||
|
int tempXAxis[8] = {500,1500,2000,2500,3000,4000,5000,6000};
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->axisX[x] = tempXAxis[x]; }
|
||||||
|
//*myFuelTable->axisX = *tempXAxis;
|
||||||
|
int tempYAxis[8] = {100,88,75,63,50,38,25,13};
|
||||||
|
for (int x = 0; x< mySparkTable->ySize; x++) { mySparkTable->axisY[x] = tempYAxis[x]; }
|
||||||
|
//*myFuelTable->axisY = *tempYAxis;
|
||||||
|
|
||||||
|
//Go through the 8 rows and add the column values
|
||||||
|
int tempRow1[8] = {10,15,20,26,35,40,43,44};
|
||||||
|
int tempRow2[8] = {10,88,75,63,50,38,25,44};
|
||||||
|
int tempRow3[8] = {12,88,75,63,50,38,25,40};
|
||||||
|
int tempRow4[8] = {12,88,75,63,50,38,25,36};
|
||||||
|
int tempRow5[8] = {28,88,75,63,50,38,25,13};
|
||||||
|
int tempRow6[8] = {22,23,75,63,50,38,25,13};
|
||||||
|
int tempRow7[8] = {17,21,75,63,50,38,25,13};
|
||||||
|
int tempRow8[8] = {15,20,25,63,50,38,25,13};
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[0][x] = tempRow1[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[1][x] = tempRow2[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[2][x] = tempRow3[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[3][x] = tempRow4[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[4][x] = tempRow5[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[5][x] = tempRow6[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[6][x] = tempRow7[x]; }
|
||||||
|
for (int x = 0; x< mySparkTable->xSize; x++) { mySparkTable->values[7][x] = tempRow8[x]; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue