Hello everyone, first post! Don't spare any thoughts, really trying to get this to work and would like all opinions.
What I'm trying to accomplish is getting vehicle data, starting with engine RPM, through the OBDII port connected to a D9 connector on an MCP2515 CAN shield v2.0 on an Arduino Mega. I've tried to use the wikipedia page for OBDII and the code I'm using (posted below) is cobbled together through several examples I've found from various libraries.
It's not working. Previously I had gotten it to say that it initialized the CAN system, successfully sent the 1 message that's in the code, and initialized masks and filters (the first section just masking true all bits and filtering for only 0x7E8). It'll even receive several messages from the OBDII but they are nonsensical to me and definitely not what I'm trying to request the OBDII to send me. The problem there was, the masks/filters that I put up were letting everything through and I don't know why. Then later I switched vehicles (from GMC Sierra to Honda Accord) with nearly the same code (identical on the sending side) and it kept saying that the sending failed.
I don't know why it's not working, especially why the filter didn't work and then why the messages stopped sending after I switched vehicles. Any help at all would be appreciated. Maybe I should use the second set of masks and filters, found those on a different example.
// Tryna set up a str8 CAN system to read OBDII on our own instead of someone else's bunk BS so we don't gotta wait to get car data
#include <mcp_can.h>
#include <SPI.h>#define CAN0_INT 2 // Set INT to pin 2 - interrupt pin
MCP_CAN CAN0(10); // Set CS to pin 10long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128]; // Array to store serial stringint engineRPM;
void setup() {
Serial.begin(500000);
// READS OUTPUTS WITH 16 MHz and 500KBPS, 500KBPS in terminal window..
if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
else Serial.println("Error Initializing MCP2515...");
pinMode(CAN0_INT, INPUT); // Configuring pin for /INT inputCAN0.init_Mask(0, 0, 0x7FF); // Init first mask (number of instance 1 vs 2, standard 0 vs extended 1, bits of ID to mask)
CAN0.init_Mask(1, 0, 0x7FF); // Init second mask
CAN0.init_Filt(0, 0, 0x7E8); // Init filter OBDII ID:2024 (number of instance 1 thru 7, standard 0 vs extended 1, bits of ID to filter)
// CAN0.init_Filt(1, 0, 0x7E8);
// CAN0.init_Filt(2, 0, 0x7E8);
// CAN0.init_Filt(3, 0, 0x7E8);
// CAN0.init_Filt(4, 0, 0x7E8);
// CAN0.init_Filt(5, 0, 0x7E8);
// CAN0.init_Filt(6, 0, 0x7E8);
// CAN0.init_Filt(7, 0, 0x7E8);// CAN0.init_Mask(0,0,0x7F00000); // Init first mask...
// CAN0.init_Filt(0,0,0x7DF0000); // Init first filter...
// CAN0.init_Filt(1,0,0x7E10000); // Init second filter...
//
// CAN0.init_Mask(1,0,0x7F00000); // Init second mask...
// CAN0.init_Filt(2,0,0x7DF0000); // Init third filter...
// CAN0.init_Filt(3,0,0x7E10000); // Init fouth filter...
// CAN0.init_Filt(4,0,0x7DF0000); // Init fifth filter...
// CAN0.init_Filt(5,0,0x7E10000); // Init sixth filter...CAN0.setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted
}void loop() {
//******************** Sending section *********************** 0x7DF=2015, 0x7E8=2024
byte RPMdata[8] = {2, 1, 12, 0, 0, 0, 0, 0}; // {how many bytes to pay attention to, service PID (1 or 9?), actual PID 0x0C=12, blah}
byte sendRPM = CAN0.sendMsgBuf(2015, 0, 8, RPMdata); // send data: ID = 0x7DF or 2015, Standard CAN Frame = 0 (Ext = 1), Data length = 8 bytes, 'data' = array of data bytes to send
if(sendRPM == CAN_OK){
Serial.println("Message Sent Successfully!");
} else {
Serial.println("Error Sending Message...");
}
delay(200);//************************************************************
//******************** Receiving section ********************* This may get wonky. The ID for all messages might be the same, so they might come from the same ECU and have to run serially. Maybe instead we can find the specific ECU's that send each thing so we can communicate with different addresses???
// - you can't specify that you want to access a certain ECU. You just have to accept messages from the bus with a certain
// identifier. CAN messages don't have addresses, the ID is the flag that tells a controller whether to receive that message.
for (int i=0; i<=10; i++){
// if (!digitalRead(CAN0_INT)) { // If CAN0_INT pin is low, read receive buffer
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)if ((rxId & 0x1FFFFFFF) == 2024) { // reading 0x7E8=2024 response if (rxBuf[2] == 12) { // reading RPM (PID 12 or 0x0C) response engineRPM = ( (256*rxBuf[3]) + (rxBuf[4]) )/4; Serial.print("EngineRPM: "); Serial.println(engineRPM); } } else Serial.println("Didn't get it"); Serial.print("ID: "); Serial.print(rxId); Serial.print(" | Length: "); Serial.println(len); sprintf(msgString, "Data: %d %d %d %d %d %d %d %d", rxBuf[0], rxBuf[1], rxBuf[2], rxBuf[3], rxBuf[4], rxBuf[5], rxBuf[6], rxBuf[7]); Serial.println(msgString);// if ((rxId & 0x1FFFFFFF) == 13) { // reading vehicle speed (PID 13 or 0x0D) response
// vehicleSpeed = rxBuf[0]/1.60934; // convert from kph to mph
// Serial.print("Speed: ");
// Serial.println(vehicleSpeed);
// }
// if ((rxId & 0x1FFFFFFF) == 17) { // reading throttle position (PID 17 or 0x11) response
// throttleValue = 100*rxBuf[0]/255;
// Serial.print("Throttle: ");
// Serial.println(throttleValue);
// }
}
// }
delay(200);
}