Pages: 1 2 [3]   Go Down
Author Topic: OBDII to UART Issues  (Read 5823 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here it is, much appreciated. Just gonna test RPM and speed for now.

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);
 
  Serial1.print("ATDPN\r");  //Shows the protocol
  delay(1000);
 
  Serial1.print("0100\r"); 
  delay(2000);
 
  //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();
  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();
  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);
 
}



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;
      }
    }
  }
}
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

Any luck with the testing? Thanks man.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4763
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I tested your code but before I inserted a bit more debugging output. I wrote every byte I received to the debugging serial and so I found several problems in your code. First of all: your interpreting a fixed protocol but the ELM 327 does communicate some errors too. The delays are absolutely no help, they just impose problems. But the good news are: the ECU responded to your code and from time to time it even got the correct speed and RPMs.

If you wanna go on with your car display you should definitely take a look at the OBDuino code. I took it as a base for my own code and got everything running in much less time than it would have needed if I wrote everything myself.

The debugging is not easy, I have to install my netbook in my car, connect everything together, start the car and see what's happening on the serial terminal. All this is taking place in the basement, four floors lower.

This is the log of the initialization and first value requests of the OBDuino code in my car:

Code:
elm_write: (ATWS^M)
elm_read: (ELM327 v1.3a)
elm_write: (ATE0^M)
elm_read: (ATE0OK)
elm_write: (0100^M)
elm_read: (SEARCHING...41 00 BE 3F A8 13 )
elm_write: (0100^M)
elm_read: (41 00 BE 3F A8 13 )
elm_write: (ATDPN^M)
elm_read: (A7) -> 4137
elm_write: (ATSHDA10F1^M)
elm_read: (OK)
elm_write: (0100^M)
elm_read: (41 00 BE 3F A8 13 )
elm_write: (0120^M)
elm_read: (41 20 80 1D B0 11 )
elm_write: (0140^M)
elm_read: (41 40 7A D0 00 00 )
elm_write: (010C^M)
elm_read: (41 0C 00 00 )
elm_write: (010C^M)
elm_read: (41 0C 00 00 )
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there and thanks for your time and effort testing the code, I very much appreciate it!

The protocol will be fixed for the moment as it will going on 1 particular car, but it would be good to make it "universal".

Would there be anyway of sharing your code with me at all?

Thanks.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4763
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Which one? Your's adapted by me to include debugging output or my version of the OBDuino?
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your version of OBDuino.
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is my version of OBDuino from their code:

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;
      }
    }
  }
}
« Last Edit: July 05, 2012, 06:24:42 am by matinzk » Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Pylon,

Did you ever manage to test my code at all?

Thanks.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4763
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not yet, I'm currently running my own software on the device. I try to find time the end of the week to change that again.
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 238
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you.
Logged

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

Hi Guys.

Great thread, It has been very helpful for me looking at some example codes.
I have been experimenting with the ELM327 and I wish to switch off the spaces between the sections of the message transmitted.

For example, as default with the spaces on, for 1000 RPM I am getting:
41 0C 0F A0

With the spaces off this will become:
410C0FA0

Code for use when spaces are being transmitted from the ELM327: (From the example code and it works great).
vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;

However the code when spaces are NOT being transmitted from the ELM327: I have been battleing away and I am getting stuck.
vehicleRPM = ((strtol(&rxData[4],0,16)*256)+strtol(&rxData[6],0,16))/4;

Basically I have tried moving the tried the value of the rxData to be where I believe the data will now be.
I think that I do not fully understand the function in use here, any advice would be great.

Thanks guys

Keith
Logged

Pages: 1 2 [3]   Go Up
Jump to: