Pages: [1]   Go Down
Author Topic: OBD-II help (J1850 PWM)  (Read 3916 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I'm trying to make an OBD2 interface using the OBD-II uart from Sparkfun, but i'm having a bit of trouble getting the right data. I'm using the following code which i found in this thread http://arduino.cc/forum/index.php?PHPSESSID=3547d5fc432e994f1fb017ce82ddaa30&topic=111827.0

Code:
//This is a character buffer that will store the data from the serial port
char rxData[20];
char rxIndex=0;

//Variables to hold the speed and RPM data.
int vehicleSpeed=0;
int vehicleRPM=0;

void setup(){

  Serial1.begin(9600);
  Serial.begin(9600);   //This is for the serial debug

  //Wait for a little while before sending the reset command to the OBD-II-UART
  delay(1500);
  //Reset the OBD-II-UART
  Serial1.print("ATWS\r");
  //Wait for a bit before starting to send commands after the reset.
  delay(1000);
 
  // turn echo off
  Serial1.print("ATE0\r");
 
  // send 01 00 until we are connected
  do
  {
    Serial1.print("0100\r");
    delay(1000);
    getResponse();    //This is only called once since the schoecho has been turned off using ATE0\r
    Serial.print("0100 Response:  ");
    Serial.print(rxData[0]);Serial.print(rxData[1]);Serial.print(rxData[3]);Serial.print(rxData[4]);Serial.print(rxData[6]);Serial.print(rxData[7]); Serial.print(rxData[9]);Serial.print(rxData[10]);
    Serial.println("");
  }
  while(ELM_CHECK_RESPONSE("0100", rxData)!=0);
   
  Serial1.flush();
   
  Serial1.print("ATDPN\r");  //Shows the protocol
  getResponse();
  Serial.print("Protocol: ");Serial.print(rxData[0]);Serial.print(rxData[1]);Serial.println("");
  // str[0] should be 'A' for automatic
  // set header to talk directly to ECU#1
  if(rxData[1]=='1')  // PWM
    Serial1.print("ATSHE410F1\r");
  else if(rxData[1]=='2')  // VPW
    Serial1.print("ATSHA810F1\r");
  else if(rxData[1]=='3')  // ISO 9141
    Serial1.print("ATSH6810F1\r");
  else if(rxData[1]=='6')  // CAN 11 bits
    Serial1.print("ATSH7E0\r");
  else if(rxData[1]=='7')  // CAN 29 bits
    Serial1.print("ATSHDA10F1\r");
 
  //Delete any data that may be in the serial port before we begin.
  Serial1.flush();

}


void loop(){
  //Delete any data that may be in the serial port before we begin. 
  Serial1.flush();

  Serial1.print("010D\r");    //Query the OBD-II-UART for the Vehicle Speed

  //Get the response from the OBD-II-UART board. We get two responses
  //because the OBD-II-UART echoes the command that is sent.
  //We want the data in the second response.
  getResponse();

  //Convert the string data to an integer
  vehicleSpeed = strtol(&rxData[6],0,16);

  //Print the speed data to debug serial window
  Serial.print("SPEED: ");
  Serial.print(vehicleSpeed);
  Serial.print(" km/h");
  Serial.println(" ");
 
  delay(20);
 
  //Delete any data that may be left over in the serial port.
  Serial1.flush();

  //Query the OBD-II-UART for the Vehicle rpm
  Serial1.println("010C\r");
  //Get the response from the OBD-II-UART board
  getResponse();

  //Convert the string data to an integer
  //NOTE: RPM data is two bytes long, and delivered in 1/4 RPM from the OBD-II-UART
  vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;

  //Print the rpm data to debug serial window
  Serial.print("RPM: ");
  Serial.print(vehicleRPM);
  Serial.println(" ");

  //Give the OBD bus a rest
  delay(50);
 
}


byte ELM_CHECK_RESPONSE(const char *cmd, char *str)
{
  // cmd is something like "010D"
  // str should be "41 0D blabla"
  if(cmd[0]+4 != rxData[0]
    || cmd[1]!= rxData[1]
    || cmd[2]!= rxData[3]
    || cmd[3]!= rxData[4])
    return 1;

  return 0;  // no error
}


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();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
  }
}

My car ('02 Ford Focus) uses the J1850-PWM protocol and the code seems to initialize fine and returns the right protocol, but when i ask for live data, i just get some random numbers. Speed jumps between 0 and 13 km/h and rpm can go from 0 to 19 to 832 and sometimes even displays higher or negtive values, bot with and without the engine running.

I have spent a lot of time googling the problem and looking through the elm327 datasheet, but so far i haven't found anything that works.

I have also tried loading the OBDuino code, but that only seems to be working with the ISO-9141 protocol.

If anyone has any code or just pointers on how to get this to work with the J1850-PWM protocol i would be very happy to hear from you, as i'm starting to get a bit frustrated.

/Jakob
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 613
Posts: 49249
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Which Arduino are you using? Which version of the IDE?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

1.0.1 and i've tried both on an UNO and a Mega 2560.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 613
Posts: 49249
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
1.0.1 and
Then you should be aware that Serial.flush() blocks until all outgoing serial data (with the exception of the last byte) has been sent.

I can't see how that is useful in your code.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, i've tried to remove all Serial.flush() from the code, but that doesn't seem to do anything.

Here is some output from the serial monitor if that helps anyone:

Code:
0100 Response:  ATS
0100 Response:  TS
0100 Response:  TS
0100 Response: EL32 v.3
0100 Response:  L32 v.3
0100 Response: >AE0 v.3
0100 Response: OKE0 v.3
0100 Response:  KEO v.3
0100 Response: >4 0 B 3
0100 Response:  4 0 B 3
0100 Response: >4 0 B 3
0100 Response:  4 0 B 3
0100 Response: 44 0 B 3
0100 Response:  4 0 B 3
0100 Response: >4 0 B 3
0100 Response:  4 0 B 3
0100 Response: >4 0 B 3
0100 Response:  4 0 B 3
0100 Response: >4 0 B 3
0100 Response:  4 0 B 3
0100 Response: 4100BE3E
Protocol:  1
SPEED: 190 km/h
RPM: 12175
SPEED: 190 km/h
RPM: 12175
SPEED: 190 km/h
RPM: 12175
SPEED: 190 km/h
RPM: 12175
SPEED: 13 km/h
RPM: 832
SPEED: 12 km/h
RPM: 799
SPEED: 15 km/h
RPM: 1439
SPEED: 0 km/h
RPM: 0
SPEED: 12 km/h
RPM: 832
SPEED: 13 km/h
RPM: 799
SPEED: 12 km/h
RPM: 768
SPEED: 12 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: -14465 km/h
RPM: 1311
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 67
SPEED: 1 km/h
RPM: 768
SPEED: 1 km/h
RPM: 960
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: 12 km/h
RPM: 832
SPEED: 13 km/h
RPM: 1311
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 799
SPEED: 13 km/h
RPM: 863
SPEED: 15 km/h
RPM: 67
SPEED: 13 km/h
RPM: 835
SPEED: -10369 km/h
RPM: -8225
SPEED: 12 km/h
RPM: 960
SPEED: 15 km/h
RPM: 8159
SPEED: 3199 km/h
RPM: 768
SPEED: 13 km/h
RPM: 832
SPEED: 127 km/h
RPM: 832
SPEED: 13 km/h
RPM: 768
SPEED: 215 km/h
RPM: 13760
SPEED: 12 km/h
RPM: 67
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: 12 km/h
RPM: 67
SPEED: 1 km/h
RPM: 832
SPEED: 13 km/h
RPM: 0
SPEED: 0 km/h
RPM: 768
SPEED: 127 km/h
RPM: 67
SPEED: 13 km/h
RPM: 832
SPEED: 12 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 768
SPEED: 12 km/h
RPM: -8225
SPEED: 1 km/h
RPM: 835
SPEED: 13 km/h
RPM: 960
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: -14465 km/h
RPM: 960
SPEED: 13 km/h
RPM: 832
SPEED: 12 km/h
RPM: 832
SPEED: 13 km/h
RPM: 832
SPEED: 13 km/h
RPM: 768
SPEED: 12 km/h
RPM: -8225
SPEED: 10 km/h
RPM: 640
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 0 km/h
RPM: 0
SPEED: 218 km/h
RPM: 13954
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 613
Posts: 49249
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are printing out the data from getResponse(), even if the response is not complete. That explains a lot of the garbage.

Similarly, you are using the data before you get a complete response, so that explains the rest of the garbage.

getResponse() should either block until a complete response arrives, or it should return a value indicating whether the response is complete, or not (that is, the \r has arrived).
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, i've changed the code a bit, but it doesn't seem to make any difference, what am i missing?

Code:
//This is a character buffer that will store the data from the serial port
char rxData[20];
char rxIndex=0;

//Variables to hold the speed and RPM data.
int vehicleSpeed=0;
int vehicleRPM=0;

boolean gotResponse = false;

void setup(){

  Serial1.begin(9600);
  Serial.begin(9600);   //This is for the serial debug

  //Wait for a little while before sending the reset command to the OBD-II-UART
  delay(1500);
  //Reset the OBD-II-UART
  Serial1.print("ATWS\r");
  //Wait for a bit before starting to send commands after the reset.
  delay(1000);
 
  // turn echo off
  Serial1.print("ATE0\r");
 
  // send 01 00 until we are connected
  do
  {
    Serial1.print("0100\r");
    delay(1000);
    getResponse();    //This is only called once since the echo has been turned off using ATE0\r
    Serial.print("0100 Response:  ");
    Serial.print(rxData[0]);Serial.print(rxData[1]);Serial.print(rxData[3]);Serial.print(rxData[4]);Serial.print(rxData[6]);Serial.print(rxData[7]); Serial.print(rxData[9]);Serial.print(rxData[10]);
    Serial.println("");
  }
  while(ELM_CHECK_RESPONSE("0100", rxData)!=0);
 
  gotResponse = false;
   
  Serial1.print("ATDPN\r");  //Shows the protocol
  getResponse();
  Serial.print("Protocol: ");Serial.print(rxData[0]);Serial.print(rxData[1]);Serial.println("");
  // str[0] should be 'A' for automatic
  // set header to talk directly to ECU#1
  if(rxData[1]=='1')  // PWM
    Serial1.print("ATSHE410F1\r");
  else if(rxData[1]=='2')  // VPW
    Serial1.print("ATSHA810F1\r");
  else if(rxData[1]=='3')  // ISO 9141
    Serial1.print("ATSH6810F1\r");
  else if(rxData[1]=='6')  // CAN 11 bits
    Serial1.print("ATSH7E0\r");
  else if(rxData[1]=='7')  // CAN 29 bits
    Serial1.print("ATSHDA10F1\r");
}

void printSpeed(){
  //Convert the string data to an integer
  vehicleSpeed = strtol(&rxData[6],0,16);
 
  Serial.print("SPEED: ");
  Serial.print(vehicleSpeed);
  Serial.print(" km/h");
  Serial.println(" ");

  gotResponse = false;
}

void printRpm(){
  //Convert the string data to an integer
  //NOTE: RPM data is two bytes long, and delivered in 1/4 RPM from the OBD-II-UART
  vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;

  //Print the rpm data to debug serial window
  Serial.print("RPM: ");
  Serial.print(vehicleRPM);
  Serial.println(" ");
 
  gotResponse = false;
}

void loop(){
  //Query the OBD-II-UART for the Vehicle Speed
  Serial1.print("010D\r");   
  delay(20);
  //Get the response from the OBD-II-UART board. We get two responses
  //because the OBD-II-UART echoes the command that is sent.
  //We want the data in the second response.
  getResponse();

  while(gotResponse == false){
    // Loop until getResponse() is done
  }
  printSpeed();

  //Print the speed data to debug serial window
 
  delay(20);
 
  //Query the OBD-II-UART for the Vehicle rpm
  Serial1.println("010C\r");
  delay(20);
  //Get the response from the OBD-II-UART board
  getResponse();
 
  while(gotResponse == false){
    // Loop until getResponse() is done
  }
  printRpm();
 
  //Give the OBD bus a rest
  delay(5000);
}

byte ELM_CHECK_RESPONSE(const char *cmd, char *str)
{
  // cmd is something like "010D"
  // str should be "41 0D blabla"
  if(cmd[0]+4 != rxData[0]
    || cmd[1]!= rxData[1]
    || cmd[2]!= rxData[3]
    || cmd[3]!= rxData[4])
    return 1;

  return 0;  // no error
}

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;
        gotResponse = true;
      }
      //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();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
  }
}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 613
Posts: 49249
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
what am i missing?
Any character that is not a '\r' should cause gotResponce to be set to false.

Code:
    getResponse();    //This is only called once since the echo has been turned off using ATE0\r
    Serial.print("0100 Response:  ");
    Serial.print(rxData[0]);Serial.print(rxData[1]);Serial.print(rxData[3]);Serial.print(rxData[4]);Serial.print(rxData[6]);Serial.print(rxData[7]); Serial.print(rxData[9]);Serial.print(rxData[10]);
    Serial.println("");
So, now getResponse() sets a flag. Let's just ignore it... Why are we bothering to set the flag?

Code:
  while(gotResponse == false){
    // Loop until getResponse() is done
  }
The comment is wrong. "Loop forever" would be correct.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
  }


Im kinda curious you say that its printing the response before it has been fully received.
who is that possible, as far as i can see it has a while loop that is checking to see if the \r is received
why is that not enough ? how is it escaping from that ? and why will it work to add a flag and another while loop that essentially does the same check?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Changed the init loop to this:

Code:
  do
  {
    Serial1.print("0100\r");
    delay(1000);
    getResponse();    //This is only called once since the echo has been turned off using ATE0\r
    while(gotResponse == false){}
    Serial.print("0100 Response:  ");
    Serial.print(rxData[0]);Serial.print(rxData[1]);Serial.print(rxData[3]);Serial.print(rxData[4]);Serial.print(rxData[6]);Serial.print(rxData[7]); Serial.print(rxData[9]);Serial.print(rxData[10]);
    Serial.println("");
  }
  while(ELM_CHECK_RESPONSE("0100", rxData)!=0);

And added gotResponse = false here:

Code:
else{
        //Get the new character from the Serial port.
        inChar = Serial1.read();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
        gotResponse = false;
      }

Still no difference, there must be something else going on?
Logged

Sydney
Offline Offline
Full Member
***
Karma: 2
Posts: 108
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe you can give this a try.
Logged


Pages: [1]   Go Up
Jump to: