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 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 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 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
|
||||
#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 "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
|
||||
|
@ -47,11 +47,14 @@ volatile unsigned long toothLastMinusOneToothTime = 0; //The time (micros()) tha
|
|||
|
||||
int rpm = 0; //Stores the last recorded RPM value
|
||||
struct table fuelTable;
|
||||
struct table ignitionTable;
|
||||
|
||||
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
|
||||
|
||||
unsigned long counter;
|
||||
unsigned long scheduleStart;
|
||||
unsigned long scheduleEnd;
|
||||
|
||||
void setup() {
|
||||
|
||||
|
@ -80,6 +83,7 @@ void setup() {
|
|||
Serial.begin(9600);
|
||||
|
||||
dummyFuelTable(&fuelTable);
|
||||
dummyIgnitionTable(&ignitionTable);
|
||||
initialiseScheduler();
|
||||
counter = 0;
|
||||
}
|
||||
|
@ -102,12 +106,25 @@ void loop()
|
|||
//Get the current MAP value
|
||||
int MAP = 20; //Placeholder
|
||||
|
||||
//Begin the fuel calculation
|
||||
//Perform lookup into fuel map for RPM vs MAP value
|
||||
int VE = getTableValue(fuelTable, MAP, rpm);
|
||||
|
||||
//From all of the above, calculate an injector pulsewidth
|
||||
//Calculate an injector pulsewidth form the VE
|
||||
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.print("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( (float)(req_fuel * (float)(VE/100)) );
|
||||
//Serial.println( (float)(VE/100.0));
|
||||
//920 out
|
||||
|
||||
if (counter > 100000) {
|
||||
Serial.print("Calling schedule at: ");
|
||||
Serial.println(micros());
|
||||
scheduleStart = micros();
|
||||
setSchedule1(openInjector2, 1000000);
|
||||
counter = 0;
|
||||
}
|
||||
counter++;
|
||||
|
||||
if (scheduleEnd != 0) {
|
||||
Serial.print("The schedule took (uS): ");
|
||||
Serial.println(scheduleEnd - scheduleStart);
|
||||
scheduleEnd = 0;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{ getSync(); }
|
||||
|
@ -153,7 +175,7 @@ void getSync()
|
|||
//Interrupts
|
||||
|
||||
//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 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
|
||||
|
||||
//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)
|
||||
(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 also means that the precision of the scheduler is 16uS
|
||||
This means that the precision of the scheduler is 16uS (+/- 8uS of target)
|
||||
|
||||
/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)
|
||||
|
@ -27,25 +26,32 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
|
|||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#define clockspeed 16000000
|
||||
//#define clockspeed 16000000
|
||||
|
||||
int schedule1Active;
|
||||
int schedule2Active;
|
||||
void (*schedule1Callback)();
|
||||
void (*schedule1Callback)(); //Callback function for schedule1
|
||||
void (*schedule2Callback)();
|
||||
|
||||
void initialiseScheduler()
|
||||
{
|
||||
|
||||
// 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
|
||||
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
|
||||
TIMSK3 = 0x01; //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
|
||||
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 << 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
|
||||
}
|
||||
|
||||
//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
|
||||
ISR(TIMER3_OVF_vect)
|
||||
{
|
||||
|
@ -79,5 +94,17 @@ ISR(TIMER3_OVF_vect)
|
|||
|
||||
TCNT3 = 0; //Reset Timer to 0 out of 255
|
||||
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]; }
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
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