#include <MsTimer2.h>
//For reading
#define ENGINE_DATA_PIN 2 // pin 2
#define ENGINE_DATA_INT 0 // for interrupts
#define OBD_DATA true
#define MY_HIGH HIGH //LOW //if you use only one wire,
#define MY_LOW LOW //HIGH //swap high and low, if twisted pair, then leave as is
#define TOYOTA_MAX_BYTES 24
volatile uint8_t ToyotaNumBytes, ToyotaID;
volatile uint8_t ToyotaData[TOYOTA_MAX_BYTES];
volatile uint16_t ToyotaFailBit = 0;
// make your life easier
#define OBD_INJ 1 //Injector pulse width (INJ)
#define OBD_IGN 2 //Ignition timing angle (IGN)
#define OBD_IAC 3 //Idle Air Control (IAC)
#define OBD_RPM 4 //Engine speed (RPM)
#define OBD_MAP 5 //Manifold Absolute Pressure (MAP)
#define OBD_ECT 6 //Engine Coolant Temperature (ECT)
#define OBD_TPS 7 // Throttle Position Sensor (TPS)
#define OBD_SPD 8 //Speed (SPD)
#define OBD_OXSENS 9 // Lambda 1
#define OBD_OXSENS2 10 //Lambda 2???????????
float g_power = 0.135; // injector performance at 3S FE in 15 sec //FOR ANOTHER AUTO, CHANGE THIS PARAMETER!!!!!!!!!!!!!!
float g_fors_cnt = 4; // number of injectors //FOR ANOTHER CAR, CHANGE THIS PARAMETER!!!!!!!!!!!!!!
float g_fors_col = 1; // number of openings per 2 revolutions //FOR ANOTHER AUTO, CHANGE THIS PARAMETER!!!!!!!!!!!!!!
float per_sec; // revolutions per second
float oborot_cnt; // speed
float fors_time; // nozzle opening time in sec
float rashod; //car consumption
float per_hous; // consumption per hour
float time_100km; // time it takes to travel 100 km
int per_100km; // cost per hundred
int timers = 1;
int full_time = 0;
float tmLast = 0;
float tmNow = 0;
float dPeriod;
boolean OBDConnected;
unsigned long OBDLastSuccessPacket;
//For transfer to Torque
String inputString = "";
boolean stringComplete = false;
void timer() {
full_time++;
}
void setup() {
MsTimer2::set(1000, timer);
Serial.begin(9600);
inputString.reserve(200);
Serial.println(">");
// login setup
pinMode(ENGINE_DATA_PIN, INPUT); // facelift
//interrupt setting
attachInterrupt(ENGINE_DATA_INT, ChangeState, CHANGE);
//initial timer settings from the moment of switching on
}
void loop() {
if ((ToyotaData[OBD_RPM] > 0) && timers == 1) {
MsTimer2::start();
timers = 0;
} else if ((ToyotaData[OBD_RPM] < 1) && timers == 0) {
MsTimer2::stop();
timers = 1;
full_time = 0;
}
//read protocol
if (ToyotaNumBytes > 0) {
// set last success
OBDLastSuccessPacket = millis();
// set connected to true
OBDConnected = true;
// reset the counter.
ToyotaNumBytes = 0;
} // end if (ToyotaNumBytes > 0)
// We make indirect calculations
//actual temperature
int OBD_ECTi;
if (ToyotaData[OBD_ECT] >= 244)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 244) * 10.0) + 174.0;
else if (ToyotaData[OBD_ECT] >= 238)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 238) * 4.0) + 145.0;
else if (ToyotaData[OBD_ECT] >= 228)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 228) * 2.1) + 122.0;
else if (ToyotaData[OBD_ECT] >= 210)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 210) * 1.11) + 102.0;
else if (ToyotaData[OBD_ECT] >= 180)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 180) * 0.666) + 82.0;
else if (ToyotaData[OBD_ECT] >= 135)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 135) * 0.444) + 62.0;
else if (ToyotaData[OBD_ECT] >= 82)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 82) * 0.377) + 42.0;
else if (ToyotaData[OBD_ECT] >= 39)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 39) * 0.465) + 22.0;
else if (ToyotaData[OBD_ECT] >= 15)
OBD_ECTi = ((ToyotaData[OBD_ECT] - 15) * 0.833) + 2.0;
else
OBD_ECTi = (ToyotaData[OBD_ECT] * 2.0) + (-28.0);
/* ----------------------------- I DON'T KNOW HOW TO CALCULATE THE EXPENSE CORRECTLY, IF ANYONE PROMPTS, HERE IS MY email Bondy)_13@list.ru -------------------------------- */
tmLast = 1;
tmNow = 2;
dPeriod = (tmNow - tmLast) / ToyotaData[OBD_SPD];
// revolutions per second
per_sec = (ToyotaData[OBD_RPM] * 25) / 60.0;
// how many turns were made
oborot_cnt = per_sec * dPeriod;
// nozzle opening time in sec
fors_time = (oborot_cnt / 2) * g_fors_col * g_fors_cnt * (ToyotaData[OBD_INJ] / 10) / 1000.0;
// how much was spent in the last time interval
rashod = fors_time * (g_power / 15.0);
// how much will be spent per hour
per_hous = rashod * 3600 / dPeriod;
// how long does it take to travel 100 km (in seconds)
time_100km = (100.0 / ToyotaData[OBD_SPD]) * 3600.0;
// consumption per 100 km
per_100km = 0.0;
if (ToyotaData[OBD_SPD] > 0) {
per_100km = rashod * time_100km / dPeriod;
}
/*--------------------------------------------------------------------------------------------------------------------------------------------- */
//check for lost connection
if (OBDLastSuccessPacket + 3500 < millis() && OBDConnected) {
OBDConnected = false;
} // end if lost connection
//transfer to Torque
if (stringComplete) {
int len = inputString.length();
String ans = "4" + inputString.substring(1, 2) + " ";
if (len > 4) ans = ans + inputString.substring(3, 5) + " ";
else if (len > 3) ans = ans + inputString.substring(2, 4) + " ";
else if (len > 2) ans = ans + inputString.substring(3, 4) + " ";
if (inputString.substring(0, 3) == "ATZ") Serial.println("ELM327 v1.4");
else if (inputString.substring(0, 3) == "ATI") Serial.println("ELM327 v1.4");
else if (inputString.substring(0, 2) == "DP") Serial.println("SAE J1850 PWM");
else if (inputString.substring(0, 3) == "DP1") Serial.println("SAE J1850 PWM");
else if (inputString.substring(0, 4) == "AT@1") Serial.println("made Alexey Bondarenko");
else if (inputString.substring(0, 4) == "ATTP1") Serial.println("OK");
else if (inputString.substring(0, 2) == "AT") Serial.println("OK");
else if (inputString.substring(0, 4) == "0100") Serial.println("41 00 08 38 80 02"); //supported pids of group 1
else if (inputString.substring(0, 4) == "0101") Serial.println("41 01 00 00 00 00");
else if (inputString.substring(0, 4) == "0120") Serial.println("41 20 00 00 00 00"); // supported pids of the 2nd group
else if (inputString.substring(0, 4) == "0140") Serial.println("41 40 00 00 80 00"); // supported pids of the 3rd group
else if (inputString.substring(0, 4) == "0151") Serial.println("41 51 01 00 00 00"); // type of fuel, there is gasoline at the moment, diesel will "41 51 04 00 00 00"
else if (inputString.substring(0, 4) == "0160") Serial.println("41 60 00 00 00 00"); // supported pids of the 4th group
else if (inputString.substring(0, 4) == "0180") Serial.println("41 80 00 00 00 00"); // supported pids of the 5th group
else if (inputString.substring(0, 4) == "01A0") Serial.println("41 A0 80 00 00 00"); //supported pids of the 6th group
else if (inputString.substring(0, 4) == "01C0") Serial.println("41 C0 00 00 00 00"); // supported pids of the 7th group
else if (inputString.substring(0, 2) == "03") Serial.println("43 03 00 00 00 00\r\n43 13 00 00"); //type of error in the car ....
else if (inputString.substring(0, 4) == "0902") Serial.println("49 02 1Z3768470804"); // car serial number... VIN
//coolant temperature output
if ((OBD_ECTi > (-16)) && (OBD_ECTi < 16)) {
if (inputString.substring(0, 4) == "0105") Serial.print("41 05 "), Serial.print("0"), Serial.println(OBD_ECTi, HEX);
} else {
if (inputString.substring(0, 4) == "0105") Serial.print("41 05 "), Serial.println(OBD_ECTi, HEX);
}
//Correct engine speed
if ((ToyotaData[OBD_RPM] * 100 / 4) < 1001) {
if (inputString.substring(0, 4) == "010C") Serial.print("41 0C "), Serial.print("0"), Serial.println(ToyotaData[OBD_RPM] * 100, HEX);
} else {
if (inputString.substring(0, 4) == "010C") Serial.print("41 0C "), Serial.println(ToyotaData[OBD_RPM] * 100, HEX); //engine speed
}
// damper angle
if (ToyotaData[OBD_TPS] < 10) {
if (inputString.substring(0, 4) == "0111") Serial.print("41 11 "), Serial.print("0"), Serial.println(ToyotaData[OBD_TPS] * 255 / 100, HEX); // damper angle
} else {
if (inputString.substring(0, 4) == "0111") Serial.print("41 11 "), Serial.println(ToyotaData[OBD_TPS] * 255 / 100, HEX);
}
//Vehicle speed
if (ToyotaData[OBD_SPD] < 16) {
if (inputString.substring(0, 4) == "010D") Serial.print("41 0D "), Serial.print("0"), Serial.println(ToyotaData[OBD_SPD], HEX); //////Vehicle speed
} else {
if (inputString.substring(0, 4) == "010D") Serial.print("41 0D "), Serial.println(ToyotaData[OBD_SPD], HEX); //////Vehicle speed
}
//Time since engine start
if (full_time < 16) {
if (inputString.substring(0, 4) == "011F") Serial.print("41 1F 00 "), Serial.print("0"), Serial.println(full_time, HEX);
} else if ((full_time > 15) && (256 > full_time)) {
if (inputString.substring(0, 4) == "011F") Serial.print("41 1F 00 "), Serial.println(full_time, HEX);
} else if ((full_time > 255) && (4096 > full_time)) {
if (inputString.substring(0, 4) == "011F") Serial.print("41 1F 0"), Serial.println(full_time, HEX);
} else if (full_time > 4096) {
if (inputString.substring(0, 4) == "011F") Serial.print("41 1F "), Serial.println(full_time, HEX);
}
//ignition timing
if ((ToyotaData[OBD_IGN] + 50) < 10) {
if (inputString.substring(0, 4) == "010E") Serial.print("41 0E "), Serial.print("0"), Serial.println((ToyotaData[OBD_IGN] + 50), HEX);
} else {
if (inputString.substring(0, 4) == "010E") Serial.print("41 0E "), Serial.println((ToyotaData[OBD_IGN] + 50), HEX);
}
// injector time
if (ToyotaData[OBD_INJ] < 16) {
if (inputString.substring(0, 4) == "01E4") Serial.print("41 E4 "), Serial.print("0"), Serial.println(ToyotaData[OBD_INJ], HEX);
} else {
if (inputString.substring(0, 4) == "01E4") Serial.print("41 E4 "), Serial.println(ToyotaData[OBD_INJ], HEX);
}
//intake manifold pressure
if (ToyotaData[OBD_MAP] < 16) {
if (inputString.substring(0, 4) == "010B") Serial.print("41 0B "), Serial.print("0"), Serial.println(ToyotaData[OBD_MAP], HEX);
} else {
if (inputString.substring(0, 4) == "010B") Serial.print("41 0B "), Serial.println(ToyotaData[OBD_MAP], HEX);
}
//Fan rotation
if (ToyotaData[OBD_IAC] < 16) {
if (inputString.substring(0, 4) == "01A2") Serial.print("41 A2 "), Serial.print("0"), Serial.println(ToyotaData[OBD_IAC], HEX);
} else {
if (inputString.substring(0, 4) == "01A2") Serial.print("41 A2 "), Serial.println(ToyotaData[OBD_IAC], HEX);
}
//Consumption per hour
if (per_hous < 16) {
if (inputString.substring(0, 4) == "01A3") Serial.print("41 A3 "), Serial.print("0"), Serial.println(per_hous, HEX);
} else {
if (inputString.substring(0, 4) == "01A3") Serial.print("41 A3 "), Serial.println(per_hous, HEX);
}
//consumption per 100 km
if (per_100km < 16) {
if (inputString.substring(0, 4) == "01A4") Serial.print("41 A4 "), Serial.print("0"), Serial.println(per_100km, HEX);
} else {
if (inputString.substring(0, 4) == "01A4") Serial.print("41 A4 "), Serial.println(per_100km, HEX);
}
// Lambda
if (OBD_OXSENS) {
if (inputString.substring(0, 4) == "0114") Serial.print("41 14 "), Serial.print(OBD_OXSENS, HEX), Serial.println(" 00");
}
Serial.println(">");
inputString = "";
stringComplete = false;
}
}
// GET DATA FROM OBD
float getOBDdata(int OBDdataIDX) {
// define return value
float returnValue;
switch (OBDdataIDX) {
case 0: // UNKNOWN
returnValue = ToyotaData[0];
break;
case OBD_INJ: // Injector pulse width (INJ) - in milisec
returnValue = ToyotaData[OBD_INJ] / 10;
break;
case OBD_IGN: // Ignition timing angle (IGN) - degree- BTDC
returnValue = ToyotaData[OBD_IGN] - 90;
break;
case OBD_IAC: //Idle Air Control (IAC) - Step # X = 125 = open 100%
returnValue = ToyotaData[OBD_IAC] / 125 * 100;
break;
case OBD_RPM: //Engine speed (RPM)
returnValue = ToyotaData[OBD_RPM] * 25;
break;
case OBD_MAP: //Manifold Absolute Pressure (MAP) - kPa Abs
returnValue = ToyotaData[OBD_MAP];
break;
case OBD_ECT: // Engine Coolant Temperature (ECT)
if (ToyotaData[OBD_ECT] >= 244)
returnValue = ((float)(ToyotaData[OBD_ECT] - 244) * 10.0) + 132.0;
else if (ToyotaData[OBD_ECT] >= 238)
returnValue = ((float)(ToyotaData[OBD_ECT] - 238) * 4.0) + 103.0;
else if (ToyotaData[OBD_ECT] >= 228)
returnValue = ((float)(ToyotaData[OBD_ECT] - 228) * 2.1) + 80.0;
else if (ToyotaData[OBD_ECT] >= 210)
returnValue = ((float)(ToyotaData[OBD_ECT] - 210) * 1.11) + 60.0;
else if (ToyotaData[OBD_ECT] >= 180)
returnValue = ((float)(ToyotaData[OBD_ECT] - 180) * 0.666) + 40.0;
else if (ToyotaData[OBD_ECT] >= 135)
returnValue = ((float)(ToyotaData[OBD_ECT] - 135) * 0.444) + 20.0;
else if (ToyotaData[OBD_ECT] >= 82)
returnValue = ((float)(ToyotaData[OBD_ECT] - 82) * 0.377) + 0.0;
else if (ToyotaData[OBD_ECT] >= 39)
returnValue = ((float)(ToyotaData[OBD_ECT] - 39) * 0.465) + (-20.0);
else if (ToyotaData[OBD_ECT] >= 15)
returnValue = ((float)(ToyotaData[OBD_ECT] - 15) * 0.833) + (-40.0);
else
returnValue = ((float)ToyotaData[OBD_ECT] * 2.0) + (-70.0);
break;
case OBD_TPS: // Throttle Position Sensor (TPS) - DEGREE
returnValue = ToyotaData[OBD_TPS] / 2;
break;
case OBD_SPD: // Speed (SPD) - km/h
returnValue = ToyotaData[OBD_SPD];
break;
case OBD_OXSENS: // Lambda
returnValue = ToyotaData[9] * 5 / 256 / 3.9215686274509807 * 200;
break;
case OBD_OXSENS2: // Lambda2
returnValue = ToyotaData[10] * 5 / 256 / 3.9215686274509807 * 200;
break;
break;
case 11: // FLAG #1
returnValue = ToyotaData[11];
break;
case 12: // FLAG # 2
returnValue = ToyotaData[12];
break;
default: // DEFAULT CASE (in no match to number)
// send "error" value
returnValue = 9999.99;
} // end switch
// send value back
return returnValue;
} // end void getOBDdata
// VOID CHANGE
void ChangeState() {
//Serial.print(digitalRead(ENGINE_DATA_PIN));
static uint8_t ID, EData[TOYOTA_MAX_BYTES];
static boolean InPacket = false;
static unsigned long StartMS;
static uint16_t BitCount;
int state = digitalRead(ENGINE_DATA_PIN);
if (InPacket == false) {
if (state == MY_HIGH) {
StartMS = millis();
} else { // else if (state == MY_HIGH)
if ((millis() - StartMS) > (15 * 8)) {
StartMS = millis();
InPacket = true;
BitCount = 0;
} // end if ((millis() - StartMS) > (15 * 8))
} // end if (state == MY_HIGH)
} else { // else if (InPacket == false)
uint16_t bits = ((millis() - StartMS) + 1) / 8; // The +1 is to cope with slight time errors
StartMS = millis();
// process bits
while (bits > 0) {
if (BitCount < 4) {
if (BitCount == 0)
ID = 0;
ID >>= 1;
if (state == MY_LOW) // inverse state as we are detecting the change!
ID |= 0x08;
} else { // else if (BitCount < 4)
uint16_t bitpos = (BitCount - 4) % 11;
uint16_t bytepos = (BitCount - 4) / 11;
if (bitpos == 0) {
// Start bit, should be LOW
if ((BitCount > 4) && (state != MY_HIGH)) { // inverse state as we are detecting the change!
ToyotaFailBit = BitCount;
InPacket = false;
break;
} // end if ((BitCount > 4) && (state != MY_HIGH))
} else if (bitpos < 9) { //else TO if (bitpos == 0)
EData[bytepos] >>= 1;
if (state == MY_LOW) // inverse state as we are detecting the change!
EData[bytepos] |= 0x80;
} else { // else if (bitpos == 0)
// Stop bits, should be HIGH
if (state != MY_LOW) { // inverse state as we are detecting the change!
ToyotaFailBit = BitCount;
InPacket = false;
break;
} // end if (state != MY_LOW)
if ((bitpos == 10) && ((bits > 1) || (bytepos == (TOYOTA_MAX_BYTES - 1)))) {
ToyotaNumBytes = 0;
ToyotaID = ID;
for (int i = 0; i <= bytepos; i++)
ToyotaData[i] = EData[i];
ToyotaNumBytes = bytepos + 1;
if (bits >= 16) // Stop bits of last byte were 1's so detect preamble for next packet
BitCount = 0;
else {
ToyotaFailBit = BitCount;
InPacket = false;
}
break;
}
}
}
++BitCount;
--bits;
} // end while
} // end (InPacket == false)
} // end void change
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
if (inChar == '\n') continue;
if (inChar == '\r') {
stringComplete = true;
if (inputString == "") inputString = "NULL";
inputString.toUpperCase();
continue;
}
inputString += inChar;
}
}