Here is a sketch that I modified to pull specific OBD data out of my F250 Diesel.
It isn't the prettiest or most efficient code I'm sure, but it works and I am ok with that.
It was built on the Sparkfun OBD interface and an Arduino Mega (multiple Serial ports)
Maybe someone will find this useful.
/*
* OBD-II-UART Quickstart Sketch
* Written by Ryan Owens for SparkFun Electronics 7/5/2011
* Updates for Arduino 1.0+ by Toni Klopfenstein
*
* Modified by Some Anon Guy 11/2014
* Customized for my specific needs on a Diesel Ford F250 Truck
*
* Released under the 'beerware' license
* (Do what you want with the code, but if we ever meet then you buy me a beer)
*
* This sketch will grab Exhaust Gas Temps, DFP Status, Regen Status, Engine Coolant,
* and Engine Oil Temp data from a vehicle with an OBD port using the OBD-II-UART
* board from SparkFun electronics. The data will be displayed
* on a serial 16x2 LCD. See the tutorial at https://www.sparkfun.com/tutorials/294
* to learn how to hook up the hardware:
*
*/
// Uncomment to print debud data to serial console
//#define debug
// include the LCD library code:
#include <LiquidCrystalFast.h>
// initialize the library with the numbers of the interface pins
LiquidCrystalFast lcd(12, 10, 11, 5, 4, 3, 2);
// LCD pins: RS RW EN D4 D5 D6 D7
//This is a character buffer that will store the data from the serial port
char rxData[32];
char rxWord1[32];
char rxWord2[32];
char rxIndex=0;
long EGT1, EGT2, EGT3, EGT4, REGEN, EngineCoolant, EngineOil;
double DPFpercent;
int DPFp;
int i=0;
void setup(){
//Both the Serial console and the OBD-II-UART use 9600 bps.
#ifdef debug
Serial.begin(9600); // Used for the USB Serial Console
#endif
Serial1.begin(9600); // Used to communicate with the OBD2 controller from SparkFun
// set up the LCD's number of rows and columns:
lcd.begin(20, 4);
// Print a message to the LCD.
lcd.print("F250 EGT/DPF Display");
//Wait for a little while before sending the reset command to the OBD-II-UART
delay(1500);
//Reset the OBD-II-UART
Serial1.println("ATZ");
//Wait for a bit before starting to send commands after the reset.
delay(2000);
// Setup Display Headers
lcd.clear();
//Left Columns
lcd.setCursor(0, 0);
lcd.print("EGT1:"); // Exhaust Gas Temp 1
lcd.setCursor(0, 1);
lcd.print("EGT2:"); // Exhaust Gas Temp 2
lcd.setCursor(0, 2);
lcd.print("EGT3:"); // Exhaust Gas Temp 3
lcd.setCursor(0, 3);
lcd.print("EGT4:"); // Exhaust Gas Temp 4
//Right Columns
lcd.setCursor(10, 0);
lcd.print("ReGen: "); // DPF Regen Cycle
lcd.setCursor(10, 1);
lcd.print("DPF %: "); // DPF Percent Full
lcd.setCursor(10, 2);
lcd.print("Cool : "); // Engine Coolant Temp
lcd.setCursor(10, 3);
lcd.print("Oil : "); // Engine Oil Temp
//Delete any data that may be in the serial port before we begin.
while(Serial1.available())
Serial1.read();
}
void loop(){
//Fill rxdata array with zeros
memset(rxData, 0, sizeof(rxData));
//Delete any data that may be in the serial port before we begin.
while(Serial1.available()>0)
Serial1.read();
//++++++++++++++++++++++++++++++++++++++++++
//Query the OBD-II-UART for the Engine OIL Temp
Serial1.println("22f45c");
delay(200);
#ifdef debug
Serial.println("PID: 22f45c");
Serial.println("Response: ");
#endif
getResponse(); // READ ECHO AND DISCARD
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord1
memcpy( rxWord1, rxData, sizeof(rxWord1));
for (i=0; i++; i<sizeof(rxWord1)){
#ifdef debug
Serial.print(rxWord1[i]);
#endif
}
// Calculate Engine Oil Temp
EngineOil = (((strtol(&rxWord1[9],0,16)-40)*9)/5)+32;
#ifdef debug
// Print to serial console for debug
Serial.println();
Serial.print("Oil Temp: ");
Serial.println(EngineOil);
Serial.println("DONE PID: 22f45c");
Serial.println();
#endif
//Display Engine Oil Temp.
lcd.setCursor(16, 3);
lcd.print(" ");
lcd.setCursor(16, 3);
lcd.print(EngineOil);
//Delete any data that may be in the serial port before we begin.
while(Serial1.available()>0)
Serial1.read();
//++++++++++++++++++++++++++++++++++++++++++
//Query the OBD-II-UART for the Engine Coolant
Serial1.println("0105");
delay(200);
#ifdef debug
Serial.println("PID: 0105");
Serial.println("Response: ");
#endif
getResponse(); // READ ECHO AND DISCARD
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord1
memcpy( rxWord1, rxData, sizeof(rxWord1));
for (i=0; i++; i<sizeof(rxWord1)){
Serial.print(rxWord1[i]);
}
EngineCoolant = (((strtol(&rxWord1[6],0,16)-40)*9)/5)+32;
#ifdef debug
Serial.println();
Serial.print("Engine Coolant: ");
Serial.println(EngineCoolant);
Serial.println("DONE PID: 0105");
Serial.println();
#endif
//Display Coolant Temp.
lcd.setCursor(16, 2);
lcd.print(" ");
lcd.setCursor(16, 2);
lcd.print(EngineCoolant);
//Delete any data that may be in the serial port before we begin.
while(Serial1.available()>0)
Serial1.read();
//++++++++++++++++++++++++++++++++++++++++++
//Query the OBD-II-UART for the Regen Status
Serial1.println("22f48b");
delay(200);
#ifdef debug
Serial.println("PID: 22f48b");
Serial.println("Response: ");
#endif
getResponse(); // READ ECHO AND DISCARD
getResponse(); // READ COUNTER? OR LENGHT? AND DISCARD
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord1
memcpy( rxWord1, rxData, sizeof(rxWord1));
for (i=0; i++; i<sizeof(rxWord1)){
#ifdef debug
Serial.print(rxWord1[i]);
#endif
}
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord2
memcpy( rxWord2, rxData, sizeof(rxWord2));
for (i=0; i++; i<sizeof(rxWord2)){
#ifdef debug
Serial.print(rxWord2[i]);
#endif
}
REGEN = bitRead(strtol(&rxWord1[15],0,16), 0);
#ifdef debug
Serial.println();
Serial.print("Regen Status: ");
Serial.println(REGEN);
Serial.println("DONE PID: 22f48b");
Serial.println();
#endif
//Display Regen Status
lcd.setCursor(16, 0);
lcd.print(" ");
lcd.setCursor(16, 0);
lcd.print(REGEN);
//Delete any data that may be in the serial port before we begin.
while(Serial1.available()>0)
Serial1.read();
//++++++++++++++++++++++++++++++++++++++++
//Query the OBD-II-UART for the DPF PERCENT
Serial1.println("22042c");
delay(200);
#ifdef debug
Serial.println("PID: 22042c");
Serial.println("Response: ");
#endif
getResponse(); // READ ECHO AND DISCARD
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord1
memcpy( rxWord1, rxData, sizeof(rxWord1));
for (i=0; i++; i<sizeof(rxWord1)){
#ifdef debug
Serial.print(rxWord1[i]);
#endif
}
DPFpercent = strtol(&rxWord1[9],0,16)*256;
//Serial.println(DPFpercent,4);
DPFpercent += strtol(&rxWord1[12],0,16);
//Serial.println(DPFpercent,4);
DPFpercent *= 0.0015259021896696;
//Serial.println(DPFpercent,4);
DPFpercent -= 1;
//Serial.println(DPFpercent,4);
DPFpercent /= 1.75;
//Serial.println(DPFpercent,4);
DPFpercent *= 100;
//Serial.println(DPFpercent,4);
DPFp = DPFpercent;
#ifdef debug
Serial.println();
Serial.print("DPF %: ");
Serial.println(DPFp);
Serial.println("DONE PID: 22042c");
Serial.println();
#endif
//Display DPF Percent on LCD
lcd.setCursor(16, 1);
lcd.print(" ");
lcd.setCursor(16, 1);
lcd.print(DPFp);
//Delete any data that may be in the serial port before we begin.
while(Serial1.available()>0)
Serial1.read();
//+++++++++++++++++++++++++++++++++++++++++
//Query the OBD-II-UART for the Vehicle EGT
#ifdef debug
Serial.println("PID: 22f478");
#endif
Serial1.println("22f478");
delay(200);
getResponse(); // READ ECHO AND DISCARD
getResponse(); // READ COUNTER? OR LENGHT? AND DISCARD
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord1
memcpy( rxWord1, rxData, sizeof(rxData));
getResponse(); // READ REAL DATA AND THEN STORE IN rxWord2
memcpy( rxWord2, rxData, sizeof(rxData));
#ifdef debug
Serial.println("DONE PID: 22f478");
Serial.println();
#endif
// Generate Display Data
EGT1 = (((strtol(&rxWord1[15],0,16)*256)+strtol(&rxWord1[18],0,16))*0.18)-40;
EGT2 = (((strtol(&rxWord2[3],0,16)*256)+strtol(&rxWord2[6],0,16))*0.18)-40;
EGT3 = (((strtol(&rxWord2[9],0,16)*256)+strtol(&rxWord2[12],0,16))*0.18)-40;
EGT4 = (((strtol(&rxWord2[15],0,16)*256)+strtol(&rxWord2[18],0,16))*0.18)-40;
lcd.setCursor(5, 0);
lcd.print(" ");
lcd.setCursor(5, 1);
lcd.print(" ");
lcd.setCursor(5, 2);
lcd.print(" ");
lcd.setCursor(5, 3);
lcd.print(" ");
lcd.setCursor(5, 0);
lcd.print(EGT1);
lcd.setCursor(5, 1);
lcd.print(EGT2);
lcd.setCursor(5, 2);
lcd.print(EGT3);
lcd.setCursor(5, 3);
lcd.print(EGT4);
delay(100);
}
//The getResponse function collects incoming data from the UART into the rxData buffer
// and only exits when a carriage return character is seen. Once the carriage return
// string is detected, the rxData buffer is null terminated (so we can treat it as a string)
// and the rxData index is reset to 0 so that the next string can be copied.
void getResponse(void){
char inChar=0;
//Keep reading characters until we get a carriage return
while(inChar != '\r'){
//If a character comes in on the serial port, we need to act on it.
if(Serial1.available()>0){
//Start by checking if we've received the end of message character ('\r').
if(Serial1.peek() == '\r'){
//Clear the Serial buffer
inChar=Serial1.read();
//Put the end of string character on our data string
rxData[rxIndex]='\0';
//Reset the buffer index so that the next character goes back at the beginning of the string.
rxIndex=0;
}
//If we didn't get the end of message character, just add the new character to the string.
else{
//Get the new character from the Serial port.
inChar = Serial1.read();
//Serial.print(inChar);
//Add the new character to the string, and increment the index variable.
rxData[rxIndex++]=inChar;
}
}
else
inChar='\r';
}
//Serial.println("GetResponseDone");
}