Page 1 of 1

Ignition simulation with canbus

Posted: 20 Apr 2019, 08:14
by Gwe89
Hi can any one help me please I'm having trouble getting this to work I want it to switch the relay on when it receives the canbus id and data and off when it no longer receives the canbus id and data, this is to simulate an ignition live so I can power up/down a DVD multi media system I have put in my car for my kids, if I leave it plugged in the battery will go flat and that's not good when we are out, and help would be much appreciated thanks

Code: Select all

#include <SPI.h>
#include "mcp_can.h"
#define INT32U unsigned long int
INT32U canId = 0x00;

unsigned char len = 0;
unsigned char buf[8];
char str[20];

String CanMessage="";
int IgnitionDetected=0;
int RelayCHN01=4;
const int SPI_CS_PIN = 17;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


void setup()
{
     //INIT RELAY PIN
     pinMode(RelayCHN01, OUTPUT);
     //TEST RELAY PIN
     TESTRElay();
    Serial.begin(115200);

START_INIT:

    if(CAN_OK == CAN.begin(CAN_125KBPS))
    {
        Serial.println("CAN BUS Shield init ok!");
    }
    else
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println("Init CAN BUS Shield again");
        delay(100);
        //goto START_INIT;
    }
}


void loop()
{
    if(CAN_MSGAVAIL == CAN.checkReceive())  
    {
        CAN.readMsgBuf(&len, buf); 
        CanMessage="";
        canId = CAN.getCanId();
        
        //Detect Ignition
        if (canId==0x0048)
        {
          //Build Complete Message Without CAN ID From BUS
          for(int i = 0; i<len; i++)    // print the data
          {
            CanMessage = CanMessage + buf;
          }
          
          if (CanMessage=="0XFF, 0x07, 0x6C, 0x09, 0x27, 0x02, 0xE0"){IgnitionDetected=1;}else{IgnitionDetected=0;}
         
          if (IgnitionDetected==1)
          {
            //PUT CODE HERE To TURN ON Relay
            Serial.println("Relay turned on!!!!!");
            digitalWrite(RelayCHN01, HIGH);
          } 
          else
          {
           digitalWrite(RelayCHN01, LOW); 
          }
        }
  
    }
}

void TESTRElay()
{
digitalWrite(RelayCHN01, HIGH);
delay(200);
digitalWrite(RelayCHN01, LOW);
delay(200);
digitalWrite(RelayCHN01, HIGH);
delay(200);
digitalWrite(RelayCHN01, LOW);
delay(200);

}

Re: Ignition simulation with canbus

Posted: 20 Apr 2019, 15:46
by Go4IT
I'm so sorry to say this Gew89, but your code is awful... and also totally wrong :?
Because this is a standard scenario let's see how this could be done in a semi-professional way.

Prior to any coding, define the problem first!
A digital output should be switched accordingly on the content of a CAN message. In your case, the ignition status of the Mondeo MK4.
If the ignition is on (even car is not startet, so this is ignition POS 1) the digital output should go HIGH. If the ignition is turned off (POS 0) the digital output should go LOW immediately. If this is what you want then the DVD Enterntainment system is only available if ingition is on or while driving. No change to start it while waiting in the car. Otherwise is may be coupled to the radio on status, so if radio is on, the DVD system is powered too, if radio is off it turns off also.

The next thing to think about is the sleep mode of the module itself. It should not be powered all the time, even if it only draws 100 mA or such. Like every other CAN module it should go into sleep and deep sleep mode. This could be handled with CAN-NM (network management) or simply by watching the CAN bus. If the CAN message we are wachting for does not repeat after the usual interval, the module itself could switch off and awake on the first CAN message received.

Considerations to be done for the module to build:
* Which processor to use? Atmega (Arduino) or any other like PIC, STM32, LPC11..
* Which power supply to use? Which voltage(s) and current is needed?
* Which output stage to use? Relay, and driver for it.
* Where to place the module? Is CAN-Bus and car power available there? What kind is the car power? Permanent, switched?
* On which CAN-Bus to connect?

Re: Ignition simulation with canbus

Posted: 20 Apr 2019, 16:02
by Gwe89
I'm no good with writing code all i want it to do is turn the relay on when it receives ignition canbus message and off when it no longer sees this data , it wont need to go to sleep it will when the car powers down having an arduino powered in the 15mins time prior to shut down will use less power than a DVD system still powered for the 15mins before shutdown I want to add everything to this like my gateway videoin adapter so the all shut down when I turn the ignition off not after the 15min shutdown never mind I will just have find someone I can pay to write the code,

Re: Ignition simulation with canbus

Posted: 22 Apr 2019, 23:03
by bigi
I am tying to teach myself to code arduino at the moment, so am interested in this and attempting to understand the steps needed to do what gwe89 is wanting to do- and trying to help him in the process! What i am putting here with form something of a "brain dump" or what i think I understand - so please feel free to rubbish what i say below if wrong :)

Working on the basis that we will use (for example) and arduino nano, with an MCP2515 CAN shield and a buck regulator:

I would suspect that the best approach to this would be to use an interrupt on the CAN shield to allow it to sleep until it received a can message as opposed to a loop to constantly monitor.
Further reduction in processing could be done by implementing masks and filters to only listen for the ignition code on the can interface - mask 0x07FF0000, filter 0x0[ignition ID]
From there a check for matching data could force the relay digital pin high to enable the relay.

the only part i'm not sure about at the moment is if you are waiting for a matching CAN signal for ingnition sense to perform any action, what you would do to turn the relay off - other than if there is an ignition off signal.

I am assuming that you would use sleep mode to save power until the needed interrupt (can ID) is found.

please feel free to tell me whats wrong! :)

Re: Ignition simulation with canbus

Posted: 23 Apr 2019, 05:25
by Go4IT
You are on the right track. The answer to the question how to react on the signal, also depends on the signal itself. For Ford Mondeo MK4 the Ignition-States are send on MS-CAN ID 048, Byte D3 every 60 ms.
Let's analyze the values i found here are:
0x20 = 0b0010 0000 = ignition off
0x21 = 0b0010 0001 = ignition off
0x22 = 0b0010 0010 = key inserted (not for Keyless-Go system)
0x24 = 0b0010 0100 = key turned from POS 0 to POS I (radios goes on and such)
0x25 = 0b0010 0101 = POS I - transition from turning off running motor
0x26 = 0b0010 0110 = Ignition on - POS II
0x27 = 0b0010 0111 = Engine running - POS II
0x29 = 0b0010 1001 = cranking - POS III

I don't find an exact pattern to macht bits to different states, so for now we could simply compare the values to drive a relay:
IGN_ON = ( D3 >= 0x24 ) && ( D3 <= 0x27 ) ;
This would result in the relay behaving like the headlamps, they go off while cranking to safe power of battery.
Maybe some applications need not to shutdown so the equation shorts to:
IGN_ON = D3 >= 0x24 ;

Re: Ignition simulation with canbus

Posted: 23 Apr 2019, 23:21
by bigi
thanks for the info :)

So, this is my first attempt - I am assuming that after the ignition off can signals are sent they will eventually stop and enter sleep, at which point the relay will have turned off and the whole setup will go into sleep mode until it receives the right canbus signal to wake up again. I've used an interrupt to trigger the relay function every 60ms although i suspect that may need tweaking. I was not sure if I should replace the if...then...else with a while condition instead? I've also used the reverse camera code you recently published as a basis for the sleep control - although i worry that sending to sleep will render the relay pin Low and therefore turn it off or even cause some chatter? I have also used volatile variables for everything although i suspect i don't need to! Lots of questions...but i'll just put my code here to be scrutinized - after all if you don't try you don't learn :)

**UPDATED typos and bugs - code compiles without error now at least... :D

/*
* CAN Based ignition simulator v0.2
* Simulates ignition on to drive relay to power device on and off
* Designed for Ford Mondeo Mk4, CAN ID 0x048 for ignition state
* (c) 2019 Ian Rushton
*/
#include <SPI.h>
#include <mcp_can.h>
#include <TimerOne.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

volatile long unsigned int BusID; // CAN ID of received info
volatile unsigned char len = 0; // received message DLC
volatile unsigned char Busbuffer [8]; // array to store 8 byte CAN message
volatile byte RelayState = LOW; // byte used to to store relay state
volatile unsigned int RelayPin = 8; // Pin to which relay trigger is attached
volatile unsigned long RelayDelay; // Used to store timer info to Interrupt

// * Define board connections

#define MSCAN_INT_PIN 2 // Interrupt pin for MSCAN_INT_PIN

MCP_CAN MSCAN(10); // Cable Select pin for MS-CAN

void setup ()
{
// * Setup MS-CAN shield to only read CAN ID 0x048
MSCAN.begin (MCP_STDEXT, CAN_125KBPS, MCP_8MHZ); //change to MCP_16MHZ for 16MHz crystal board
MSCAN.setMode (MODE_CONFIG);
MSCAN.init_Mask (0,0,0x07FF0000);
MSCAN.init_Filt (0.0,0x00480000);
MSCAN.init_Mask (1,0,0x07FF0000);
MSCAN.init_Filt (0,0,0x00480000);
MSCAN.setMode (MCP_LISTENONLY);

// * Configure Relay settings
pinMode (RelayPin, OUTPUT); // Configure Relay pin as an output port
digitalWrite(RelayPin, RelayState); //Set initial state of relay to Low (Off)

// * Initialise timer for relay state.
RelayDelay = 60; // Relay Delay set for 60ms
Timer1.initialize (RelayDelay);
Timer1.attachInterrupt (relay_int);

// * Initialise MS_CAN shield /INT pin
pinMode (digitalPinToInterrupt (MSCAN_INT_PIN), INPUT_PULLUP);
// If /INT of MS-CAN shield goes low, read message from bus (wakeup from sleep)
attachInterrupt (digitalPinToInterrupt (MSCAN_INT_PIN), mscan_init, LOW);
// Configure watchdog to restart module if WD timer not reset properly from loop (set to 8secs)
wdt_enable (WDTO_8S);
}

// * ISR for MS-CAN incoming message ID 0x048
void mscan_init ()
{
wdt_enable (WDTO_8S);
wdt_reset ();
MSCAN.readMsgBuf (& BusID, len, Busbuffer);
set_sleep_mode (SLEEP_MODE_IDLE);
}
// * ISR for Relay Control
void relay_int ()
{
wdt_reset ();
// Confirm CanBUS message received
if ((Busbuffer [3] >=0x24) && (Busbuffer [3] <=0x27)) // Byte D3 between 0x24>0x27 - Ignition On
{
RelayState = HIGH; // Set Relay state to High (On)
}
else if ((Busbuffer [3] == 0x20) || (Busbuffer [3] == 0x21) ) // Signal of Ignition Off
{
RelayState = LOW; // Set Relay state to Low (Off)
}
else
{
RelayState = RelayState; // In all other conditions, leave RelayState unchanged
}
digitalWrite (RelayPin, RelayState); // Write result to Relay output pin
}

// * Main Program Loop
void loop ()
{
sleep_enable();
sleep_mode ();
sleep_disable ();
}

Re: Ignition simulation with canbus

Posted: 25 Apr 2019, 19:03
by bigi
so I have made some adjustments to the code after working with gwe89 - it appears the code successfully detects and responds to ignition on and off signals - and the relay behaves as expected :D

Initially the code was not detecting the iginition codes, and when i added some debug output, it showed me the problem - and a query @go4it :)

You mentioned that byte D3 held the ignition sense code, but the ignition code needed is below:

0048FF076C092702E0A0

Id ID 0048, Data 0xFF, 0x07, 0x6C, 0x09, 0x27, 0x02, 0xE0, 0xA0

I assume this is to do with the Endian-ness of the transmission - but the problem is that the array is storing the data D0-D7 but it's actually being read in D7-D0, so to access the correct data i need to reference D5! is there a way to resolve this, or am i doing something wrong!

Would also appreciate anyone's comments about the sleep states and how i'm handling the relay switching - this is very much a learning process so all input welcomed! :)

/*
* CAN Based ignition simulator v0.5
* Simulates ignition on to drive relay to power device on and off
* Designed for Ford Mondeo Mk4, CAN ID 0x048 for ignition state
* (c) 2019 Ian Rushton
*/
#include <SPI.h>
#include <mcp_can.h>
#include <TimerOne.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

volatile long unsigned int BusID; // CAN ID of received info
volatile unsigned char len = 0; // received message DLC
volatile char Busbuffer [8]; // array to store 8 byte CAN message
volatile byte RelayState = HIGH; // byte used to to store relay state, set to High (OFF)
volatile unsigned int RelayPin = 8; // Pin to which relay trigger is attached
volatile unsigned long RelayDelay; // Used to store timer info to Interrupt

// * Define board connections

#define MSCAN_INT_PIN 2 // Interrupt pin for MSCAN_INT_PIN

MCP_CAN MSCAN(10); // Cable Select pin for MS-CAN

void setup ()
{
// * Configure Serial Baud Rate
Serial.begin (9600);

// * Setup MS-CAN shield to only read CAN ID 0x048
MSCAN.begin (MCP_STDEXT, CAN_125KBPS, MCP_8MHZ); //change to MCP_16MHZ for 16MHz crystal board
MSCAN.setMode (MODE_CONFIG);
MSCAN.init_Mask (0,0,0x07FF0000);
MSCAN.init_Filt (0,0,0x00480000);
MSCAN.init_Mask (1,0,0x07FF0000);
MSCAN.init_Filt (0,0,0x00480000);
MSCAN.setMode (MCP_LISTENONLY);

// * Configure Relay settings
pinMode (RelayPin, OUTPUT); // Configure Relay pin as an output port
digitalWrite(RelayPin, RelayState); //Set initial state of relay to High (Off)

// * Initialise timer for relay state.
RelayDelay = 60; // Relay Delay set for 60ms
Timer1.initialize (RelayDelay);
Timer1.attachInterrupt (relay_int);

// * Initialise MS_CAN shield /INT pin
pinMode (digitalPinToInterrupt (MSCAN_INT_PIN), INPUT_PULLUP);
// If /INT of MS-CAN shield goes low, read message from bus (wakeup from sleep)
attachInterrupt (digitalPinToInterrupt (MSCAN_INT_PIN), mscan_init, LOW);
// Configure watchdog to restart module if WD timer not reset properly from loop (set to 8secs)
wdt_enable (WDTO_8S);
}

// * ISR for MS-CAN incoming message ID 0x048
void mscan_init ()
{
wdt_enable (WDTO_8S);
wdt_reset ();
MSCAN.readMsgBuf (& BusID, len, Busbuffer);
set_sleep_mode (SLEEP_MODE_IDLE);
}
// * ISR for Relay Control
void relay_int ()
{
wdt_reset ();
// Confirm CanBUS message received
if ((Busbuffer [4] >=0x24) && (Busbuffer [4] <=0x27)) // Byte D5 between 0x24>0x27 - Ignition On
{
/* Serial.print("Ignition State detected, contents of Byte 5 : 0x");
Serial.print(Busbuffer [4], HEX); */
RelayState = LOW; // Set Relay state to Low (On)
}
else if ((Busbuffer [4] == 0x20) || (Busbuffer [4] == 0x21) ) // Signal of Ignition Off
{

/* Serial.print("Ignition Off detected, contents of Byte 5 : 0x");
Serial.print(Busbuffer [4], HEX); */
RelayState = HIGH; // Set Relay state to High (Off)
}
else
{
/* Serial.print("Ignition State indeterminate, contents of Byte 5 : 0x");
Serial.print(Busbuffer [4], HEX); */
RelayState = RelayState; // In all other conditions, leave RelayState unchanged
}
digitalWrite (RelayPin, RelayState); // Write result to Relay output pin
}

// * Main Program Loop
void loop ()
{
sleep_enable();
sleep_mode ();
sleep_disable ();
}