I’m about to try and connect my CANXtra to my car’s OBDII connector. I still have some doubts:
Do the CAN1H and CAN1L from pin 24/25 of the DB25 connect to CAN H and CAN L on the ODBII connector or should they be switched like a serial connection (rx to tx and tx to rx)
I should also connect the car’s GND to the CANXtra right?
the good news is that I managed to receive some data. 126 packets of 8 bytes (below are the first 20 packets)
The bad news is that I have no clue how to interpret that data. Can someone jump in here?
Data: (Don’t look at the date because I forgot to update the time on the CANXtra)
MSG: ID = 896 at time = 02/14/2011 00:02:14
30 B3 82 00 84 02 04 81
MSG: ID = 897 at time = 02/14/2011 00:02:14
15 40 88 00 43 00 40 04
MSG: ID = 1088 at time = 02/14/2011 00:02:14
00 00 00 00 00 00 04 81
MSG: ID = 1184 at time = 02/14/2011 00:02:14
00 00 72 57 40 00 40 04
MSG: ID = 1329 at time = 02/14/2011 00:02:14
03 00 28 01 01 00 04 81
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 8A 7F FF 6E 00 40 04
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 9C 7F FF 78 00 04 81
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 66 7F FF 82 00 40 04
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 68 7F FF 8C 00 04 81
MSG: ID = 320 at time = 02/14/2011 00:02:14
81 03 20 FC DF 00 00 00
MSG: ID = 640 at time = 02/14/2011 00:02:14
00 00 00 00 00 00 00 00
MSG: ID = 899 at time = 02/14/2011 00:02:14
9A 60 A0 00 00 00 00 00
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 72 7F FF 96 00 00 00
MSG: ID = 320 at time = 02/14/2011 00:02:14
82 03 20 FC DE 00 00 00
MSG: ID = 640 at time = 02/14/2011 00:02:14
00 00 00 00 00 00 00 00
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 44 7F FF A0 00 00 00
MSG: ID = 320 at time = 02/14/2011 00:02:14
83 03 20 FC DD 00 00 00
MSG: ID = 640 at time = 02/14/2011 00:02:14
00 00 00 00 00 00 00 00
MSG: ID = 384 at time = 02/14/2011 00:02:14
64 4E 7F FF AA 00 00 00
MSG: ID = 320 at time = 02/14/2011 00:02:14
80 03 20 FC E0 00 00 00
MSG: ID = 392 at time = 02/14/2011 00:02:14
00 00 0F FD AA 00 00 00
Go to gadgeteer.codeplex.com and get the Gadgeteer driver source for the OBD II module. All sorts of code for processing the data. I think you have to get all the Gadgeteer source…
Mike, I don’t think that is relevant because the OBD II module uses an ELM 327, which the CANXtra does not have.
The ELM327 has the protocols build in.
I will instead give the datasheet of the ELM327 a look in the hope to get something useful out of it.
First of all, I’m getting data back, so I can assume my connections are correct.
2nd: This is my first experience with the CAN bus and so far i haven’t got much luck.
From what I understood, there are 2 ways to get data: 1) Read the date as is is transmitted, 2) Request for specific PID’s
It’s the 2nd option I’m trying. I’m trying to read the Engine coolant temperature which is Mode 01 (hex) PID 05 (hex).
My code for requesting this data is:
public class Program
{
// Messages list
static CAN.Message[] msgList;
static CAN.Message[] RequestMsg = new CAN.Message[1];
static bool NetworkCableConnected = false;
const byte ENGINE_COOLANT_TEMP = 0x05;
public static void Main()
{
// Set the system time. CAN messages will have a time stamp
NetworkCableConnected = Ethernet.IsCableConnected;
if (NetworkCableConnected)
{
RealTimeClock.SetTime(NtpClient.GetNetworkTime());
}
Utility.SetLocalTime(RealTimeClock.GetTime());
Debug.Print(DateTime.Now.ToString());
Configuration.DebugInterface.Set(Configuration.DebugInterface.Port.Sockets1, Configuration.DebugInterface.Port.USB1);
int T1, T2, BRP;
// These numbers were calculated using the calculator on this link:
// http://www.kvaser.com/en/about-can/the-can-protocol/22.html
// We used the very first value from the calculator output
/////////////////////////////////////////////////////////////////////////////////////////////
// Bitrate 250 kbit/s
// CLK = 72 MHz, with BRP = 12 -> 6 MHz CAN clock
// 6 MHz/250 kbit/s = 24 TQ
// T1 = 16 minus 1 for sync = 15
// T2 = 8
// 15 + 1 + 8 = 24 TQs which is what we need
/////////////////////////////////////////////////////////////////////////////////////////////
// Uncomment to use this bit timing
//BRP = 12;
//T1 = 15;
//T2 = 8;
/////////////////////////////////////////////////////////////////////////////////////////////
// Bitrate 125 kbit/s
// CLK = 72 MHz, with BRP = 24 -> 3 MHz CAN clock
// 3 MHz/125 kbit/s = 24 TQ
// T1 = 16 minus 1 for sync = 15
// T2 = 8
// 15 + 1 + 8 = 24 TQs which is what we need
/////////////////////////////////////////////////////////////////////////////////////////////
// Uncomment to use this bit timing
BRP = 6;
T1 = 15;
T2 = 8;
// For 500 kbit/s you can use BRP=6 and for 1 Mbit/s you can use BRP=3 ...and so on
// Use channel 1
CAN can = new CAN(CAN.Channel.Channel_1,
(uint)(((T2 - 1) << 20) |
((T1 - 1) << 16) |
((BRP - 1) << 0))
);
// Create a message list of 126 messages
msgList = new CAN.Message[126];
for (int i = 0; i < msgList.Length; i++)
msgList[i] = new CAN.Message();
// Subscribe to events
//can.DataReceivedEvent += new CANDataReceivedEventHandler(can_DataReceivedEvent);
//can.ErrorReceivedEvent += new CANErrorReceivedEventHandler(can_ErrorReceivedEvent);
float engine_data;
// Example for sending one message
// msg ID
RequestMsg[0] = new CAN.Message();
//RequestMsg[0].ArbID = 0x7DF;
RequestMsg[0].Data[0] = 0x01;
RequestMsg[0].Data[1] = 0x05;
RequestMsg[0].Data[2] = 0x00;
RequestMsg[0].Data[3] = 0x00;
RequestMsg[0].Data[4] = 0x00;
RequestMsg[0].Data[5] = 0x00;
RequestMsg[0].Data[6] = 0x00;
RequestMsg[0].Data[7] = 0x00;
// Send the 8 bytes for example
//RequestMsg[0].DLC = 8;
//RequestMsg[0].IsEID = false;
//RequestMsg[0].IsRTR = false;
// Send one message
int numberOfMessagesPosted = can.PostMessages(RequestMsg, 0, 1);
Debug.Print("Transmit Errors: " + can.TransmitErrorCount);
if (can.GetMessages(msgList, 0, msgList.Length) > 0)
{
for (int i = 0; i < msgList.Length; i++)
{
Debug.Print("Pos: " + i + " Bytes: " + PrintBytes(msgList[i].Data) + " Hex: " + BytesToHex(msgList[i].Data));
switch (msgList[i].Data[2])
{
case ENGINE_COOLANT_TEMP:
engine_data = msgList[i].Data[3] - 40;
Debug.Print("Coolant Temp: " + engine_data.ToString());
break;
default:
break;
}
}
Debug.Print("CAN Done");
}
// Sleep forever
Thread.Sleep(Timeout.Infinite);
}
private static string BytesToHex(byte[] b)
{
string x = string.Empty;
for (int i = 0; i < b.Length; i++)
{
x += FromByteToHex(b[i]);
if (i < b.Length)
{
x += " ";
}
}
return x;
}
private static string PrintBytes(byte[] b)
{
string x = string.Empty;
for (int i = 0; i < b.Length; i++)
{
x += b[i];
if (i < b.Length)
{
x += " ";
}
}
return x;
}
static readonly string hex = "0123456789ABCDEF";
/// <summary>
/// Converts Byte to a Hexadecimal string, like .ToString("X2") would do;
/// </summary>
/// <param name="number">Byte to represent has a hexadecimal string.</param>
/// <returns>2 character string of hexadecimal representation of the number</returns>
public static string FromByteToHex(byte number)
{
return new string(new char[] { hex[(number & 0xF0) >> 4], hex[number & 0x0F] });
}
}
@ Brett, and anyone else who’s interested in OBD-II, I got it working
Now, let me ask this: OBD-II works with PID numbers, and the 1st PID of every Mode (0x0100 means Mode 01 PID 00, there are 10 modes in total) contains a bit-masked DWord (32 bits) of the supported PID’s.
For example: (hope the layout keeps it readable)
B E 1 F A 8 1 3
---- ---- ---- ---- ---- ---- ---- ----------
Every PID has a description, and what I would like to do is when you read this PID, show all the supported PID’s with their description.
Is a HashTable the way to go here?
Brett, I use something similar to this to interface OBD-II with my smartphone. It could be a good wireless option for interfacing with a FEZ also. That port isn’t exactly in a great spot.
Thanks Ian; part of the appeal with CANxtra direct is there is no need to use the ELM chip and that potentially filters stuff you may not want (probably more correctly, it can’t handle stuff you may want so you can’t get to). Don’t get me wrong, buying stuff out of interest’s sake is a-ok with me
I think all I need is a connector plus some cable; yeah cable is never fun when you can have wireless right plus I agree, locaiton of OBD ports on the car is another potential challenge - a 1yr old Subaru Forester that I have not even thought about pulling the dash covers off, well since my last thought about buying a connector
Eric, snap a pic of your setup when you plug it in next
And nobody forget about Eric’s question… it’s just fallen off the current page so here it is:
[quote]Now, let me ask this: OBD-II works with PID numbers, and the 1st PID of every Mode (0x0100 means Mode 01 PID 00, there are 10 modes in total) contains a bit-masked DWord (32 bits) of the supported PID’s.
For example: (hope the layout keeps it readable)
Every PID has a description, and what I would like to do is when you read this PID, show all the supported PID’s with their description.
Is a HashTable the way to go here?[/quote]
These are the PID’s supported by my car (The ones with TRUE at the end)
A bit disappointing that only 11 pid’s are supported. Most of the other info is also available, though it’s proprietary Opel and not documented (at least not on the internet)
07/31/2012 16:21:18
Valid OBD-II PID reply
Supported PID mask: -1740963823
Mask: 10011000001110110000000000010001 0x01 - STATUS_DTC - Status since DTC Cleared >>> TRUE
0x02 - FREEZE_DTC - Freeze Diagnostic Trouble Code >>> FALSE
0x03 - FUEL_SYS_STATUS - Fuel System Status >>> FALSE 0x04 - ENGINE_LOAD - Calculated Engine Load >>> TRUE
0x05 - ENGINE_COOLANT_TEMP - Engine Coolant Temperature >>> TRUE
0x06 - ST_FUEL_TRIM_1 - Short Term Fuel % Trim - Bank 1 >>> FALSE
0x07 - LT_FUEL_TRIM_1 - Long Term Fuel % Trim - Bank 1 >>> FALSE
0x08 - ST_FUEL_TRIM_2 - Short Term Fuel % Trim - Bank 2 >>> FALSE
0x09 - LT_FUEL_TRIM_2 - Long Term Fuel % Trim - Bank 2 >>> FALSE
0x0A - FUEL_PRESSURE - Fuel Pressure >>> FALSE 0x0B - INTAKE_PRESSURE - Intake Manifold Absolute Pressure >>> TRUE
0x0C - ENGINE_RPM - Engine RPM >>> TRUE
0x0D - VEHICLE_SPEED - Vehicle Speed >>> TRUE
0x0E - TIMING_ADVANCE - Timing Advance >>> FALSE 0x0F - INTAKE_TEMP - Intake Air Temperature >>> TRUE
0x10 - MAF_SENSOR - MAF Sensor Air Flow Rate >>> TRUE
0x11 - THROTTLE - Throttle Position >>> FALSE
0x12 - COMMANDED_SEC_AIR - Commanded Secondary Air Status >>> FALSE
0x13 - O2_SENS_PRES - Detected O2 Sensors >>> FALSE
0x14 - O2_B1S1_VOLTAGE - O2 Sensor Voltage - Bank 1 Sensor 1 >>> FALSE
0x15 - O2_B1S2_VOLTAGE - O2 Sensor Voltage - Bank 1 Sensor 2 >>> FALSE
0x16 - O2_B1S3_VOLTAGE - O2 Sensor Voltage - Bank 1 Sensor 3 >>> FALSE
0x17 - O2_B1S4_VOLTAGE - O2 Sensor Voltage - Bank 1 Sensor 4 >>> FALSE
0x18 - O2_B2S1_VOLTAGE - O2 Sensor Voltage - Bank 2 Sensor 1 >>> FALSE
0x19 - O2_B2S2_VOLTAGE - O2 Sensor Voltage - Bank 2 Sensor 2 >>> FALSE
0x1A - O2_B2S3_VOLTAGE - O2 Sensor Voltage - Bank 2 Sensor 3 >>> FALSE
0x1B - O2_B2S4_VOLTAGE - O2 Sensor Voltage - Bank 2 Sensor 4 >>> FALSE 0x1C - OBDII_STANDARDS - Supported OBDII Standards >>> TRUE
0x1D - O2_SENS_PRES_ALT - Detected O2 Sensors - Alternate Grouping >>> FALSE
0x1E - AUX_IN_STATUS - Auxiliary Input Status >>> FALSE
0x1F - ENGINE_RUNTIME - Run Time Since Engine Started >>> FALSE 0x20 - PID_21_40 - PID 0x21 - 0x40 Supported >>> TRUE
Valid OBD-II PID reply
Supported PID mask: -1610612735
Mask: 10100000000000000000000000000001 0x21 - DIST_TRAVELED_MIL - Distance Traveled with MIL On >>> TRUE
0x22 - FUEL_RAIL_PRESSURE - Fuel Rail Pressure Relative to Manifold >>> FALSE 0x23 - FUEL_RAIL_PRES_ALT - MPI/Diesel Fuel Rail Pressure >>> TRUE
0x24 - O2S1_WR_LAMBDA_V - O2 Sensor 1 Equivalence Ratio Voltage >>> FALSE
0x25 - O2S2_WR_LAMBDA_V - O2 Sensor 2 Equivalence Ratio Voltage >>> FALSE
0x26 - O2S3_WR_LAMBDA_V - O2 Sensor 3 Equivalence Ratio Voltage >>> FALSE
0x27 - O2S4_WR_LAMBDA_V - O2 Sensor 4 Equivalence Ratio Voltage >>> FALSE
0x28 - O2S5_WR_LAMBDA_V - O2 Sensor 5 Equivalence Ratio Voltage >>> FALSE
0x29 - O2S6_WR_LAMBDA_V - O2 Sensor 6 Equivalence Ratio Voltage >>> FALSE
0x2A - O2S7_WR_LAMBDA_V - O2 Sensor 7 Equivalence Ratio Voltage >>> FALSE
0x2B - O2S8_WR_LAMBDA_V - O2 Sensor 8 Equivalence Ratio Voltage >>> FALSE
0x2C - COMMANDED_EGR - Commanded EGR >>> FALSE
0x2D - EGR_ERROR - EGR Error >>> FALSE
0x2E - COMMANDED_EVAP_P - Commanded Evaporative Purge >>> FALSE
0x2F - FUEL_LEVEL - Fuel Level Input >>> FALSE
0x30 - WARMUPS_SINCE_CLR - Number of Warmups since DTC Cleared >>> FALSE
0x31 - DIST_SINCE_CLR - Distance Traveled Since DTC Cleared >>> FALSE
0x32 - EVAP_PRESSURE - Evap. System Vapor Pressure >>> FALSE
0x33 - BAROMETRIC_PRESSURE - Barometric Pressure >>> FALSE
0x34 - O2S1_WR_LAMBDA_I - O2 Sensor 1 Equivalence Ratio Current >>> FALSE
0x35 - O2S2_WR_LAMBDA_I - O2 Sensor 2 Equivalence Ratio Current >>> FALSE
0x36 - O2S3_WR_LAMBDA_I - O2 Sensor 3 Equivalence Ratio Current >>> FALSE
0x37 - O2S4_WR_LAMBDA_I - O2 Sensor 4 Equivalence Ratio Current >>> FALSE
0x38 - O2S5_WR_LAMBDA_I - O2 Sensor 5 Equivalence Ratio Current >>> FALSE
0x39 - O2S6_WR_LAMBDA_I - O2 Sensor 6 Equivalence Ratio Current >>> FALSE
0x3A - O2S7_WR_LAMBDA_I - O2 Sensor 7 Equivalence Ratio Current >>> FALSE
0x3B - O2S8_WR_LAMBDA_I - O2 Sensor 8 Equivalence Ratio Current >>> FALSE
0x3C - CAT_TEMP_B1S1 - Catalyst Temperature Bank 1 Sensor 1 >>> FALSE
0x3D - CAT_TEMP_B2S1 - Catalyst Temperature Bank 2 Sensor 1 >>> FALSE
0x3E - CAT_TEMP_B1S2 - Catalyst Temperature Bank 1 Sensor 2 >>> FALSE
0x3F - CAT_TEMP_B2S2 - Catalyst Temperature Bank 2 Sensor 2 >>> FALSE 0x40 - PID_41_60 - PID 0x41 - 0x60 Supported >>> TRUE
Valid OBD-II PID reply
Supported PID mask: 1
Mask: 00000000000000000000000000000001
0x41 - MONITOR_STATUS - Monitor Status This Drive Cycle >>> FALSE
0x42 - ECU_VOLTAGE - Control Module Voltage >>> FALSE
0x43 - ABSOLUTE_LOAD - Absolute Load Value >>> FALSE
0x44 - COMMANDED_EQUIV_R - Commanded Equivalence Ratio >>> FALSE
0x45 - REL_THROTTLE_POS - Relative Throttle Position >>> FALSE
0x46 - AMB_AIR_TEMP - Ambient Air Temperature >>> FALSE
0x47 - ABS_THROTTLE_POS_B - Absolute Throttle Position B >>> FALSE
0x48 - ABS_THROTTLE_POS_C - Absolute Throttle Position C >>> FALSE
0x49 - ACCEL_POS_D - Accelerator Pedal Position D >>> FALSE
0x4A - ACCEL_POS_E - Accelerator Pedal Position E >>> FALSE
0x4B - ACCEL_POS_F - Accelerator Pedal Position F >>> FALSE
0x4C - COMMANDED_THROTTLE - Commanded Throttle Actuator >>> FALSE
0x4D - TIME_RUN_WITH_MIL - Time Run with MIL on >>> FALSE
0x4E - TIME_SINCE_CLR - Time Since DTC Cleared >>> FALSE
0x4F - MAX_R_O2_VI_PRES - Maximum Value - Equivalence ratio, O2 Voltage, O2 Current, Intake Manifold Pressure >>> FALSE
0x50 - MAX_AIRFLOW_MAF - Maximum MAF Airflow Value >>> FALSE
0x51 - FUEL_TYPE - Fuel Type >>> FALSE
0x52 - ETHANOL_PERCENT - Ethanol fuel % >>> FALSE
0x53 - ABS_EVAP_SYS_PRES - Absolute Evap. System Vapor Pressure >>> FALSE
0x54 - EVAP_SYS_PRES - Evap. System Vapor Pressure >>> FALSE
0x55 - ST_O2_TRIM_B1B3 - Short Term Secondary O2 Sensor Trim - Bank 1 and 3 >>> FALSE
0x56 - LT_O2_TRIM_B1B3 - Long Term Secondary O2 Sensor Trim - Bank 1 and 3 >>> FALSE
0x57 - ST_02_TRIM_B2B4 - Short Term Secondary O2 Sensor Trim - Bank 2 and 4 >>> FALSE
0x58 - LT_O2_TRIM_B2B4 - Long Term Secondary O2 Sensor Trim - Bank 2 and 4 >>> FALSE
0x59 - ABS_FUEL_RAIL_PRES - Absolute Fuel Rail Pressure >>> FALSE
0x5A - REL_ACCEL_POS - Relative Accelerator Pedal Position >>> FALSE
0x5B - HYBRID_BATT_PCT - Hybrid Battery Pack Charge Percent >>> FALSE
0x5C - ENGINE_OIL_TEMP - Engine Oil Temperature >>> FALSE
0x5D - FUEL_TIMING - Fuel Injection Timing >>> FALSE
0x5E - FUEL_RATE - Engine Fuel Rate >>> FALSE
0x5F - EMISSIONS_STANDARD - Emmissions Requirements >>> FALSE 0x60 - PID_61_80 - PID 0x61 - 0x80 Supported >>> TRUE
Not really any different or elegant, just another flavor
static string GetIntBinaryString(int n)
{
char[] b = new char[32];
for (int i = 31; i >= 0; i--)
{
b[i] = (n & 1) == 1 ? '1' : '0';
n >>= 1;
}
return new string(b);
}
If I could make one suggestion on the naming. Since you are passing an ‘int’ argument you can leave out the ‘Int’ from the function name. Why? well later you can provide overloads that accept byte, short etc. and the name will still be ‘GetBinaryString’ the argument type will dictate the overload that is called.
How about Obd Iis Australia | Little Bird Australia since it has cable attached. I suspect the one you point to is the same connection except no easy place to grab hold and remove it… (and $20 for the convenience and cables )