Icesythe7
Active member
- 147
- 223
- 43
- Location
- Indiana, USA
So I design alot of pcbs/circuits for mods for retro systems like gameboys etc and have alot of MCU's laying around figured I would make some rudimentary autostart, I did manage to get an autostart made for about $7 in parts that works but was curious if I am going about it properly and if I should change anything.
Currently I am more or less electronically emulating the master switch with the thought process that if there is an error of some sort (oil pressure, coolant temp, etc) it will still shutdown the engine as it overrides the master switch which I am emulating. I have yet to hook up any of the gauges for monitoring (I do plan too) but my thought process is as follows:
User presses start on touchscreen/bluetooth device/wifi device
1. Ensure motor is not already running by reading HZ (if HZ greater than x motor running)
2. Read coolant temp if temp less than x start preheat for y time
3. Set proper mode (run or aux run) and let pressure build for ~3 seconds
4. Crank motor until oil pressure is higher than 35 (assume we started here) then hold for 2 seconds
5. If we don't see a start after cranking for 5 seconds or we had a start but died reset and start again at step 2 until 3 attempts are made and then notify user of a non start
6. If we start and are running monitor all data for user and display it including faults
Does anyone see a better way to know if the engine is running? Am I missing any critical steps or can anything be improved?
For the people that like code I am currently just testing with an arduino but plan to use a pico w or esp32 for the final product so don't judge the 15 mins it took to make this lol
Currently I am more or less electronically emulating the master switch with the thought process that if there is an error of some sort (oil pressure, coolant temp, etc) it will still shutdown the engine as it overrides the master switch which I am emulating. I have yet to hook up any of the gauges for monitoring (I do plan too) but my thought process is as follows:
User presses start on touchscreen/bluetooth device/wifi device
1. Ensure motor is not already running by reading HZ (if HZ greater than x motor running)
2. Read coolant temp if temp less than x start preheat for y time
3. Set proper mode (run or aux run) and let pressure build for ~3 seconds
4. Crank motor until oil pressure is higher than 35 (assume we started here) then hold for 2 seconds
5. If we don't see a start after cranking for 5 seconds or we had a start but died reset and start again at step 2 until 3 attempts are made and then notify user of a non start
6. If we start and are running monitor all data for user and display it including faults
Does anyone see a better way to know if the engine is running? Am I missing any critical steps or can anything be improved?
For the people that like code I am currently just testing with an arduino but plan to use a pico w or esp32 for the final product so don't judge the 15 mins it took to make this lol
C++:
class MepAutoStart
{
enum state: uint8_t {
off,
preheat,
start,
running
};
enum mode: uint8_t {
aux_run,
run
};
static constexpr uint8_t num_states = 4;
static constexpr uint8_t num_modes = 2;
const char* const state_strings_[num_states] = { "Off", "Preheat", "Start", "Running" };
const char* const mode_strings_[num_modes] = { "Aux run", "Run" };
using callback_function_t = void(*)(uint8_t);
callback_function_t callback_ = nullptr;
uint8_t preheat_start_pin_;
uint8_t aux_run_pin_;
uint8_t run_pin_;
uint8_t current_state_ = off;
uint8_t last_state_ = 0xFF;
uint8_t current_mode_ = run;
bool has_preheated_ = false;
MepAutoStart(const uint8_t preheat_start, const uint8_t aux, const uint8_t run) {
preheat_start_pin_ = preheat_start;
aux_run_pin_ = aux;
run_pin_ = run;
pinMode(preheat_start_pin_, OUTPUT);
pinMode(aux_run_pin_, OUTPUT);
pinMode(run_pin_, OUTPUT);
}
// forbid more than 1 instance or copies of class
MepAutoStart(const MepAutoStart&) = delete;
MepAutoStart& operator=(MepAutoStart const&) = delete;
public:
static MepAutoStart& init(const uint8_t preheat_start, const uint8_t aux, const uint8_t run) {
static MepAutoStart res(preheat_start, aux, run);
return res;
}
void registerCallback(const callback_function_t f) {
callback_ = f;
}
void setState(const uint8_t new_state) {
current_state_ = new_state;
}
uint8_t getState() const {
return current_state_;
}
const char* stateToString(const uint8_t state) {
return (state < num_states) ? state_strings_[state] : "Unknown";
}
void setMode(const uint8_t new_mode) {
current_mode_ = new_mode;
}
uint8_t getMode() const {
return current_mode_;
}
const char* modeToString(const uint8_t mode) {
return (mode < num_modes) ? mode_strings_[mode] : "Unknown";
}
bool preHeat(const bool test) {
static bool pre_heat_running = false;
static uint32_t start_time = 0;
// todo: if engine temp < 55c preheat for x time based on temp else skip state
if (pre_heat_running) {
constexpr uint32_t preheat_time = 5000;
const uint32_t elapsed_time = millis() - start_time;
if (preheat_time > elapsed_time) {
return true;
}
pre_heat_running = false;
has_preheated_ = true;
digitalWrite(preheat_start_pin_, LOW);
return false;
}
if (test) { // fake simulation of cold start since no temp yet
pre_heat_running = true;
start_time = millis();
digitalWrite(preheat_start_pin_, HIGH);
return true;
}
return false;
}
void update() {
const uint8_t current_state = getState();
if (current_state != last_state_) {
last_state_ = current_state;
if (callback_)
callback_(current_state);
}
switch (current_state) {
case off: {
digitalWrite(preheat_start_pin_, LOW);
digitalWrite(aux_run_pin_, LOW);
digitalWrite(run_pin_, LOW);
has_preheated_ = false;
break;
}
case preheat: {
digitalWrite(aux_run_pin_, LOW);
digitalWrite(run_pin_, LOW);
if (!preHeat(true))
setState(start);
break;
}
case start: {
digitalWrite(getMode() ? run_pin_ : aux_run_pin_, HIGH);
delay(3000);
digitalWrite(preheat_start_pin_, HIGH);
delay(3000);
digitalWrite(preheat_start_pin_, LOW);
setState(running);
break;
}
case running: {
//if (errors)
//{
// // report errors and shutdown engine
// setState(off);
//}
break;
}
default:
break;
}
}
};
inline void OnStateChange(uint8_t state);
MepAutoStart& gen_set = MepAutoStart::init(2, 4, 3);
uint32_t last_time = millis();
void setup() {
Serial.begin(9600);
gen_set.registerCallback(OnStateChange);
Serial.println("AutoStart Controller v0.1 by Icesythe7");
// test code until touchscreen gets here from china
delay(5000);
gen_set.setState(1);
}
void loop() {
const uint32_t current_time = millis();
static uint32_t times = 0;
// simulate a button press of touchscreen every 2 mins
if (current_time - last_time >= 120000) {
last_time = current_time;
gen_set.setState(times % 2);
times++;
}
gen_set.update();
}
void OnStateChange(const uint8_t state) {
Serial.print("Current machine state changed to ");
Serial.println(gen_set.stateToString(state));
}
Last edited: