// this is https://wokwi.com/projects/469125032375576577
// see https://forum.arduino.cc/t/project-works-for-a-while-then-hangs/1451042
# define WOKWI
# ifdef WOKWI
const byte brakePedal = 6;
const byte startButton = 7;
const byte engineRunningSignal = 8; //temporary button to simulate CAN
const byte RED = 5;
const byte GREEN = 4;
const byte ignitionRelay = 3;
const byte Crank = 2;
const byte ledPin = 9;
// brake pedal backwards to me
# define UP HIGH
# define DOWN LOW
# else // real Mega hardware
const byte brakePedal = 21;
const byte startButton = 20;
const byte RED = 55;
const byte GREEN = 56;
const byte ignitionRelay = 24;
const byte Crank = 15;
const byte ledPin = 13;
// brake pedal
# define UP LOW
# define DOWN HIGH
# endif
const byte engineStatus = A0; // an output the engine FSM uses to say engine is running
boolean engineRunning;
boolean brakePedalState;
boolean startButtonCurrent;
boolean startButtonPrevious;
boolean ledState;
byte startButtonPresses;
unsigned long startTime;
unsigned long debounce = 100;
unsigned long previousMillis;
const long interval = 200;
//...
# define PRESSSED LOW
# define NOTPRESSSED HIGH
# define ON LOW
# define OFF HIGH
# define LED_ON HIGH
# define LED_OFF LOW
# define RELAY_ON LOW
# define RELAY_OFF HIGH
# define CRANK_ON HIGH
# define CRANK_OFF LOW
# define RUNNING LOW
# define NOT_RUNNING HIGH
//... sorry Mom! these are for the simulated engine FSM
# define SIM_RUNNING LOW
# define SIM_NOT_RUNNING HIGH
void setup() {
Serial.begin(9600) ;
digitalWrite (ignitionRelay, RELAY_OFF); //Stop nuisance trigger of
startButtonPresses = 0;
//...
pinMode(brakePedal, INPUT); // switch to earth, pull up please
pinMode(startButton, INPUT); // switch to earth, pull up please
pinMode(engineRunningSignal, INPUT); // switch to earth, pull up please
pinMode(ledPin, OUTPUT);
pinMode(RED, OUTPUT); // Direct output to Start button LED
pinMode(GREEN, OUTPUT); // Direct output to Start button LED
pinMode(ignitionRelay, OUTPUT); // Relay
pinMode(Crank, OUTPUT); // Direct output
pinMode(engineStatus, OUTPUT); // engine FSM
digitalWrite(engineStatus, SIM_NOT_RUNNING);
}
void loop()
{
startMeUp(); //... FSM to simulate cranky engine
//
IgnitionSwitch();
flash();
}
void IgnitionSwitch()
{
startButtonCurrent = digitalRead(startButton) == PRESSSED;
brakePedalState = digitalRead(brakePedal) == DOWN;
// CAN to say, here the signal comes from startMeUp()
engineRunning = digitalRead(engineRunningSignal) == RUNNING; // was proxy pushbutton now automagic FSM
if (false) {
Serial.print(" engine running "); Serial.println(engineRunning ? "YES " : "NO");
Serial.print(" starter "); Serial.println(startButtonCurrent ? "PRESSED" : "NO");
Serial.print(" brake pedal "); Serial.println(brakePedalState ? "PRESSED" : "NO");
Serial.println("");
}
// debounce / edge detection
if (millis() - startTime >= debounce) {
if (startButtonCurrent != startButtonPrevious) {
startTime = millis();
if (startButtonCurrent) { // newly PRESSSED
if (brakePedalState && !engineRunning) {
// brake is PRESSSED and engine is not running:
// go to crank
startButtonPresses = 2;
}
else {
// otherwise, toggle ignition ON/OFF
if (startButtonPresses == 0)
startButtonPresses = 1;
else
startButtonPresses = 0;
}
}
startButtonPrevious = startButtonCurrent;
}
}
static int lastPrinted = -1;
if (lastPrinted != startButtonPresses) {
Serial.print(" ignition case : "); Serial.println(startButtonPresses);
lastPrinted = startButtonPresses;
}
switch (startButtonPresses) { //Things to do as a result of above code
case 0: //Ignition OFF
digitalWrite (RED, LED_OFF);
digitalWrite (GREEN, LED_OFF);
digitalWrite (ignitionRelay, RELAY_OFF);
digitalWrite (Crank, CRANK_OFF);
break;
case 1: //Ignition ON
digitalWrite (RED, engineRunning ? LED_OFF : LED_ON);
digitalWrite (GREEN, engineRunning ? LED_ON : LED_OFF);
digitalWrite (ignitionRelay, RELAY_ON);
digitalWrite (Crank, CRANK_OFF);
break;
case 2: //Crank engine
digitalWrite (RED, LED_ON);
digitalWrite (GREEN, LED_ON);
digitalWrite (ignitionRelay, RELAY_ON);
if (!engineRunning) { //If the engine isn't running
digitalWrite (Crank, startButtonCurrent ? CRANK_ON : CRANK_OFF); //Send MaxxECU an active low start pulse
} else { //If the engine is running
startButtonPresses = 1; //go back to just ignition on
}
break;
}
}
void flash()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
void startMeUp()
{
static unsigned long timer;
static byte state;
static int timeToCatch;
static int lastPrinted = -1;
if (lastPrinted != state) {
Serial.print(" cranking case : "); Serial.println(state);
lastPrinted = state;
}
switch (state) {
case 0 : // off
if (digitalRead(Crank) == CRANK_ON) {
timeToCatch = random(777, 1999); // it will catch in 777 - 1999 ms
timer = millis();
Serial.print(" will catch in ");
Serial.print(timeToCatch);
Serial.println(" ms.");
Serial.println("");
state = 1;
}
break;
case 1 : // cranking. will it start this time?
if (millis() - timer > timeToCatch) {
digitalWrite(engineStatus, SIM_RUNNING);
state = 2;
}
break;
//...
case 2 :
if (digitalRead(ignitionRelay) == RELAY_OFF) {
state = 0;
digitalWrite(engineStatus, SIM_NOT_RUNNING);
}
break;
default :
Serial.println("\nRotten Denmark!");
while (1);
break;
}
}