Introduction: Hack an ELM327 Cable to Make an Arduino OBD2 Scanner
In my previous instructable i created an OBD2 Simulator so that i didn't have to test my Arduino OBD2 Reader in the car the whole time but instead in the comfort of my own home.
Stuff you need.
Arduino UNO
LCD shield
ELM327 USB cable.
What it can read
Coolant Temp,IAT Temp,Ambient Temp, Throttle %,RPM,Vehicle Speed, Air flow Rate,Barometric Pressure
I will be removing the board from the ELM327 Enclosure and then bypass the USB bridge chip and attach the Serial TX/RX pins of the arduino to the Serial TX/RX pins onto the ELM327 board, program the arduino and attach the ELM327 OBD2 connector to the OBD2 port .
Pretty Simple
Step 1: Prepare the ELM327 Board to Bypass the USB Bridge Chip
Start by removing the sticker on ELM327 Cable's Enclosure, remove the 4 screws with a smallish star screwdriver.
And then take out the board.
Tip:Borrow your Girlfrien's/Wife's cutex and make a mark on one side of the connector that runs to the OBD2 Connector, that way when you take it out you will know which side it goes because it can go in both ways, for this instructable its not needed to remove the mentioned connector though.
Solder 2 wires to the TX and RX pins on the board, in the attached photo's i have included the pin-out information of the USB Bridge chip. Be careful though I managed to de-solder some components which i could not put back, but luckily it still worked afterwards.
Tip:Program the arduino so that it writes to the serial monitor with some short delays in between, then connect a jumper cable to the TX pin of the arduino and poke around with the other end on the board to see where you get some serial activity, the surface mounted LED's wil flicker as communication happens, unfortunately this will not work for the RX side but in the pictures its easy enough to see where I soldered it onto the board.
NOTE:The USB cable is connected to the board with a 4 pin connector, i cut the middle 2 out so that the ELM327 cannot communicate with the PC whilst its connected, this way it only gets power from my PC's USB port and the serial controller on the board will not be occupied by the PC allowing the Arduino to talk to it
Once done put it back into the box, I just taped it up because In my Jeep the box is in my way and cannot drive it whilst in the driver seat, I will be using the enclosure for something else.
Step 2: Attach the Arduino LCD Shield to the Arduino
Attach the Arduino LCD Shield to the arduino and hook it up to your PC to be programmed.
Below is my Arduino Sketch, I noticed that the formatting messes with the code a bit, I have some more information available related to this build you can also view the code here.
http://techtinker.co.za/viewtopic.php?f=14&t=17
// include the library code:<br>#include
//Declare Serial Read variables int CmdCount=1; byte inData; char inChar; String BuildINString=""; String DisplayString=""; long DisplayValue; String SentMessage=""; int ByteCount=0; long A; int B; int WorkingVal; String WorkingString="";
//Declare Buttons int MenuID=0;
// initialize the library with the numbers of the interface pins LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup() { // set up the LCD's number of columns and rows: lcd.begin(16, 2); // Print a message to the LCD. lcd.setCursor(0, 0); Bootup();//Simulate Bootup process doesnt have to be here this only makes it look cool Retry: lcd.setCursor(0, 0); lcd.print("Connecting...... "); lcd.setCursor(0, 1); lcd.print(" "); Serial.begin(38400); delay(500); //Send a test message to see if the ELM327 Chip is responding SentMessage = "ATI"; Serial.println("ATI");delay(500);ReadData(); if (BuildINString.substring(1,7)=="ELM327") { lcd.setCursor(0, 0); lcd.print("Welcome... "); lcd.setCursor(0, 1); lcd.print("Connection OK "); delay(1500); } else { lcd.setCursor(0, 0); lcd.print("Error "); lcd.setCursor(0, 1); lcd.print("No Connection! "); delay(1500); goto Retry; }
delay(1500); }
void loop() { int x; x = analogRead (0); //Serial.println(x); lcd.setCursor(10,1); if (x > 800 and x < 820){lcd.print ("Select ");} if (x > 620 and x < 630){if (MenuID>0){MenuID--;}delay(250);}//Left if (x > 400 and x < 415){lcd.print ("Down ");} if (x > 190 and x < 215){lcd.print ("Up ");} if (x > -10 and x < 10){if (MenuID<11){MenuID++;}delay(250);} //Right
if (MenuID==0){lcd.setCursor(0, 0);lcd.print("01 Coolant Temp ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 05";Serial.println("01 05");delay(300);ReadData();} if (MenuID==1){lcd.setCursor(0, 0);lcd.print("02 IAT Temp ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 0F";Serial.println("01 0F");delay(300);ReadData();} if (MenuID==2){lcd.setCursor(0, 0);lcd.print("03 Ambient Temp ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 46";Serial.println("01 46");delay(300);ReadData();} if (MenuID==3){lcd.setCursor(0, 0);lcd.print("04 Throttle % ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 11";Serial.println("01 11");delay(300);ReadData();} if (MenuID==4){lcd.setCursor(0, 0);lcd.print("05 CAT 1 Temp ");lcd.setCursor(0, 1);lcd.print("Not Implemented ");} if (MenuID==5){lcd.setCursor(0, 0);lcd.print("06 CAT 2 Temp ");lcd.setCursor(0, 1);lcd.print("Not Implemented ");} if (MenuID==6){lcd.setCursor(0, 0);lcd.print("07 CAT 3 Temp ");lcd.setCursor(0, 1);lcd.print("Not Implemented ");} if (MenuID==7){lcd.setCursor(0, 0);lcd.print("08 CAT 4 Temp ");lcd.setCursor(0, 1);lcd.print("Not Implemented ");} if (MenuID==8){lcd.setCursor(0, 0);lcd.print("09 RPM ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 0C";Serial.println("01 0C");delay(300);ReadData();} if (MenuID==9){lcd.setCursor(0, 0);lcd.print("10 Vehicle Speed ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 0D";Serial.println("01 0D");delay(300);ReadData();} if (MenuID==10){lcd.setCursor(0, 0);lcd.print("11 Air Flow Rate ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 10";Serial.println("01 10");delay(300);ReadData();} if (MenuID==11){lcd.setCursor(0, 0);lcd.print("12 Barometric ");lcd.setCursor(0, 1);lcd.print(DisplayString);SentMessage = "01 33";Serial.println("01 33");delay(300);ReadData();}
}
//Read Data and act accordingly void ReadData() { BuildINString=""; while(Serial.available() > 0) { inData=0; inChar=0; inData = Serial.read(); inChar=char(inData); BuildINString = BuildINString + inChar; } //if(BuildINString!=""){Serial.print(BuildINString);} BuildINString.replace(SentMessage,""); BuildINString.replace(">",""); BuildINString.replace("OK",""); BuildINString.replace("STOPPED",""); BuildINString.replace("SEARCHING",""); BuildINString.replace("NO DATA",""); BuildINString.replace("?",""); BuildINString.replace(",",""); //Serial.print(BuildINString); //Check which OBD Command was sent and calculate VALUE //Calculate RPM I.E Returned bytes wil be 41 0C 1B E0 if (SentMessage=="01 0C") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0); WorkingString = BuildINString.substring(11,13); B = strtol(WorkingString.c_str(),NULL,0); DisplayValue = ((A * 256)+B)/4; DisplayString = String(DisplayValue) + " rpm "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //Calculate Vehicle speed I.E Returned bytes wil be 41 0C 1B E0 if (SentMessage=="01 0D") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0);
DisplayValue = A; DisplayString = String(DisplayValue) + " km/h "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //Coolant Temp if (SentMessage=="01 05") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0);
DisplayValue = A; DisplayString = String(DisplayValue) + " C "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //IAT Temp if (SentMessage=="01 0F") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0);
DisplayValue = A; DisplayString = String(DisplayValue) + " C "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //Air flow Rate if (SentMessage=="01 10") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0); WorkingString = BuildINString.substring(11,13); B = strtol(WorkingString.c_str(),NULL,0); DisplayValue = ((A * 256)+B)/100; DisplayString = String(DisplayValue) + " g/s "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //Ambient Temp if (SentMessage=="01 46") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0);
DisplayValue = A; DisplayString = String(DisplayValue) + " C "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //Throttle position if (SentMessage=="01 11") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0);
DisplayValue = A; DisplayString = String(DisplayValue) + " % "; lcd.setCursor(0, 1); lcd.print(DisplayString); } //Barometric pressure if (SentMessage=="01 33") { WorkingString = BuildINString.substring(7,9); A = strtol(WorkingString.c_str(),NULL,0);
DisplayValue = A; DisplayString = String(DisplayValue) + " kpa "; lcd.setCursor(0, 1); lcd.print(DisplayString); } }
void Bootup() { lcd.print("WisperChip V2.00 "); for (int i=0; i <= 5; i++) { for (int j=1; j <= 4; j++)// -/|\- { if(j==1){lcd.setCursor(0, 1);lcd.print ("-");delay(200);} if(j==2){lcd.setCursor(0, 1);lcd.print ("/");delay(200);} if(j==3){lcd.setCursor(0, 1);lcd.print ("|");delay(200);} if(j==4){lcd.setCursor(0, 1);lcd.print ("\\");delay(200);} } } delay(1000); }
Step 3: Hooking It Up to Your Vehicle,
Once you have programmed the Arduino, make sure the Arduino's TX/RX pins are connected to the TX/RX pins on the ELM327 board.
The Code ensures that its able to talk to the ELM327 Chip by sending a command "ATI" the ELM327 chip will respond with ELM327, if it doesn't the LCD will print "Error, No Connection" if it worked it will welcome you wuth a welcome message on the LCD.
From there you simply press the left and right buttons to cycle through the menus currently it will only read.
Coolant Temp,IAT Temp,Ambient Temp, Throttle %,RPM,Vehicle Speed, Air flow Rate,Barometric Pressure
You can add more if you like and change the menu to your liking
See Wiki http://en.wikipedia.org/wiki/OBD-II_PIDs for more PID's that you can add there are quite a few.
You can use a cellphone cradle that you stuck agains the window to hold it and use a USB cellphone charger to power the Arduino, The ELM327 will be powered by the OBD port on Pin 16 which is positive and PIN4/5 which is negative.
If you get stuck feel free to check out on this forum http://techtinker.co.za/viewforum.php?f=14 you may also contact me if you have questions.
Please also see the youtube video.
Good Luckl!
19 Comments
1 year ago
what library programs are needed?
Tip 3 years ago
For a more robust interface between your Arduino and ELM327, you can use ELMduino.h --> https://github.com/PowerBroker2/ELMduino. It's installable through the Arduino IDE's libraries manager and comes with examples.
4 years ago
OBDII. 15765 CAN. missing pin # 5
I have a 2005 Daihatsu Delta which the speedo has died. I have purchased an obdII speedo. It will not connect as the delta's obdII port is missing pin #5. On pin 4 is a B/W wire, #6 is white, #9 is B/W, #13 is purp/pink, #14 is blu/w & #16 yell/b. Is it possible that #9 (vendor option) could actually be the signal ground (#5) ? I have read that there is an adapter, but I have not been able to source one. Thanks for any help & info
Question 4 years ago on Step 3
kalau buat motor cycle honda atau yamaha apa bisaa
Question 5 years ago
Hi,
I tried do the same with an elm327 from sparkfun but without success.
If I am using a ftdi adapter and try with pc I get this (1.png)
When I upload code to a mega I get what you can see in the rest of the pictures.
Any ideea what I am doing wrong?
Question 5 years ago
Hi, how do I calculate the WorkingString (7,9) or (10,12) for my Skoda Fabia 5J?
6 years ago
Do you have the code for this in correct format? The link to your tinker webpage doesn't work?
6 years ago
I got inspired by this
Project. So a big Thanks. I did have to change some code probably because
technology changes and each car uses a different protocol. Maybe my
ELM327 is a China knock off which I wouldn’t be surprised. The Formula for the
conversion from hex to decimal needs to be modified. Below a items I had to correct. It Worked on My 2004
Rav4 that has the CAN Bus protocol but not on my 2004 Miata which has a ISO
9141-2 Protocol. I Published my Project for my Miata if someone is interested.
https://www.instructables.com/id/Arduino-OBD2-ELM327-I2C-LCD-HC05-Bluetooth
Serial.begin(9600);
A =
strtol(WorkingString.c_str(),NULL,16)
DisplayString = String(DisplayValue - 40) + " C
7 years ago
It's not a good idea to put that tape betwen red cable and quartz resonator.
Quartz cristal resonator can shortly became hot that can even melt plastic while working.
7 years ago
This is a good tutorial and I've even used it personally for reference while working on my own OBDII car display. I appreaite the effort to write this! Although, I went a slightly different route.
A good alternative would be to get an HC-05 or similar Bluetooth module for the Arduino and a Bluetooth OBDII adapter. Both are very cheap on sites like Amazon or eBay. I'm talking less than $10 for a bluetooth OBD adapter and around the same for a HC-05. You may also need a logic level converter between the Arduino and bluetooth module like I did, since the Arduino is 5V and the module is 3.3V. The advantage of this method is that you don't have to rip an adapter apart and there's need to worry about running wires. Attempting to solder to a surface mount board can also be a very unpleasant experience and will likely be unreliable unless you are good at it.
Reply 7 years ago
hi Garyjs
please helpe me
i have similar project like you
7 years ago
hello sir;
excuseme i have many question :
1-it is Necessary that GND ardino with GND board is same?
2--it is Necessary for test circuit ,obd connector connect ecu ? for example if i dont connect it to ecu ,it must work?
3-please explain apart programming void loop?
thanks
7 years ago
Hey Guys!
Do you recommend any good places to buy this OBD-2 connection (ELM327 USB cable)? Thanks in advance.
7 years ago
Hello
I soldered to the two positions you have in your photos however when I hook the wires up to the Arduino I get an error in the connection. You mention to connect the wire to the TX and RX pins on the USB bridge chip however in your photos it seems like you only soldered to the TX and not the RX pin. Any help you can provide is greatly appreciated. Thank you.
8 years ago on Introduction
THANK YOU! this seems to be one of the cheapest ways to interface the Arduino and OBD II easily. There are kits but they want $50 for them. I saw this and bought the cord instantly, I mean its nine bucks, that is worth getting for just OBD plug! Again nice indestructible. Will post a pic when I finish!!
8 years ago on Introduction
this might help
http://en.wikipedia.org/wiki/OBD-II_PIDs
8 years ago on Introduction
I already follow your instruction. The ELM327 has
return ELM327 by using ATI command. Yet when I send 01 0C or 01 0D to
retrieve the RPM and speed, ELM327 is not seem to return the current
value. It is always 0 value. I hope you have any suggestion for me.
Thank you for sharing your knowledge.
8 years ago on Introduction
That is cool, great work
8 years ago on Introduction
Thanks for sharing this!