SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By Mee_n_Mac
#144290
OK, I've looked over the tutorial code and your mods to it. There are some carry-overs from the 1'st to the 2'nd that I don't think are proper and might be screwing up your parallel LCD. In fact I'm not sure how it compliled (if it did). Then there are some mods I'd like to see added (as mentioned above and perhaps some more). Lastly I don't understand the tutorial code for getResponse(). I'll have to look at it more, but it would seem to wait forever in a loop until it sees the proper response from the OBDII. And it's called twice (?) but yet has a 20 byte buffer ?!?!? I'm missing something here. In any case it should have an escape method and display something like "no comm" if there's no proper response from the OBDII in some specified time period. Let's see if I can whip up something in the next hour or so.
By djarmyssg
#144291
That would be AWESOME... Im tottally at a lose here... I just want to see the shield call back and say SOMETHING!! "hey im here, Im getting ur commands, just cant connect to OBD" not matter what I do though, I dont get anything!
By djarmyssg
#144293
Ok well I tried a couple more things.... I gotta be up by 5am... So imma clock out for tonight! definitly gonna keep working on her tommorow though.. I really appreciate your help man!! Thanx!
By Mee_n_Mac
#144296
Here's my first take on doing what I said above. I added some easy "prints" to the LCD just to see if that part works independantly of the OBDII. Then I added a "print" to the LCD of the response message to the ATZ reset. Hopefully it's much like the one shown in the tutorial and not longer than 16 characters. I'm fuzzy as to the proper way to send that response string to the LCD; whether it should be this ...
lcd.print(rxData);
... or this ...
lcd.print(rxData[]);
... or this ...
lcd.print(rxData, string);
... or something else. It's the first one right now but if the compiler squawks, change it around.

For that matter if you can't find a way to print the actual response string to the LCD, simply send a "Message rcvd" to the LCD. That may be enough to know there's good comm btw the Arduino and ODII. Then if you don't get any data for the speed and RPM, you'll know it's some odd setup or comm problem btw the OBDII and the car. And on that note ... wasn't there someting about commanding an auto setup of the OBDII to detect the proper protocol to use for the car in the tutorial example #1 ? If you don't get any data from the car, that may need to be added/done.

I also added a time out to the getResponse() function and if there's no reponse in 1 sec, the LCD should indicate "No data". So look at the following and make sure I've not missed anything obvious, see if it makes sense to you and then give it a try.
Code: Select all
#include <LiquidCrystal.h>

#define LCD_RS 4
#define LCD_ENABLE 5

#define LCD_DATA1 7
#define LCD_DATA2 8
#define LCD_DATA3 12
#define LCD_DATA4 13

LiquidCrystal lcd(LCD_RS, LCD_ENABLE, LCD_DATA1, LCD_DATA2, LCD_DATA3, LCD_DATA4);
#define ContrastPin 6
#define BrightnessPin 9


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

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

void setup(){
  //Both the Serial LCD and the OBD-II-UART use 9600 bps.
  Serial.begin(9600);
  
  //Delete any data that may be in the serial port before we begin.
  delay (100);
  Serial.flush();

  //Init and clear the old data from the LCD.
  lcd.begin(16, 2);
  lcd.clear();
  // Put a Hello World message on the LCD.
  lcd.print("  Initializing  ");
  delay (1000);  
  lcd.setCursor(0, 1);
  lcd.print(" Reseting OBDII ");
  delay (1000);
  
  //Reset the OBD-II-UART
  Serial.println("ATZ");
  // Ignore the echo and use the second true response - if any
  getResponse();
  getResponse();
  
  // Show what came back.
  lcd.clear();
  // Now show what are we doing.
  lcd.print("Response message");
  lcd.setCursor(0, 1);
  if(rxIndex)
  {
    lcd.print(rxData);
  }
  else
  {
    lcd.print(" no response");
  }
  
  delay (5000);  // wait long enough for user to see response
  //Hoping the above worked, now put the speed header on the first row.
  lcd.clear();
  lcd.print("Speed: ");
  //Put the RPM header on the second row.
  lcd.setCursor(0, 1);
  lcd.print("RPM: ");
  //Wait for a bit before starting to send commands after the reset.
  delay(2000);
  
}

void loop(){
  //Delete any data that may be in the serial port before we begin. 
  Serial.flush();
  //Set the cursor in the position where we want the speed data.
  lcd.setCursor(7, 0);
  //Clear out the old speed data, and reset the cursor position.
  lcd.print("        ");  // need 8 spaces for speed data
  lcd.setCursor(7, 0);
  
  //Query the OBD-II-UART for the Vehicle Speed
  Serial.println("010D");
  
  //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
  if(rxIndex) // test to see if anything was received from OBDII
  {
    vehicleSpeed = strtol(&rxData[6],0,16);
    //Print the speed data to the lcd
    lcd.print(vehicleSpeed);
  }
  else
  {
    lcd.print("No data");
  } 
  delay(100);
  
  //Delete any data that may be left over in the serial port.
  Serial.flush();
  //Move the serial cursor to the position where we want the RPM data.
  lcd.setCursor(5, 1);
  //Clear the old RPM data, and then move the cursor position back.
  lcd.print("          ");  // need 10 spaces for RPM data ?
  lcd.setCursor(5, 1);

  //Query the OBD-II-UART for the Vehicle rpm
  Serial.println("010C");
  //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
  if(rxIndex) // test to see if anything was received from OBDII
  {
    vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;
    //Print the rpm data to the lcd
    lcd.print(vehicleRPM);
  }
  else
  {
    lcd.print("No data");
  }
  
  //Give the OBD bus a rest
  delay(300);
}

//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;
  rxIndex=0;
  unsigned long TimeIn = millis();
  //Keep reading characters until we get a carriage return or time out
  while(inChar != '\r'){
    //If a character comes in on the serial port, we need to act on it.
    if(Serial.available() > 0){
      //Start by checking if we've received the end of message character ('\r').
      if(Serial.peek() == '\r'){
        //Clear the Serial buffer
        inChar=Serial.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 = Serial.read();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
    if (millis() - TimeIn > 1000) // wait 1 sec for some kind of response
    {
      break;
    } 
  }
}
FWIW I had to delete the "km/hr" after the speed reading as you may not have enough characters in the 16x2 LCD. The tutorial code reserved a (?too?) large set of characters for the data. I have to believe it (and RPM) are really less than the 8-10 spaces but should this work, that can be fixed if desired. Afterall this is just test/debug code, not the end "product". I also changed the rxIndex from a char to a byte as it's used as a counter/index and not really as a character variable (shouldn't make any real difference but ...).
Last edited by Mee_n_Mac on Thu May 10, 2012 9:35 pm, edited 1 time in total.
By djarmyssg
#144297
Wow.... That looks amazing!!!! I didnt have a chance to plug into my obd... but i did a quick upload and now im actually seeing the tx/rx on the shield lighting up!!! Which is a first!!!! Tommorow morning ill plug her in and see what she does.... Definitly getting a good feeling about it though. Thnks soooo much!
By Mee_n_Mac
#144298
djarmyssg wrote:Wow.... That looks amazing!!!! I didnt have a chance to plug into my obd... but i did a quick upload and now im actually seeing the tx/rx on the shield lighting up!!! Which is a first!!!! Tommorow morning ill plug her in and see what she does.... Definitly getting a good feeling about it though. Thnks soooo much!
Even w/o the car, the OBDII should (ideally) be getting a request for data every couple of seconds or so ... now, with the timeout added to the code. Let me know if the LCD shows anything. Even w/o the car it should. If it doesn't, that needs to get fixed. It's the only** way you'll get to see the responses from the OBDII, whatver they are ... or aren't.

BTW re-read my earlier post and check the code again as I was changing it and noticed you were online during the edits.

**unless you want to use a "soft" UART to talk to the OBDII. Then you could relay the messages from the OBDII to the PC via the normal route, keeping the serial links btw the PC and OBDII separate. You still have some spare I/O pins.
By Mee_n_Mac
#144300
Here's my last-for-the-moment shot at getting the OBDII to talk to the Arduino and the car. I added the auto protocol command ala the tutorial example #1. I'm also semi-sure the lcd.print(rxData) is proper (but if not, comment that part out and uncomment the lcd.print(" Got a message");). Lastly after looking at the serial monitor screen caps in example #1, I don't see the 2 responses, the command echo and the real response, that the tutorial code seems to think there is. So for any responses to the reset and auto-protocol commands I "print" to the LCD both the 1'st and 2'nd responses, with a couple of secs in between. I guess you should see the echo and then the "ELM ..." (or the "OK" for the ATSP0 command) displayed. Or maybe not. There seems to be a disconnect btw the tutorial code and the example #1 results shown.
Code: Select all
#include <LiquidCrystal.h>

#define LCD_RS 4
#define LCD_ENABLE 5

#define LCD_DATA1 7
#define LCD_DATA2 8
#define LCD_DATA3 12
#define LCD_DATA4 13

LiquidCrystal lcd(LCD_RS, LCD_ENABLE, LCD_DATA1, LCD_DATA2, LCD_DATA3, LCD_DATA4);
#define ContrastPin 6
#define BrightnessPin 9


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

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

void setup(){
  //Both the Serial LCD and the OBD-II-UART use 9600 bps.
  Serial.begin(9600);
  
  //Delete any data that may be in the serial port before we begin.
  delay (100);
  Serial.flush();

  //Init and clear the old data from the LCD.
  lcd.begin(16, 2);
  lcd.clear();
  // Put a Hello World message on the LCD.
  lcd.print("  Initializing  ");
  delay (1000);  
  lcd.setCursor(0, 1);
  lcd.print(" Reseting OBDII ");
  delay (2000);  // allow user time to look towards OBDII LEDs
  
  //Reset the OBD-II-UART
  Serial.println("ATZ");
  
  // Show both responses - if any
  getResponse();  // get first response
  
  // Show what came back.
  lcd.clear();
  // Now show what are we doing.
  lcd.print("Reset response");
  lcd.setCursor(0, 1);
  if(rxIndex)
  {
    lcd.print(rxData);  // should be cmd echo ??
    // lcd.print(" Got a message");
  }
  else
  {
    lcd.print(" no response");
  }
  delay (2000);  // wait just long enough for user to see 1st response
  
  // Now get 2nd real response ??
  getResponse();
  
  lcd.setCursor(0, 1);
  lcd.print("                ");  // erase prior response
  if(rxIndex)
  {
    lcd.print(rxData);  // should be ELM ... 
    // lcd.print(" Got a message");
  }
  else
  {
    lcd.print(" no response");
  }
  delay (5000);  // wait long enough for user to see responses
  
  //Now command the OBDII to auto-detect the proper protocol as done in example 1.
  Serial.println("ATSP0");
  // Again show both responses - if any
  getResponse();
  
  // Show what came back.
  lcd.clear();
  lcd.print("Auto protocol");
  lcd.setCursor(0, 1);
  if(rxIndex)
  {
    lcd.print(rxData);  // should be cmd echo ?
    // lcd.print(" Got a message");
  }
  else
  {
    lcd.print(" no response");
  }
  delay (2000);  // wait just long enough for user to see 1st response
  
  // Now get 2nd real response ??
  getResponse();
  lcd.setCursor(0, 1);
  lcd.print("                ");  // erase prior response
  if(rxIndex)
  {
    lcd.print(rxData);  // should be OK
    // lcd.print(" Got a message");
  }
  else
  {
    lcd.print(" no response");
  }
  delay (5000);  // wait long enough for user to see responses

  //Hoping the above worked, now put the speed header on the first row.
  lcd.clear();
  lcd.print("Speed: ");
  //Put the RPM header on the second row.
  lcd.setCursor(0, 1);
  lcd.print("RPM: ");
  //Wait for a bit before starting to send commands after the reset.
  delay(2000);
}

void loop(){
  //Delete any data that may be in the serial port before we begin. 
  Serial.flush();
  //Set the cursor in the position where we want the speed data.
  lcd.setCursor(7, 0);
  //Write over the old speed data, and then reset the cursor position.
  lcd.print("        ");  // need 8 spaces for speed data per old code
  lcd.setCursor(7, 0);
  
  //Query the OBD-II-UART for the Vehicle Speed
  Serial.println("010D");
  
  //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
  if(rxIndex) // test to see if anything was received from OBDII
  {
    vehicleSpeed = strtol(&rxData[6],0,16);
    //Print the speed data to the lcd
    lcd.print(vehicleSpeed);
  }
  else
  {
    lcd.print("No data");
  } 
  delay(100);
  
  //Delete any data that may be left over in the serial port.
  Serial.flush();
  //Move the serial cursor to the position where we want the RPM data.
  lcd.setCursor(5, 1);
  //Clear the old RPM data, and then move the cursor position back.
  lcd.print("          ");  // need 10 spaces for RPM data ?
  lcd.setCursor(5, 1);

  //Query the OBD-II-UART for the Vehicle rpm
  Serial.println("010C");
  //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
  if(rxIndex) // test to see if anything was received from OBDII
  {
    vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;
    //Print the rpm data to the lcd
    lcd.print(vehicleRPM);
  }
  else
  {
    lcd.print("No data");
  }
  
  //Give the OBD bus a rest
  delay(300);
}

//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;
  rxIndex=0;
  unsigned long TimeIn = millis();
  //Keep reading characters until we get a carriage return or time out
  while(inChar != '\r'){
    //If a character comes in on the serial port, we need to act on it.
    if(Serial.available() > 0){
      //Start by checking if we've received the end of message character ('\r').
      if(Serial.peek() == '\r'){
        //Clear the Serial buffer
        inChar=Serial.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 = Serial.read();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
    if (millis() - TimeIn > 1000) // wait 1 sec for some kind of response
    {
      break;
    } 
  }
}
The testing ball is in your court ! :twisted:
By djarmyssg
#144324
OK Mac, Heres what i got so far....

I ran the program with the ground wire from the shield to the arduino.... NOTHING.. got "NO Response" for everything, and "No data" for RPM and Speed.... Now I took the ground wire off, and seems like she came alive... didnt get ANY information, where it would say "No response" It was just blank. And where it said "no data" now I get "0". and the TX/RX flashes like its getting info. I took a video.. but cant upload it yet, Im wondering if the data needs to be converted to "char" before the screen can show it??? not quites sure yet.. Still working on it though. as soon as i get the video uplaoded, I'll post!
By Mee_n_Mac
#144326
Hmmm, let's see the video first and then I may have some questions. What did the serial monitor on the PC show when this was all happening ? I hope it showed the ATZ and then the ATSP0 followed by repreated commands for the speed and RPM (whatever those codes are).

ps - well at least it seems the LCD is now working ! :shifty:
By dkulinski
#144329
Just an FYI, you do need to change it into the character equivalent of the numeral. The easy way is to add each numeral to 0. Mee_n_Mac has some of my code that I used to do that in another project which I don't currently have access to. I am sure he can supply it if it already isn't in the code he handed you.

Dan
By djarmyssg
#144330
Mac, Yea, The serial monitor looked like it was sending the right commands... Still havent seen any real actions saying the shield is actually sending back real data... But it seems to be getting there!!!

Dan... Thanx for the info!!!! Mac has been helping me a ton!!
By Mee_n_Mac
#144333
It certainly looks like you're getting data back w/o the ground wire. I think I see the command echo for the ATZ and ATSP0 commands. I didn't see the proper responses to those commands but I may not have left enough time for them to display properly. I'll go fix that.

Just a stupid question but was the car running when you did this test ? I expect 0 for speed at all times since you're not moving, and perhaps 0 for RPM w/o the engine turning.
By djarmyssg
#144334
Im actually starting to wonder if the ground might not be helpin anything by bein dissconnected. I get the exact same responses if i have it plugged into the car, as i do when its not plugged into the car.... So im thinking its not doing much either way.... Ughhhh starting to get agrivated.... But anyways.. i did have her engine running and at one point i drove her around to check the speed output!!! Still nothing :violin:
By dkulinski
#144335
I quickly skimmed over the previous posts, but was it discovered if the ODB UART is sending out TTL level serial or RS-232 level serial? If it is the latter you will of course need something like the MAX232 to convert the voltages.

EDIT: Nevermind, found the tutorial showing a direct connection to the Arduino.

Dan