I am working on a project that I am taking over from someone else. I’m new to Arduino and am not a full time programmer. I know the basics but need help as much as I can get. I have the following components:
I am trying to write to the SD card, and print to the LCD also. For now I am only trying to read RPM and temp because thats what the code I was given does. I can save the files to the SD but they are blank, and nothing reads to the LCD. can anyone help double check my code and see whats going on?
I really appreciate any help.
FP
//Define Serial Ports so I remember which is which
#include <SoftwareSerial.h>
#include <Wire.h>
#include <SD.h>
//#include "RTClib.h"
//Create an instance of the new soft serial library to control the serial LCD
//Note, digital pin 3 of the Arduino should be connected to Rx of the serial LCD.
SoftwareSerial lcd(2,3);
File logfile;
//RTC_DS1307 RTC;
//Set up ring buffer
char rxData[20];
char rxIndex=0;
char filename[11];
void setup()
{
lcd.begin(19200);
Serial.begin(9600);
//Clear the old data from the LCD.
lcd.write(254);
lcd.write(1);
lcd.print("Temp: ");
lcd.write(254);
lcd.write(128+64);
lcd.print("RPM: ");
// creating SD files
delay(5000);
if(!SD.begin(10))
{
Serial.println("Card failed");
}
char temp[] = "DATA00.csv";
for (int i=0; i< 11; i++){
filename[i] = temp[i];
}
bool isFound = false;
for (uint8_t i=0; i< 10; i++)
{
for (uint8_t j=0; j<10; j++)
{
if(!isFound)
{
filename[4]= i + '0';
filename[5]= j + '0';
if(!SD.exists(filename))
{
isFound = true;
}
}
}
}
logfile = SD.open(filename, FILE_WRITE);
if (! logfile) {
Serial.println("couldnt create file");
}
Serial.println("Logging to: ");
Serial.print(filename);
Wire.begin();
//if(!RTC.begin()){
//logfile.println("RTC failed");
//}
logfile.print("rpm,");
// logfile.close();
ODB_init();
}
void loop()
{
//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.print(" ");
lcd.write(254);
lcd.write(128 + 69);
int rpm = getRPM();
lcd.print(rpm); //Print the int returned from getRPM
// logfile = SD.open(filename, FILE_WRITE);
//DateTime now = RTC.now();
//Serial.println("SECONDS: " + now.second());
Serial.println("RPM: "+rpm);
//logfile.print(now.minute() + ",");
logfile.print(rpm + ",");
// logfile.close();
Serial.flush();
lcd.print(" ");
lcd.write(254);
lcd.write(128 + 6);
lcd.print(getTemp()); //Print the int returned from getTemp
lcd.print(" C");
delay(200); //wait .2 seconds and grab another reading
}
void ODB_init(void)
{
//Wait for a little while before sending the reset command to the OBD-II-UART
delay(2000);
//Reset the OBD-II-UART
Serial.print("ATZ\r");
//Wait for a bit before starting to send commands after the reset.
delay(2000);
OBD_read();
Serial.print("ATE0\r");
OBD_read();
Serial.flush();
}
int getRPM(void)
{
//Query the OBD-II-UART for the Vehicle rpm
Serial.flush();
Serial.print("010C\r");
OBD_read();
return ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;
}
int getTemp(void)
{
//Query the OBD-II-UART for the Engine Coolant Temp
Serial.flush();
Serial.print("0105\r");
OBD_read();
return strtol(&rxData[6],0,16)-40;
}
void OBD_read(void)
{
char c;
do{
if(Serial.available() > 0)
{
c = Serial.read();
lcd.print(c);
if((c!= '>') && (c!='\r') && (c!='\n')) //Keep these out of our buffer
{
rxData[rxIndex++] = c; //Add whatever we receive to the buffer
}
}
}while(c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
rxData[rxIndex++] = '\0';//Converts the array into a string
rxIndex=0; //Set this to 0 so next time we call the read we get a "clean buffer"
}
It was not commented out when I was using the code. I don’t remember why I commented it out in the above.
I have since worked on it some more. Below is the current state of the code. It is now reading data but sitting with the car parked in the garage I am getting 167,168, etc MPH. I am also getting nearly 1800 RPM. I know these values are not correct but not sure how to correct them.
Thank you for the help.
FP
#include <SoftwareSerial.h>
#include <Wire.h>
#include <SD.h>
//Create an instance of the new soft serial library to control the serial LCD
//Note, digital pin 3 of the Arduino should be connected to Rx of the serial LCD.
SoftwareSerial lcd(2,3);
File logfile;
//This is a character buffer that will store the data from the serial port
char rxData[20];
char rxIndex=0;
char filename[11];
//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.
lcd.begin(9600);
Serial.begin(9600);
//Clear the old data from the LCD.
lcd.write(254);
lcd.write(1);
//Put the speed header on the first row.
lcd.print("Speed: ");
lcd.write(254);
//Put the RPM header on the second row.
lcd.write(128+64);
lcd.print("RPM: ");
// creating the SD files
delay(1000);
if(!SD.begin(10))
{
Serial.println("Card failed");
}
char temp[] = "DATA00.csv";
for (int i=0; i< 11; i++){
filename[i] = temp[i];
}
bool isFound = false;
for (uint8_t i=0; i< 10; i++)
{
for (uint8_t j=0; j<10; j++)
{
if(!isFound)
{
filename[4]= i + '0';
filename[5]= j + '0';
if(!SD.exists(filename))
{
isFound = true;
}
}
}
}
logfile = SD.open(filename, FILE_WRITE);
if (! logfile) {
Serial.println("couldnt create file");
}
Serial.print("Logging to: ");
Serial.print(filename);
//
// Wire.begin();
// if(!RTC.begin()){
// logfile.println("RTC failed");
// }
logfile.print("vehicleSpeed, vehicleRPM,\n");
// logfile.close();
//Wait for a little while before sending the reset command to the OBD-II-UART
delay(1500);
//Reset the OBD-II-UART
Serial.println("ATZ");
//Wait for a bit before starting to send commands after the reset.
delay(2000);
//Delete any data that may be in the serial port before we begin.
Serial.flush();
logfile.close();
}
void loop(){
//Delete any data that may be in the serial port before we begin.
Serial.flush();
logfile = SD.open(filename, FILE_WRITE);
//Set the cursor in the position where we want the speed data.
lcd.write(254);
lcd.write(128+8);
//Clear out the old speed data, and reset the cursor position.
lcd.print(" ");
lcd.write(254);
lcd.write(128+8);
//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
vehicleSpeed = (strtol(&rxData[6],0,16)/1.6); // conversion to "km/h" then to "mph"
//Print the speed data to the lcd
lcd.print(vehicleSpeed);
lcd.print(" mph");
//Print the speed data to the Serial Monitor
Serial.print(vehicleSpeed);
Serial.print(" mph");
logfile.print(String(vehicleSpeed));
logfile.print(",");
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.write(254);
lcd.write(128 + 69);
//Clear the old RPM data, and then move the cursor position back.
lcd.print(" ");
lcd.write(254);
lcd.write(128+69);
//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
vehicleRPM = (((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4);
//Print the rpm data to the lcd
lcd.print(vehicleRPM);
Serial.print(vehicleRPM);
Serial.print(" RPM");
// logfile = SD.open(filename, FILE_WRITE);
logfile.print(String(vehicleRPM));
logfile.print("\n");
// logfile.close();
//Give the OBD bus a rest
delay(100);
logfile.close();
}
//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;
//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(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;
}
}
}
}
Thank you for the reply however I am getting everything to work. The problem is that the data is not correct. I am writing to the SD card, and writing to the LCD. I’m not sure what to do about the data being incorrect which is my problem. Any additional help is greatly appreciated.
Something must be going wrong in the OBD-II packet parsing. Without knowing what is sent to the arduino, and what it makes of this, it is hard to point at something specific. Dump the second getResponse to a debug file, and the RPM and MPH after it is calculated from that. Or better, dump both getResponses as it may have lost synchronisation. Who knows, it might be calculating based on the command string. While recording this also try to get an external measurement to verify both. Just by looking at the code nobody will become any wiser. You need raw data. At the very least upload the file it generates.
Also,is it always a steady 1800 rpm or 160 MPH or wildly fluctuating? Does it change in a certain rythm? That could help identify the way the data get’s corrupted.
Print rxData after you get it from the OBD2. That will tell you whether you are getting valid data back and there’s a bug in parsing it or if the OBD2 is returning the bad data.