Canbus controlled relay problems

I'm attempting to take an RPM signal from a car and use it to turn on a relay. Well, kind of a switching point. I'd like to switch the relay on after 3 seconds and when the car has kicked over 500rpm.

The ultimate goal is to make a module to stand in for a transmission control module. I'm swapping a manual transmission into a car that only came automatic.

As of right now I can't get the relay to be activated if I use millis to make a timer or if I use a PID request. If I just activate it, it will work. I feel like I'm probably over looking something simple since I've ridiculously new to both the Arduino and coding.

#include <mcp_can.h>
#include <mcp_can_dfs.h>
#include <Canbus.h>
#include <SPI.h>
#include <OBD.h>

MCP_CAN CAN0(10);

unsigned long currentTCMtime;
unsigned long previousTCMtime;
unsigned long previousPNDtime;
unsigned long currentPNDtime;
int parkrelay = 5;
int engineRPM;
const unsigned long TCMHeartbeat = 10;
const unsigned long waittodrive = 3000;
byte tcmone[8] = {0x00, 0x00, 0x61, 0x02, 0x00, 0x00, 0x00, 0x63};
byte tcmtwo[8] = {0x01, 0xff, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00};

void setup() {

  Serial.begin(115200);
  CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK;
  currentTCMtime = millis();
  currentPNDtime = millis();
  pinMode(parkrelay, OUTPUT);
  CAN0.setMode(MCP_NORMAL);
}

void loop()
{
  tcmheartbeat();
  parkneutraldrive();
}

void tcmheartbeat()
{
  previousTCMtime = 0;
  if (currentTCMtime - previousTCMtime >= TCMHeartbeat)
    previousTCMtime = currentTCMtime;
  CAN0.sendMsgBuf(0x3e9, 0, 8, tcmone);
  CAN0.sendMsgBuf(0xc9, 0, 8, tcmtwo);
}

void parkneutraldrive()
{
  digitalWrite(parkrelay, LOW);
  previousPNDtime = 0;
  int engineRPM;
  char buffer[512];
  {
    if (engineRPM = Canbus.ecu_req(ENGINE_RPM, buffer))
      if ((engineRPM >= 500) || ((currentPNDtime - previousPNDtime) >= waittodrive))
        digitalWrite(parkrelay, HIGH); 
  }
  }

I'm using a Arduino Uno, Arduino Canbus shield v2 and Arduino 4 relay shield.
Am I missing something?

see again the "BlinkWithoutDelay" example.
I assume you need to update currentPNDtime with millis.
additionally you should set your previousPNDtime with the millis.

so more like


void parkneutraldrive()
{
  digitalWrite(parkrelay, LOW);
  //previousPNDtime = 0;  // why zero???
  currentPNDtime = millis(); // get actual millis timestamp
  int engineRPM;
  char buffer[512];
  {
    if (engineRPM = Canbus.ecu_req(ENGINE_RPM, buffer))
      if ((engineRPM >= 500) || ((currentPNDtime - previousPNDtime) >= waittodrive))
      {
        digitalWrite(parkrelay, HIGH); 
        previousPNDtime = currentPNDtime; // remember the timestamp when you have activated the relay
      } 
  }
  }

I put the currentPNDtime = millis line in the original void setup section of the sketch. Not a good idea?

I guess I didn't see the need to reset the previousPNDtime because I only need to trigger the relay once when the car starts. It's just the relay that is the park switch so you can start the car. It's on the NC side so you turn the key on, there is connection, once the car starts it triggers the relay to the NO side. After that I don't need to activate or deactivate the relay again while the ignition is on.

As far as setting previousPNDtime to zero initially, isn't that how the blinkwithoutdelay works? You set a baseline time to compare against?

Thank you.

So I think I'm being foolish here. I was trying to use two different CAN libraries to interact with the car. When I strip out the canbus PID stuff in the last loop it functions as expected. Powers on, waits 3 seconds and shifts the car out of park.

I just haven't grasped the concept of how I can pull RPM signal with only the first library. Can masks/filters be setup inside a loop? As in, instead of the filtering the whole sketch, just when it needs to pay attention to a certain message?

This line seems wrong but maybe you are using a different library. The SparkFun version returns a 'char' for Canbus.ecu_req() so it can never be above 500. Other libraries return 0/1 and the actual data in in buffer

Instead of this you could just take a signal from the oil pressure switch or maybe the alternator to show the engine is running

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.