Help for beginner, starter relay control

Hi guys, have project, so only Arduino can help.
Need to transfer HIGH to the pin for control starter relay with 4 if's, started write sketch, but too many questions came straight away.
Sorted only 1st step, it's rpm counter, switching relay off if rpm is higher than 14HZ.
Cannot connect another inputs.
What I need:
After switching ignition on, delay 2 sec, then checking engine rpm, brake pedal position, gearbox park position. If all signals are HIGH, turn on relay, after rpm is more than 14HZ relay off.
What I did:

int rpm = 3;
int brake = 2;
int park = 4;
int ign = 5;
int start = 12;


int rpmStat = 0;
int brakeStat = 0;
int parkStat = 0;
int ignStat = 0;
int on = 0;


void setup() {
  
 pinMode(3, INPUT); //rpm input up to 14HZ(engine running = 18HZ))
 pinMode(2, INPUT); //brake switch +
 pinMode(4, INPUT); //park/neutral switch +
 pinMode(5, INPUT); //15 terminal IGNITION +
 pinMode(12, OUTPUT); //Starter relay control
  
}

void loop()
{ int Speed;
Speed = 500000/pulseIn(3, HIGH);
{ 
 if (Speed > 7)
 {
 digitalWrite(12, HIGH);
 }
 else
 {
 digitalWrite(12, LOW);
 }
 
 }
}

read about delay() and millis()
for your tests on signals high you can do

  if(digitalRead(2) && digitalRead(3) ....
1 Like

Hi, @keturi
Welcome to the forum and thank you for using code tags.

You could improve the readability of you code by using the variable names you have given you I/O pins.

I have edited it to make it easier to read, including pressing [ CTRL ] [ T } in the IDE to auto format the structure.
Also there were an extra set of { } that weren't needed.

int rpmPin = 3;
int brakePin = 2;
int parkPin = 4;
int ignPin = 5;
int startPin = 12;


int rpmStat = 0;
int brakeStat = 0;
int parkStat = 0;
int ignStat = 0;
int on = 0;


void setup()
{
  pinMode(rpmPin, INPUT); //rpm input up to 14HZ(engine running = 18HZ))
  pinMode(brakePin, INPUT); //brake switch +
  pinMode(parkPin, INPUT); //park/neutral switch +
  pinMode(ignPin, INPUT); //15 terminal IGNITION +
  pinMode(startPin, OUTPUT); //Starter relay control
}

void loop()
{
  int Speed;
  Speed = 500000 / pulseIn(rpmPin, HIGH);
  if (Speed > 7)
  {
    digitalWrite(startPin, HIGH);
  }
  else
  {
    digitalWrite(startPin, LOW);
  }
}

You might be worth drawing a flow chart. or a check list table to sort out what you outputs can be with different combinations of input.

Tom... :smiley: :+1: :coffee: :australia:

1 Like

that's not very readable

meaningful variable names (isn't rpm the speed) and using them makes sense

    rpm =  MsecPerSec / PulsePerRev / pulseIn (rpmPin, HIGH);

not sure what pulseIn

there are obviously several states:

  • idle,
  • presumably started (ignition switch on),
  • a delay state after started,
  • ready to run(?) but rpm < 14HZ
  • running (rpm > 14HZ)

a switch statement can manage the execution of code for each state.

1 Like

Is your "14 Hz" supposed to represent 14 pulses per second (7 RPS = 420 RPM) or 14 RPS (840 RPM)?

Speed = 500000 / pulseIn(rpmPin, HIGH);

WARNING: Depending on the source of your pulses, the HIGH time may not be proportional to the speed. Usually it's the time between pulses that is of interest. You can get close with (pulseIn(rpmPin, HIGH) + pulseIn(rpmPin, LOW)) but that still leaves the possibility of timeout where the value ZERO is returned. You don't get good answers when you divide by zero.

I recommend something like this for measuring revolutions per second:

  // No need to wait longer than 1/10th second.
  const unsigned long timeout = 100000ul;  

  unsigned long highTime = pulseIn(rpmPin, HIGH, timeout);
  unsigned long lowTime = pulseIn(rpmPin, LOW, timeout);
  if (highTime != 0 && lowTime != 0)
  {
    rps =  MsecPerSec / PulsePerRev / (highTime + lowTime);
  }
  else // Timeout on one or both samples
    rps = 0;
1 Like

Thanks for everybody, I have made some modifications and it started work.
Now can work for mods which can make project more stable, about counting rpm's as well.
Sketch now:

const int rpmPin = 3;
const int brakePin = 2;
const int parkPin = 4;
const int ignPin = 5;
const int startPin = 12;

int rpmState = 0;
int brakeState = 0;
int parkState = 0;
int ignState = 0;

void setup() {
 Serial.begin(9600); 
 pinMode(rpmPin, INPUT); //rpm input up to 15HZ(engine running = 18HZ)
 pinMode(brakePin, INPUT); //brake switch +
 pinMode(parkPin, INPUT); //park/neutral switch +
 pinMode(ignPin, INPUT); //15 terminal IGNITION +
 pinMode(startPin, OUTPUT); //Starter relay control
 digitalWrite(startPin, LOW); 

}

void loop(){
  
  int Speed;
  Speed = 500000/pulseIn(rpmPin, HIGH);
  
  rpmState = digitalRead(rpmPin);
  brakeState = digitalRead(brakePin);
  ignState = digitalRead(ignPin);
  parkState = digitalRead(parkPin);

 
 if (Speed <= 7 && brakeState == HIGH && ignState == HIGH)
  {
 digitalWrite(startPin, HIGH);
 }
 else
 {
  digitalWrite(startPin, LOW);
 }
}type or paste code here

One more question, why delay is 2 sec as well when ignition is off? How to make no delay after rpm more than 7 or ignition is off?

if (ignState == HIGH)
    delay(2000);
    if (Speed <= 7 && brakeState == HIGH && ignState == HIGH)
 
  {
 digitalWrite(startPin, HIGH);
 }
 else
 {
  digitalWrite(startPin, LOW);

P.S. sorry for the stupid questions, it's first my touch with Arduino :slight_smile:

it's very hard to comment on this approach, not a state machine or sequencer

clearly there is a state where if the ignition is off, the motor should be turned off and nothing else done.

for your 2 sec delay, there needs to be the recognition of when the ignition changes from off to on, possibly in the OFF state (not ignition off), a 2 sec delay occurs and then setting the state to ON

and then after the delay, there is a state where normal processing occurs.

That's how you wrote it. That's how you said it should work: "After switching ignition on, delay 2 sec, ". Did you mean "After turning starter relay on, wait two seconds and check engine RPM...".

Why the delay? Why not: When the ignition is on, and the "Speed" is below 8, and the, brake is on, and the transmission is in Park, then turn on the starter relay.

void loop()
{
  brakeState = digitalRead(brakePin);
  ignState = digitalRead(ignPin);
  parkState = digitalRead(parkPin);

  // If everything is ready for starting
  if (ignState == HIGH && brakeState == HIGH && parkState == HIGH)
  {
    unsigned long pulseWidth = pulseIn(rpmPin, HIGH);

    // If the engine is not running
    if (pulseWidth == 0 || (500000ul / pulseWidth) <= 7)
    {
      // Turn on the starter
      digitalWrite(startPin, HIGH);
    }
    else
    {
      // Engine running.  Turn off the starter
      digitalWrite(startPin, LOW);
    }
  }
  else
  {
    // NOT READY TO START.  Make sure the starter is off
    digitalWrite(startPin, LOW);
  }
}
1 Like

I mean that starter motor relay control should be ON after 2 sec when ign, rpm, brake and park are HIGH and immediately OFF when one of the functions is LOW. Now it works ok, but after engine is started, starter motor spins 2 sec extra.

Because after press ignition button, for a while all car systems running check and if to run starter relay straight away, some warning lights coming on. With 2 sec delay all is good only damaging starter motor while keeping on 2 sec extra.

it would be easier to implement this (or at least discuss it in terms of) three states: OFF, ON, STARTED

the ignition switch off forces the state to OFF, tuning the ignition switch on sets the state of ON and after a 2 sec delay the state is set to STARTED

Here is a version with a timer to turn on the starter after everything has been ready for two seconds:

const int rpmPin = 3;
const int brakePin = 2;
const int parkPin = 4;
const int ignPin = 5;
const int startPin = 12;

unsigned long LastTimeNotReady = 0;

void setup()
{
  // Serial.begin(9600); // Not using any Serial I/O

  pinMode(rpmPin, INPUT); //rpm input up to 15HZ(engine running = 18HZ)
  pinMode(brakePin, INPUT); //brake switch +
  pinMode(parkPin, INPUT); //park/neutral switch +
  pinMode(ignPin, INPUT); //15 terminal IGNITION +
  digitalWrite(startPin, LOW);
  pinMode(startPin, OUTPUT); //Starter relay control
}

void loop()
{
  int brakeState = digitalRead(brakePin);
  int ignState = digitalRead(ignPin);
  int parkState = digitalRead(parkPin);

  // If everything is ready for starting
  if (ignState == HIGH && brakeState == HIGH && parkState == HIGH)
  {
    unsigned long pulseWidth = pulseIn(rpmPin, HIGH);

    // If the engine is not running
    if (pulseWidth == 0 || (500000ul / pulseWidth) <= 7)
    {
      // Turn on the starter if everything has been ready for at least 2 seconds
      if (millis() - LastTimeNotReady >= 2000)
        digitalWrite(startPin, HIGH);
    }
    else
    {
      // Engine running.  Turn off the starter
      digitalWrite(startPin, LOW);
      LastTimeNotReady = millis();
    }
  }
  else
  {
    // NOT READY TO START.  Make sure the starter is off
    digitalWrite(startPin, LOW);
    LastTimeNotReady = millis();
  }
}
1 Like

(500000ul / pulseWidth) <= 7

This can be simplified to:
500000ul <= 7 * pulseWidth
500000ul / 7 <= pulseWidth
'71429ul <= pulseWidth'

pulseWidth >= 71429ul

You can make the pulseIn() more responsive by setting a timeout below the default of a million microseconds:

    const unsigned long maxPulseWidthRunning = 71429ul; 
    unsigned long pulseWidth = pulseIn(rpmPin, HIGH, maxPulseWidthRunning * 2);

    // If the engine is not running
    if (pulseWidth == 0 || pulseWidth >= maxPulseWidthRunning)
    {

This will get an answer in under 0.15 seconds rather than waiting a whole second to find out that the motor isn't turning.

2 Likes

Thanks guys for the help. all working, tested on the car, only increased rpm from value 7 to 8, as well changed inputs to LOW, because for 5V inputs from 12V used optocouplers.

//Range Rover TDV8 2013 starter relay control


const int rpmPin = 3;
const int brakePin = 2;
const int ignPin = 5;
const int parkPin = 4;
const int startPin = 12;
const unsigned long maxPulseWidthRunning = 30000ul; // 15HZ

unsigned long LastTimeNotReady = 0;
 

void setup()
{
  
  pinMode(rpmPin, INPUT); //rpm input up to 15HZ(engine running = 18HZ)
  pinMode(brakePin, INPUT); //brake switch +
  pinMode(parkPin, INPUT); //park/neutral swith +
  pinMode(ignPin, INPUT); //15 terminal IGNITION +
  digitalWrite(startPin, LOW);
  pinMode(startPin, OUTPUT); //Starter relay control
}

void loop()
{
  int brakeState = digitalRead(brakePin);
  int ignState = digitalRead(ignPin);
  int parkState = digitalRead(parkPin);

  // If everything is ready for starting
  if (ignState == LOW && brakeState == LOW && parkState == LOW)
  {
    unsigned long pulseWidth = pulseIn(rpmPin, LOW, maxPulseWidthRunning * 2);

    // If the engine is not running
    if (pulseWidth == 0 || pulseWidth >= maxPulseWidthRunning)
    {
      // Turn on the starter if everything has been ready for at least 2 seconds
      if (millis() - LastTimeNotReady >= 2000)
        digitalWrite(startPin, HIGH);
    }
    else
    {
      // Engine running.  Turn off the starter
      digitalWrite(startPin, LOW);
      LastTimeNotReady = millis();
    }
  }
  else
  {
    // NOT READY TO START.  Make sure the starter is off
    digitalWrite(startPin, LOW);
    LastTimeNotReady = millis();
  }
}

Have problem, every time when engine started and running and pressed brake pedal, after 2 seconds starter relay working again.

looks like the logic to start engine depends on pulseWidth

where does pulseWidth get set during operation (i.e. after engine is started)?

[quote="keturi, post:16, topic:969856"]

if (pulseWidth == 0 || pulseWidth >= maxPulseWidthRunning)
    {
      // Turn on the starter if everything has been ready for at least 2 seconds
      if (millis() - LastTimeNotReady >= 2000)
        digitalWrite(startPin, HIGH);
    }
    else
    {
      // Engine running.  Turn off the starter
      digitalWrite(startPin, LOW);
      LastTimeNotReady = millis();
    }

I understand, that pulseWidth higher than nominal, stops starter relay, so stop is really working, but should to avoid of start when engine is running. This point not understand why not working.

my mistake, i now see where pulse width is set

what are the conditions that cause the engine to stop?

Engine stops when ignition is off. For stop the engine no need extra projects, stops after press ignition button. Arduino only need for starting.