ok again, this is the sketch that I was using so far.
#include <digitalWriteFast.h>
// 5k pot inputs
#define kphIn A5
#define rpmIn A3
#define injectorIn A4
// signal outputs
#define kphOut 13
#define rpmOut 11
#define injectorOut 7
unsigned long timeMicros;
unsigned long timeMillis;
// injector variables
int injector;
unsigned long injectionFactor;
unsigned long injectionOffFactorBasic;
unsigned long injectionOffFactor;
unsigned long injectorLowTimestamp;
unsigned long injectorHighTimestamp;
unsigned long injectionLowElapse;
unsigned long injectionHighElapse;
boolean injectionIntervalStart = false;
// kph variables
int kph;
unsigned long kphFactor;
unsigned long kphTimestamp = millis();
unsigned long kphElapse;
boolean kphOn = false;
boolean rpmOn = false;
// rpm variables
int rpm;
int rpmFactor;
unsigned long rpmTimestamp = micros();
unsigned long rpmElapse;
void setup() {
pinModeFast(injectorIn, INPUT);
pinModeFast(injectorOut, OUTPUT);
pinModeFast(kphIn, INPUT);
pinModeFast(kphOut, OUTPUT);
pinModeFast(rpmIn, INPUT);
pinModeFast(rpmOut, OUTPUT);
Serial.begin(115200);
Serial.println("Serial Connection OK");
}
void loop() {
// ------- Generating signals
// injector signal
// ----------------- calculating factors --------------------
// I have observed that injection intervals at low engine load
// are constantly around 1 ms, and at high engine load they are ca. 2 ms.
// This should be the engine control unit's response to
// detecting higher engine load.
// So the ECU increases fuel injection quantities both by shortening
// intervals between injection events and by lengthening
// the injection interval itself.
// Note: Fuel is injected by switching the fuel injectors to GND.
// This opens a needle valve on the injector and causes fuel to inject.
injector = analogRead(injectorIn);
if (injector >= 800) injectionFactor = 2000; // injection interval (us) at high engine load
else if (injector < 800) injectionFactor = 1000; // injection interval (us) at low engine load
injectionOffFactorBasic = (1023 - injector); // Calculating the spacing between injection events
if (injector >= 800) injectionOffFactor = injectionOffFactorBasic * 50; // high engine load
else if (injector < 800) injectionOffFactor = injectionOffFactorBasic * 100; // low engine load
if (injectionIntervalStart) {
timeMicros = micros();
injectionLowElapse = timeMicros - injectorLowTimestamp;
if (injectionLowElapse >= injectionFactor) {
injectorHighTimestamp = micros();
digitalWriteFast(injectorOut, HIGH);
injectionIntervalStart = false;
}
}
else if (!injectionIntervalStart) {
timeMicros = micros();
injectionHighElapse = timeMicros - injectorHighTimestamp;
if (injectionHighElapse >= injectionOffFactor) {
injectorLowTimestamp = micros();
digitalWriteFast(injectorOut, LOW);
injectionIntervalStart = true;
}
}
// kph signal
// The kph signal is a symmetric square wave generated
// by the car's speed transducer. Its frequency is directly
// proportional to the vehicle speed.
kph = analogRead(kphIn);
if (kph == 0) kph = 1;
kphFactor = (int) (kph * (-0.085) + 90); // generates life-like speed signal from 3 mph to about 125 mph
timeMillis = millis();
kphElapse = timeMillis - kphTimestamp;
if (kphElapse >= kphFactor) {
kphTimestamp = millis();
if (kphOn) {
digitalWriteFast(kphOut, LOW);
kphOn = false;
}
else {
digitalWriteFast(kphOut, HIGH);
kphOn = true;
}
}
// rpm signal
rpm = analogRead(rpmIn);
if (rpm == 0) rpm = 1;
rpmFactor = (int) (rpm * (-0.551) + 650); // leads to 86 us if pot analogRead is at 1023, which is about 7000 rpm
timeMicros = micros();
rpmElapse = timeMicros - rpmTimestamp;
if (rpmElapse >= rpmFactor) {
rpmTimestamp = micros();
if (!rpmOn) {
digitalWriteFast(rpmOut, HIGH);
rpmOn = true;
}
else {
digitalWriteFast(rpmOut, LOW);
rpmOn = false;
}
}
}
I still need to get my head around a few timer related things and read up on them (I'm feeling reluctant to just use code I don't yet fully understand), but once I've managed that, I will probably finally implement Johnny's code from further up in this thread and see how it does.
And then one of the next things on my to-do list will be incorporating the Attiny's functionality so far of measuring just the rpm pulses into the Atmega. So that there is really just one chip at work in the engine data module.
On another note - is there any point in trying to keep I2C transmissions brief, if I've got such time critical code? Or will that not make a big difference?
At the moment, this is what happens when the engine data module "phones home", or rather, when the master requests data:
void requestEvent() {
bitWrite(PORTB, led, HIGH); // Confirmation LED blinks every time data is sent.
// This should help debug the system when it
// gets installed in the car.
// Generating Fuel Consumption and Speed Bytes
byte Data[5];
fuelConsFloatPtr = (byte*) & fuelConsumption;
Data[0] = fuelConsFloatPtr[0];
Data[1] = fuelConsFloatPtr[1];
Data[2] = fuelConsFloatPtr[2];
Data[3] = fuelConsFloatPtr[3];
// Maximum speed is 190 kph, so one byte will be enough
Data[4] = (byte) (kmh_speed);
Wire.write(Data, 5);
// Generating fuel tank, oil temp and coolant temp bytes
byte DataGauges[9];
// fuel tank
fuelTankFloatPtr = (byte*) & fuelLevelFinal;
DataGauges[0] = fuelTankFloatPtr[0];
DataGauges[1] = fuelTankFloatPtr[1];
DataGauges[2] = fuelTankFloatPtr[2];
DataGauges[3] = fuelTankFloatPtr[3];
// oil and coolant... 16 bit, always low byte first, second byte last
DataGauges[4] = (byte) (oilTempFinal & 0xff);
DataGauges[5] = (byte) ((oilTempFinal >> 8) & 0xff);
DataGauges[6] = (byte) (coolantTempFinal & 0xff);
DataGauges[7] = (byte) ((coolantTempFinal >> 8) & 0xff);
DataGauges[8] = lowCoolant;
Wire.write(DataGauges, 9);
delay(50); // I know that this will need to be addressed; a later version of the code
// will have a non-blocking led blink.
bitWrite(PORTB, led, LOW);
}