// Simulation of a 4 stroke engine (injection and ignition)
// https://forum.arduino.cc/t/micros-counting-time-for-engine-simulation/1255668/13
// 2024-04-05 by noiasca
constexpr uint8_t throttlePin {A0}; // Analog Input
constexpr uint8_t cylinders = 3;
constexpr uint8_t ignitionPin[cylinders] {3, 5, 6};
constexpr uint8_t injectionPin[cylinders] {9, 10, 11};
// parameters from 0 .. 720 for a 4 stroke
constexpr int16_t injectionStart = 720 - 90;
constexpr int16_t injectionEnd = 720 - 45;
constexpr int16_t ignitionStart = 720 - 25;
constexpr int16_t ignitionEnd = 720 - 10;
constexpr uint16_t firingOffset[cylinders] = {0, 480, 240}; // can also be used for firing order or a Big-bang engine
uint16_t cycle = 0; // counts from 0 to 720 for a 4 stroke
void setup() {
Serial.begin(115200);
for (auto &i : ignitionPin) pinMode(i, OUTPUT);
for (auto &i : injectionPin) pinMode(i, OUTPUT);
}
void loop() {
static uint32_t previousMicros = 0;
uint32_t currentMicros = micros();
uint16_t interval = map(analogRead(throttlePin), 0, 1024, 0, 2048);
if (currentMicros - previousMicros > interval) {
previousMicros = currentMicros;
if (++cycle > 720) cycle = 0;
for (int i = 0; i < cylinders; i++) {
uint16_t thisCycle = (cycle + firingOffset[i]) % 720; // cylce angle for this cylinder
if (thisCycle >= ignitionStart && thisCycle <= ignitionEnd) {
if (digitalRead(ignitionPin[i]) == LOW) digitalWrite(ignitionPin[i], HIGH);
}
else if (digitalRead(ignitionPin[i]) == HIGH) digitalWrite(ignitionPin[i], LOW);
if (thisCycle >= injectionStart && thisCycle <= injectionEnd) {
if (digitalRead(injectionPin[i]) == LOW) digitalWrite(injectionPin[i], HIGH);
}
else if (digitalRead(injectionPin[i]) == HIGH) digitalWrite(injectionPin[i], LOW);
}
}
}