Arduino Uno w/ 4 Relay Shield - confuzzled by code

Greetings Y'all.
I'm hoping you can point out my errors in my code that I've been researching and unsuccessful in resolving for the last several months. It's prolly much simpler than I'm making it out to be; please educate me and I'm standing by for feedback.

Thanks for your help,
Eric

Skill level: Simple hobbyist with Noob programming experience.

BLUF: The project is designed to control a high-idle feature in my diesel truck and I'm struggling with the execution sequence of the code included below. Problematically, after several variations of code modification, it's not executing as desired and causing the relays to activate out of the sequence and without the meeting the prescribed conditions.

Original code was used from Droktane's high-idle request github site. ( Ford SEIC controller. I'm attempting to add an input condition that senses when I'm turning on the system via switch and adding a relay that closes the emergency brake light switch to set the condition without the need to enter the vehicle or preset the brake condition and closing a relay that signals the PCM i'm wanting to turn on the high-idle feature and automatically resets the feature if the brake or gas pedal, or other safety stop feature is observed by the PCM.
Disclaimer: there are several other conditions that have to be met before the PCM will set a high idle condition (e.g. has to be in park, the brake pedal and throttle pedal are not touched, engine temps, etc....), therefore a "fooled" emergency brake light condition is not an immediate threat to safety or vehicle operation under the high-idle condition and I understand the personal implications of such practices.

Hardware;

  1. Arduino Uno V3.
  2. Seeedstudio relay shield v2.1 (using relay 1 [pin 7] & relay 2 [pin 6]

Ford Definitions
SEIC = Stationary Elevated Idle Controller
PCM = Powertrain Control Module

Desired flow;
NOTE: Initial 1 min delay is intentional to prevent high-idle condition if I'm looking to start driving after start up. The PCM will reseek input conditions if I put the truck in park and high-idle switch is set to on.

  1. "high-Idle" switch set to "on" (seic_request_pin input = HIGH)
  2. Then activates emergency break switch via relay #1 (emer_relay_pin, output = HIGH)
  3. Delay 10 secs before providing high-idle request input (delay 10000)
  4. Then activates high-idle request via relay #2 (pto_request_pin, output = HIGH)
  5. push message "SEIC Initiated"
  6. awaits for PCM signal shows high-idle active (pto_state_pin, input LOW) [low = on /high = off]
  7. push message "SEIC Active"

**IF SEIC active - (pto_state_pin input = LOW)
8. remain in configured condition and Monitor every sec for change in state of High-idle switch set to off (seic_request_pin input = LOW)
8.a. if high-idle switch is turned off, deactivate high-idle request (pto_request_pin output = LOW) and deactivate emer break switch (emer_relay_pin out=LOW)
8.b. push message "SEIC Deactivated"
8.c. await input from high-idle switch set to "on" (seic_request_pin input = HIGH) reinitiate sequence at step 2.
8.d. Push message "Sleeping..." every 60secs. (not sure how to do this)

**ELSE deactivated while high-idle switch turned on and without command- (seic_request_pin input = HIGH & pto_state_pin input = LOW)
9. reset activation condition
9.a. push message "SEIC was interrupted, restarting in 8 seconds..."
9.b. deactivate high-idle request (seic_request_pin output = LOW)
9.c. deactivate emer brake relay (emer_relay_pin outout = LOW)
9.d. delay 5 secs (delay 5000)
9.e. activate emer brake relay (emer_relay_pin output = HIGH)
9.f. delay 5 secs (delay 3000)
9.g. activate high-idle request (seic_request_pin output = HIGH)
9.h. push message "SEIC reactivated, high-idle should resume shortly"
9.i. await PCM signal showing high-idle activated (pto_state_pin input = LOW)
9.j. if good, push message "SEIC Active"

-------------------------------------------------------------------code ------------------------------------------------------------

// High Idle Auto Resume TEST

const int seic_request_pin = 2; //turning it on/off
const int pto_state_pin = 3;    //PCM feedback state LOW/HIGH
const int emer_relay_pin = 5;   //relay closing emergency brake light swich circuit
const int pto_request_pin = 6;  //relay activating high-idle request to PCM

// Variables will change:
int ptoState = 0;         // current state of the pto
int lastptoState = 0;     // previous state of the pto
int seicState = 0;
int lastseicState = 0;

void setup() {
  pinMode(seic_request_pin, INPUT); 
  pinMode(pto_state_pin, INPUT);       
  pinMode(pto_request_pin, OUTPUT); 
  pinMode(emer_relay_pin, OUTPUT);  
  Serial.begin(9600);  
  delay(60000);
}

void loop() {
// read seic switch state
    seicState = digitalRead(seic_request_pin);
    if (seicState == HIGH) {
        digitalWrite(emer_relay_pin, HIGH);
        delay (10000);
        digitalWrite(pto_request_pin, HIGH);
        Serial.println ("SEIC Initiated");
        ptoState = digitalRead(pto_state_pin);
        // compare the ptoState to its previous state
          if (ptoState == LOW) {
            // if the current state is LOW then the PTO is ok
            // went from off to on:
            Serial.println("SEIC Active");
            delay(1000);
            } 
          else {
            // if the current state is High then the pto
            // went from on to off:
            lastptoState = ptoState;
            // the modulo function gives you the remainder of 
            // the division of two numbers:
              if (ptoState == HIGH) {
                digitalWrite(pto_request_pin, LOW);
                Serial.println("SEIC was interrupted, restarting in 8 seconds...");
                delay(5000); 
                digitalWrite(pto_request_pin, HIGH);
                Serial.println("SEIC reactivated, high-idle should resume shortly");
                delay(3000);
              }
              else {
                digitalWrite(pto_request_pin, LOW);
                delay(1000);
              }    
          }
    }
      else {
        digitalWrite(pto_request_pin, LOW);
        digitalWrite(emer_relay_pin, LOW);
        Serial.println ("SEIC Deactivated");
        Serial.println ("Sleeping");
        delay(1000);
        }
      }



void loop() {
// read seic switch state
    seicState = digitalRead(seic_request_pin);
    if (seicState == HIGH) {
        digitalWrite(emer_relay_pin, HIGH);
        delay (10000);
        digitalWrite(pto_request_pin, HIGH);
        Serial.println ("SEIC Initiated");
        ptoState = digitalRead(pto_state_pin);
        // compare the ptoState to its previous state
          if (ptoState == LOW) {
            // if the current state is LOW then the PTO is ok
            // went from off to on:
            Serial.println("SEIC Active");
            delay(1000);
            } 
          else {
            // if the current state is High then the pto
            // went from on to off:
            lastptoState = ptoState;
            // the modulo function gives you the remainder of 
            // the division of two numbers:
**              if (ptoState == HIGH) {
                digitalWrite(pto_request_pin, LOW);
                Serial.println("SEIC was interrupted, restarting in 8 seconds...");
                delay(5000); 
 *1               digitalWrite(pto_request_pin, HIGH);
                Serial.println("SEIC reactivated, high-idle should resume shortly");
                delay(3000);
  **            }
  **           else {
  **              digitalWrite(pto_request_pin, LOW);
  **              delay(1000);
  **            }    
          }
    }
      else {
        digitalWrite(pto_request_pin, LOW);
        digitalWrite(emer_relay_pin, LOW);
        Serial.println ("SEIC Deactivated");
        Serial.println ("Sleeping");
        delay(1000);
        }
      }

Just to point out what appear to be a couple of simple points:

The lines I've marked with ** are, I believe, redundant as you have already got an answer to the if question higher up.

The line mark *1 does not appear to agree with you description earlier as it is using pto_request_pin but looks as though it should be emer_relay_pin

1 Like

Thanks, I'll give this a try and let you know what comes of it.

Ok CountryPaul,

The recommendations you suggested got me 95% closer. Huge thanks man!

SO the other 5% is mere flow and messages as it does what I'm looking for it to do, but seems to cycle through sections (messages in # 3 & action delay in #4) of the code before performing the desired action.

Observed flow.

  1. (seic_request_pin = LOW / pto_state_pin = HIGH) = "SEIC Deactivated" [Ops Check Good]
  2. (seic_request_pin = HIGH / pto_state_pin = HIGH) = SEIC Initiated" activates emer brake relay (emer_relay_pin = HIGH) and cycles through interrupt sequence until PCM messages high-idle activated (pto_state_pin = LOW) [OCG]
    1. (seic_request_pin = HIGH / pto_state_pin = LOW) runs the "SEIC Initiated" and "SEIC Active" messages repeatedly untill the state changes.
      Question - how do I get it to Push "SEIC Initiated" once after initial on (seic_request_pin = HIGH) and repeats "SEIC Active" only?
  1. (seic_request_pin = LOW / pto_state_pin = LOW) appears to cycle through the actions as described in *3 any where between two and three times before recognizing the switch was turned off before running the shutdown sequence (emer_relay_pin = LOW and messages "SEIC Deactivated").
    Question - how do I get the code to recognize the on/off switch (seic_request_pin INPUT) immediately while in "SEIC Active" or "SEIC Deactivated" states?

I'm sure it's something with my code delays, just spent the last two days trying to figure it out and not trying to make it worse LOL.

// High Idle Auto Resume TEST - V2 (CountryPaul suggestions)

const int seic_request_pin = 2; //turning it on/off
const int pto_state_pin = 3;    //PCM feedback state LOW/HIGH
const int emer_relay_pin = 5;   //relay closing emergency brake light swich circuit
const int pto_request_pin = 6;  //relay activating high-idle request to PCM

// Variables will change:
int ptoState = 0;         // current state of the pto
int lastptoState = 0;     // previous state of the pto
int seicState = 0;
int lastseicState = 0;

void setup() {
  pinMode(seic_request_pin, INPUT); 
  pinMode(pto_state_pin, INPUT);       
  pinMode(pto_request_pin, OUTPUT); 
  pinMode(emer_relay_pin, OUTPUT);  
  Serial.begin(9600);  
  delay(60000);
}

void loop() {
// read seic switch state
    seicState = digitalRead(seic_request_pin);
    if (seicState == HIGH) {
        digitalWrite(emer_relay_pin, HIGH);
        delay (10000);
        digitalWrite(pto_request_pin, HIGH);
        Serial.println ("SEIC Initiated");
        ptoState = digitalRead(pto_state_pin);
        // compare the ptoState to its previous state
          if (ptoState == LOW) {
            // if the current state is LOW then the PTO is ok
            // went from off to on:
            Serial.println("SEIC Active");
            delay(1000);
            } 
          else {
            // if the current state is High then the pto
            // went from on to off:
            lastptoState = ptoState;
            // the modulo function gives you the remainder of 
            // the division of two numbers:
                digitalWrite(pto_request_pin, LOW);
                Serial.println("SEIC was interrupted, restarting in 8 seconds...");
                delay(5000); 
                digitalWrite(pto_request_pin, HIGH);
                Serial.println("SEIC reactivated, high-idle should resume shortly");
                delay(3000);
              }    
          }
        else {
        digitalWrite(pto_request_pin, LOW);
        digitalWrite(emer_relay_pin, LOW);
        Serial.println ("SEIC Deactivated");
        delay(10000);
        }
      }

I can't see anything obvious in your code other than perhaps your use of delay. Quote "No other reading of sensors, mathematical calculations, or pin manipulation can go on during the delay function, so in effect, it brings most other activity to a halt." You may have to look at alternatives to delay, for a better explanation see delay() - Arduino Reference

You may have to loop around the "SEIC Active" section using millis rather than delay.

1 Like