Fully working scheduler (With 2 schedules), initial crank timing work.

This commit is contained in:
Josh Stewart 2013-02-14 17:34:29 +11:00
parent feff0b244d
commit 1537249958
3 changed files with 100 additions and 19 deletions

View File

@ -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,14 +134,19 @@ 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
@ -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

View File

@ -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 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
}

View File

@ -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]; }
}