Struggling with K-Line ISO 9141-2 Communication

Hello everyone,

I’ve been working on a project to establish communication using Arduino Uno with a vehicle's K-Line (ISO 9141-2) protocol, but I’ve hit a roadblock that I can’t seem to solve despite spending countless hours troubleshooting.

Currently, I’m trying to initialize the ISO9141 communication. The serial monitor shows the following messages: ISO9141 initializing... First 3 Bytes: 55 8 8 Other Bytes: F7 Initialization Successful !!

The issue is that while the serial monitor indicates a successful initialization, the byte sequence seems unexpected to me. I’m not sure if I’m missing a step in the timing, configuration, or if there’s a problem with the hardware itself.

I've already tried various resistor values, changed the timing delays, and swapped out components, but I’m still getting the same result.

If anyone has experience with ISO9141-2 or any tips on why I’m seeing this particular sequence, your input would be greatly appreciated!

#include <AltSoftSerial.h>
AltSoftSerial K_Serial;

// Define Pins
#define K_line_RX 8
#define K_line_TX 9
#define Led 13

// Define Delays
#define READ_DELAY 5
#define REQUEST_DELAY 500

int SPEED, RPM, THROTTLE, COOLANT_TEMP, INTAKE_TEMP, VOLTAGE;
bool KLineStatus = false;
static unsigned long lastReqestTime = 0;

uint8_t result = 0;
uint8_t resultBuffer[20];
uint8_t initBuffer[20];

int dtcs = 0;
char dtc_Byte_1, dtc_Byte_2;
String dtcBuffer[20];

const byte read_DTCs[4] = { 0x68, 0x6A, 0xF1, 0x03 };   // Read Troubleshoot Codes
const byte clear_DTCs[4] = { 0x68, 0x6A, 0xF1, 0x04 };  // Clear Troubleshoot Codes

// Request data bytes for slow init (ISO9141 and KWP slow)
const byte read_PIDs_20[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x00 };  // Read suported PIDs 0-20
const byte read_PIDs_40[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x20 };  // Read suported PIDs 20-40
const byte read_PIDs_60[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x40 };  // Read suported PIDs 40-60
const byte read_PIDs_80[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x60 };  // Read suported PIDs 60-80
const byte read_PIDs_A0[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x80 };  // Read suported PIDs 80-A0
const byte read_PIDs_C0[5] = { 0x68, 0x6A, 0xF1, 0x01, 0xA0 };  // Read suported PIDs A0-C0
const byte read_PIDs_E0[5] = { 0x68, 0x6A, 0xF1, 0x01, 0xC0 };  // Read suported PIDs A0-E0

const byte speed_obd[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x0D };
const byte rpm_obd[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x0C };
const byte throttle_obd[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x11 };
const byte coolant_temp_obd[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x05 };
const byte intake_temp_obd[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x0F };
const byte voltage_obd[5] = { 0x68, 0x6A, 0xF1, 0x01, 0x42 };

void setup() {
  Serial.begin(9600);
  pinMode(K_line_RX, INPUT_PULLUP);
  pinMode(K_line_TX, OUTPUT);
  pinMode(Led, OUTPUT);
}

void loop() {
  if (KLineStatus == false) {
    if (millis() - lastReqestTime >= 5000) {
      Serial.println("Initialising ISO9141...");
      bool init_success = init_ISO9141();
      if (init_success) {
        KLineStatus = true;
        digitalWrite(Led, HIGH);
        Serial.println("Init Success !!");
        read_DTC();
      }
      lastReqestTime = millis();
    }
  } else {
    read_K();
  }
}

void read_K() {
  //------------------------------------------------------ get speed
  writeData(speed_obd, sizeof(speed_obd));
  readData();

  if (resultBuffer[10] == 0x0D) {
    SPEED = resultBuffer[11];
    Serial.print("Speed: ");
    Serial.println(SPEED);
  }

  //------------------------------------------------------ get rpm
  writeData(rpm_obd, sizeof(rpm_obd));
  readData();

  if (resultBuffer[10] == 0x0C) {
    RPM = (resultBuffer[11] * 256 + resultBuffer[12]) / 4;
    Serial.print("RPM: ");
    Serial.println(RPM);
  }

  //------------------------------------------------------ get throttle
  writeData(throttle_obd, sizeof(throttle_obd));
  readData();

  if (resultBuffer[10] == 0X11) {
    THROTTLE = resultBuffer[11] * 100 / 255;
    Serial.print("Throttle: ");
    Serial.println(THROTTLE);
  }

  //------------------------------------------------------ get Coolant temp
  writeData(coolant_temp_obd, sizeof(coolant_temp_obd));
  readData();

  if (resultBuffer[10] == 0x05) {
    COOLANT_TEMP = resultBuffer[11] - 40;
    Serial.print("Coolant Temp: ");
    Serial.println(COOLANT_TEMP);
  }

  //------------------------------------------------------ get Intake temp
  writeData(intake_temp_obd, sizeof(intake_temp_obd));
  readData();

  if (resultBuffer[10] == 0x0F) {
    INTAKE_TEMP = resultBuffer[11] - 40;
    Serial.print("Intake Temp: ");
    Serial.println(INTAKE_TEMP);
  }

  Serial.println();
}

void read_DTC() {
  writeData(read_DTCs, sizeof(read_DTCs));
  delay(REQUEST_DELAY);
  result = K_Serial.available();
  if (result > 0) {
    // Serial.print("Buffer: ");
    for (int i = 0; i < result; i++) {
      resultBuffer[i] = K_Serial.read();
      delay(READ_DELAY);
      // Serial.print(resultBuffer[i], HEX);
      // Serial.print(" ");
    }
    // Serial.println();
    int length = result - 10;
    for (int i = 0; i < length; i++) {
      int index1 = 9 + i * 2;
      int index2 = 9 + i * 2 + 1;
      dtc_Byte_1 = resultBuffer[index1];
      dtc_Byte_2 = resultBuffer[index2];
      delay(READ_DELAY);

      if (dtc_Byte_1 == 0 && dtc_Byte_2 == 0) {
        if (i == 0) {
          Serial.println("Not Found Errors !");
        } else {
          Serial.println("Errors ended !");
        }
        Serial.println();
        return;
      } else {
        // Serial.print("Errors: "), Serial.print(dtc_Byte_1, HEX), Serial.print(" "), Serial.println(dtc_Byte_2, HEX);
        decodeDTC(dtc_Byte_1, dtc_Byte_2);
      }
    }
  }
}

void clear_DTC() {
  writeData(clear_DTCs, sizeof(clear_DTCs));
}

bool init_ISO9141() {
  K_Serial.end();

  digitalWrite(K_line_TX, HIGH), delay(300);
  digitalWrite(K_line_TX, LOW), delay(200);
  digitalWrite(K_line_TX, HIGH), delay(400);
  digitalWrite(K_line_TX, LOW), delay(400);
  digitalWrite(K_line_TX, HIGH), delay(400);
  digitalWrite(K_line_TX, LOW), delay(400);
  digitalWrite(K_line_TX, HIGH), delay(200);

  K_Serial.begin(10400);
  delay(REQUEST_DELAY);

  result = K_Serial.available();
  if (result > 0) {
    Serial.print("First 3 Bytes: ");
    for (int i = 0; i < result; i++) {
      initBuffer[i] = K_Serial.read();
      delay(READ_DELAY);
      Serial.print(initBuffer[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    if (initBuffer[0] == 0x55) {
      delay(30);
      K_Serial.write(~initBuffer[2]);  //0xF7
      delay(50);

      result = K_Serial.available();
      if (result > 0) {
        Serial.print("Other Bytes: ");
        for (int i = 0; i < result; i++) {
          initBuffer[i] = K_Serial.read();
          delay(READ_DELAY);
          Serial.print(initBuffer[i], HEX);
          Serial.print(" ");
        }
        Serial.println();
        return true;
      }
    }
  }
  return false;
}

void writeData(const byte data[], int length) {
  byte checksum = calculateChecksum(data, length);
  K_Serial.write(data, length);
  K_Serial.write(checksum);
}

void readData() {
  delay(REQUEST_DELAY);
  result = K_Serial.available();
  if (result > 0) {
    for (int i = 0; i < result; i++) {
      resultBuffer[i] = K_Serial.read();
      delay(READ_DELAY);
    }
  }
}

byte calculateChecksum(byte data[], int length) {
  byte checksum = 0;
  for (int i = 0; i < length; i++) {
    checksum += data[i];
  }
  return checksum % 256;
}

void decodeDTC(char input_byte1, char input_byte2) {
  String ErrorCode = "";
  const static char type_lookup[4] = { 'P', 'C', 'B', 'U' };
  const static char digit_lookup[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

  ErrorCode += type_lookup[(input_byte1 >> 6) & 0b11];
  ErrorCode += digit_lookup[(input_byte1 >> 4) & 0b11];
  ErrorCode += digit_lookup[input_byte1 & 0b1111];
  ErrorCode += digit_lookup[input_byte2 >> 4];
  ErrorCode += digit_lookup[input_byte2 & 0b1111];

  dtcBuffer[dtcs] = ErrorCode;
  Serial.print("Error Code: ");
  Serial.println(dtcBuffer[dtcs]);
  dtcs++;
}

This is the output I’m getting on the serial monitor using basic code on Arduino Uno. I’ve also encountered these errors when using a different code. Önceden bReceived Data: C1 33 F1 81 66
Initializing...
Writing Data...
Received Data: C1 33 F1 81 66
Initializing...
Writing Data...
Received Data: C1 33 F1 81 66
Initializing...içimlendirilmiş metin

Hello toprakbocu

Welcome to the best Arduino forum ever :slight_smile:

I had a quick look:

K_Serial.begin(I don´t know);

missing in the sketch.

hth

1 Like

Good morning,

I am currently working on my thesis project, which focuses on communication with the ECU of a 2024 Suzuki GSX-S150 motorcycle using an OBDII adapter cable. Our goal is to extract key information such as speed, RPM, fuel consumption, among others, through the diagnostic pins.

However, we have encountered an issue: we are unable to establish communication or retrieve any values. We suspect it may be related to the baud rate. According to the theory, to initiate communication, a hexadecimal code 33 is sent at 5 baud, and the ECU should respond with a hexadecimal 55 at 10400 baud. Despite following this procedure, we are not receiving any response.

We have also tried using an ELM327 adapter, but it returns an error, which I will attach along with the code we have been using for the project.

Any input or suggestions you can provide on how to proceed would be greatly appreciated.

Here is the code we are using:

#include <AltSoftSerial.h>

// Definir pines y constantes
AltSoftSerial KLine;  // Usaremos AltSoftSerial para la lectura de la respuesta
#define KLINE_PIN 9  // Pin para la K-Line

void setup() {
  // Inicializar la comunicación serie para depuración
  Serial.begin(9600);

  // Iniciar la comunicación serial en la K-Line
  KLine.begin(10400);  // Comenzar a 10400 baudios para leer la respuesta

  // Realizar secuencia de Wakeup
  Serial.println("Iniciando secuencia de Wakeup...");
  wakeupSequence();
}

void loop() {
  // Realizar Handshake a 5 baudios hasta que sea exitoso
  Serial.println("Iniciando handshake...");
  while (!handshakeSequence()) {
    Serial.println("Handshake fallido. Reintentando...");
    delay(1000);  // Esperar un momento antes de reintentar
  }

  Serial.println("Comunicación establecida.");
}

void wakeupSequence() {
  // Enviar el bit de wakeup manualmente
  pinMode(KLINE_PIN, OUTPUT);  // Control manual de la K-Line

  // Wakeup: Baja la K-Line a 0 por 200 ms, luego la sube a 12V (HIGH) por 20 ms
  digitalWrite(KLINE_PIN, LOW);
  delay(200);  // Baja a 0 por 200 ms
  digitalWrite(KLINE_PIN, HIGH);
  delay(20);   // Sube a HIGH por 20 ms

  Serial.println("Wakeup finalizado.");
}

bool handshakeSequence() {
  pinMode(KLINE_PIN, OUTPUT);
  Serial.println("Enviando byte 0x33 a 5 baudios...");

  // Secuencia de bits para 0x33 a 5 baudios:
  // Start bit (0) - 200 ms
  digitalWrite(KLINE_PIN, LOW);
  delay(200);

  // Bit 1 - 400 ms (dos bits 1 en 0x33)
  digitalWrite(KLINE_PIN, HIGH);
  delay(400);

  // Bit 0 - 400 ms (dos bits 0 en 0x33)
  digitalWrite(KLINE_PIN, LOW);
  delay(400);

  // Bit 1 - 400 ms (dos bits 1 en 0x33)
  digitalWrite(KLINE_PIN, HIGH);
  delay(400);

  // Bit 0 - 400 ms (dos bits 0 en 0x33)
  digitalWrite(KLINE_PIN, LOW);
  delay(400);

  // Bit de parada (1) - 200 ms
  digitalWrite(KLINE_PIN, HIGH);
  delay(200);

  // Cambiar el pin K-Line a entrada para recibir la respuesta
  pinMode(KLINE_PIN, INPUT);

  // Esperar y leer la respuesta del ECU
  delay(25);  // Pequeño retraso para permitir que la ECU responda
  if (KLine.available()) {
    uint8_t response = KLine.read();
    if (response == 0x55) {
      Serial.println("Respuesta de la ECU recibida: 0x55.");
      return true;  // Handshake exitoso
    } else {
      Serial.print("Respuesta inesperada de la ECU: ");
      Serial.println(response, HEX);
    }
  } else {
    Serial.println("No se recibió respuesta de la ECU.");
  }

  return false;  // Handshake fallido, se repetirá
}

And this is the error returned by the OBDII:

"Protocol check: 3) ISO 9141-2 (5 baud init, 10.4 kbaud) The ignition must be on or the engine must be started!"

Hello.
It's nice (but not nice), to see I'm not the only one struggling with what should be such a basic operation... It makes me feel Stupid !
From mid-late last year, I started trying to tie into the CAN bus on my 2006 Honda Accord.
Bit of a 'mare if not using an ESP32, and I couldn't get it to tie up with SavvyCAN on my Mac (I'm sure that was my fault).
But my biggest problem was that I have so little spare time, so I never managed to get anywhere.
My original goal was to get basic info such as RPM & Speed (possibly gear), to build myself a Cruise Control.
I'm electronics, but not much of a programmer.
Recently, I decided to put the CAN side on hold, & just tap into the (quote) 'Simple' OBD socket. That also allowed me to know in advance what the relevant PIDs would be.
I started by designing a better OBD Interface with FETs.
This allowed me to Disconnect the 510 ohm resistor across the K-Line (to B+), meaning Zero current drain when the uC is powered down.

Originally, I only had 4 FETs, thinking that I'd keep the logic as 1 on the Ardunio = 0v on the K-Line & Vice versa.
I had to rethink that & add 2 extra FETs to invert that, as ALL the code I found worked this way... that's fine.
I have started with an ESP32 as I want to use ESP-NOW feature.
Trouble is, Nothing I do gets a response from the car.
I've been using Ivor Wanders code examples & libs from Github:
wanders/OBD9141
He has some good info on the ReadMe file.

I've read the ISO standard, which says exactly what he does in respect of a Recessive wait period, then 1 Start Bit (Dominant, 0v), then the 0x33 initialiser (LS bit sent first).
Ive tried his ISO9141, ISO14230 (KWP), & KWP-Slow init, but Nada from the car.
Main reason I looked at the ISO9141 is because my cheap OBD Scanner states that as the Successful communication protocol (and there's No CAN or L-Line on the OBD socket)
I've used my handheld scope to prove that the Arduino signals are indeed being transferred onto the K-Line, in the correct logic.


Tonight I confirmed that my logic is exactly what you get if using a SN65HVDA195 LIN chip.
My biggest problem, is that Not being a programmer, I find it difficult working through the .cpp files, which are the backbone functions for his code.
I wouldn't spot a problem if it was right in front of me !
So I am delighted to find your code here.
I will endeavour to test it in the next couple of days, and report back any findings.

You probably already come across this International Standards Doc:
ISO9141-2
On Pg3, item 6, it discusses the 5-baud initialisation procedure, then goes on to give details of the Frame Formats etc ("Figure 4" doesn't show up till Pg5).

Sorry for 'Chewing your Ear off' here, but I will get back when I've tested your code.
Ta Muchly !

PS: Will I need the K_Serial.begin code, or is that just a link to AltSoftSerial (?).

1 Like

Hello again.
I never managed to get your code working in the (very) short time I had spare.
So - I only just came back to all this in the past weekend.
Can't remember why or how I got onto it, but I saw another GitHub page for OBD stuff:
OBD2_K-line_Reader
Looked interesting, as he had Allowance for both Arduino and ESP32 within the Code.

Yesterday, after making proper connections to my OBD lines in the car, I uploaded his code to my Nano & had a play.
Had an issue right away, where it got to the point where it said "Initialisation Success", but then just went back around the same loop & did the same Initialisation thing over & over.
Changed a line in the code to 'return true', and got past this (will investigate this properly later).
From then, this is the info I received from the Serial Monitor:

Initialising...
Received Data: 55 8 8 
Your Protocol is ISO9141
Received Data: F7 
Init Success !!
Writing Data
Received Data: 68 6A F1 1 0 C4 
Writing Data
Received Data: 68 6A F1 1 20 E4 
Suported LiveData: 
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 
Received Data: 68 6A F1 2 0 0 C5 
Suported FreezeFrame: 
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 
Writing Data
Received Data: 68 6A F1 9 0 CC 
Suported VehicleInfo: 
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 
Writing Data
Received Data: 68 6A F1 1 D D1 
Speed: 0
Writing Data
Received Data: 68 6A F1 1 C D0 
Engine RPM: 0
Writing Data
Received Data: 68 6A F1 1 5 C9 
Coolant Temp: 0
Writing Data
Received Data: 68 6A F1 1 F D3 
Intake Air Temp: 0
Writing Data
Received Data: 68 6A F1 1 11 D5 
Throttle: 0
Writing Data
Received Data: 68 6A F1 1 E D2 
Timing Advance: 0
Writing Data
Received Data: 68 6A F1 1 4 C8 
Engine Load: 0
Writing Data
Received Data: 68 6A F1 1 10 D4 
MAF Flow Rate: 0
Writing Data
Received Data: 68 6A F1 1 0 C4 
Writing Data
Received Data: 68 6A F1 1 20 E4 
Suported LiveData: 
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
Received Data: 68 6A F1 1 C D0 
Engine RPM: 0
Writing Data
Received Data: 68 6A F1 1 5 C9 
Coolant Temp: 0
Writing Data
Received Data: 68 6A F1 1 F D3 
Intake Air Temp: 0
Writing Data
Received Data: 68 6A F1 1 11 D5 
Throttle: 0
Writing Data
Received Data: 68 6A F1 1 E D2 
Timing Advance: 0
Writing Data
Received Data: 68 6A F1 1 4 C8 
Engine Load: 0
Writing Data
Received Data: 68 6A F1 1 10 D4 
MAF Flow Rate: 0
Writing Data
Received Data: 68 6A F1 1 0 C4 
Writing Data
Received Data: 68 6A F1 1 20 E4 
Suported LiveData: 
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 
Engine RPM: 0
Writing Data
Received Data: 68 6A F1 1 5 C9 
Coolant Temp: 0
Writing Data
Received Data: 68 6A F1 1 F D3 
Intake Air Temp: 0
Writing Data
Received Data: 68 6A F1 1 11 D5 
Throttle: 0
Writing Data
Received Data: 68 6A F1 1 E D2 
Timing Advance: 0
Writing Data
Received Data: 68 6A F1 1 4 C8 
Engine Load: 0
Writing Data
Received Data: 68 6A F1 1 10 D4 
MAF Flow Rate: 0
Writing Data
Received Data: 68 6A F1 1 0 C4 
Writing Data
Received Data: 68 6A F1 1 20 E4 
Suported LiveData: 
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 

No valid data for the actual PID Variables.
I came back to your post here, and saw that my numbers returned are almost identical to your returned values.

When I was testing last night, something caught my eye early on.
First thing it comes up with is "55 8 8".
This equates to the initial Result Buffers [0], [1], & [2] => Data in those being 0x55, 0x08, 0x08.
'Great' I thought... but here's where I got confused.
From what I gathered, 0x55 is the ISO9141 reply.
But every time the program Wrote to the OBD, it started with '68 6A F1.....'
With the particular code I was testing, it uses a <PID.h> library file.
So I opened that file & had a look...
This is the library contents:

//-------------------------------------------------------------------------------------//
// PIDs (https://en.wikipedia.org/wiki/OBD-II_PIDs)
//-------------------------------------------------------------------------------------//

const byte start_Bytes[3] = { 0xC1, 0x33, 0xF1 };
const byte start_Bytes_SLOW[3] = { 0x68, 0x6A, 0xF1 };

const byte live_data[4] = { 0xC2, 0x33, 0xF1, 0x01 };           //Live Data Start Bytes
const byte live_data_SLOW[4] = { 0x68, 0x6A, 0xF1, 0x01 };      //Live Data Start Bytes

const byte freeze_frame[4] = { 0xC3, 0x33, 0xF1, 0x02 };        //Freeze Frame Start Bytes
const byte freeze_frame_SLOW[4] = { 0x68, 0x6A, 0xF1, 0x02 };   //Freeze Frame Start Bytes

const byte vehicle_info[4] = { 0xC2, 0x33, 0xF1, 0x09 };        //Live Data Start Bytes
const byte vehicle_info_SLOW[4] = { 0x68, 0x6A, 0xF1, 0x09 };   //Live Data Start Bytes

const byte init_OBD = 0x81;    // Init fast ISO14230
const byte read_DTCs = 0x03;   // Read Troubleshoot Codes
const byte clear_DTCs = 0x04;  // Clear Troubleshoot Codes

const byte read_VIN = 0x02;             // Read VIN
const byte read_ID_Length = 0x03;       // Read Calibration ID Length
const byte read_ID = 0x04;              // Read Calibration ID
const byte read_ID_Num_Length = 0x05;   // Read Calibration ID Number Length
const byte read_ID_Num = 0x06;          // Read Calibration ID Number



const byte SUPPORTED_PIDS_1_20              = 0x00;  // bit encoded
const byte MONITOR_STATUS_SINCE_DTC_CLEARED = 0x01;  // bit encoded          suported
const byte FREEZE_DTC                       = 0x02;  //                      suported
const byte FUEL_SYSTEM_STATUS               = 0x03;  // bit encoded          suported
const byte ENGINE_LOAD                      = 0x04;  // %
const byte ENGINE_COOLANT_TEMP              = 0x05;  // °C
const byte SHORT_TERM_FUEL_TRIM_BANK_1      = 0x06;  // %   suported
const byte LONG_TERM_FUEL_TRIM_BANK_1       = 0x07;  // %   suported
const byte SHORT_TERM_FUEL_TRIM_BANK_2      = 0x08;  // %
const byte LONG_TERM_FUEL_TRIM_BANK_2       = 0x09;  // %
const byte FUEL_PRESSURE                    = 0x0A;  // kPa
const byte INTAKE_MANIFOLD_ABS_PRESSURE     = 0x0B;  // kPa
const byte ENGINE_RPM                       = 0x0C;  // rpm
const byte VEHICLE_SPEED                    = 0x0D;  // km/h
const byte TIMING_ADVANCE                   = 0x0E;  // ° before TDC
const byte INTAKE_AIR_TEMP                  = 0x0F;  // °C
const byte MAF_FLOW_RATE                    = 0x10;  // g/s
const byte THROTTLE_POSITION                = 0x11;  // %
const byte COMMANDED_SECONDARY_AIR_STATUS   = 0x12;  // bit encoded
const byte OXYGEN_SENSORS_PRESENT_2_BANKS   = 0x13;  // bit encoded    suported
const byte OXYGEN_SENSOR_1_A                = 0x14;  // V %            suported
const byte OXYGEN_SENSOR_2_A                = 0x15;  // V %            suported
const byte OXYGEN_SENSOR_3_A                = 0x16;  // V %
const byte OXYGEN_SENSOR_4_A                = 0x17;  // V %
const byte OXYGEN_SENSOR_5_A                = 0x18;  // V %
const byte OXYGEN_SENSOR_6_A                = 0x19;  // V %
const byte OXYGEN_SENSOR_7_A                = 0x1A;  // V %
const byte OXYGEN_SENSOR_8_A                = 0x1B;  // V %
const byte OBD_STANDARDS                    = 0x1C;  // bit encoded  suported
const byte OXYGEN_SENSORS_PRESENT_4_BANKS   = 0x1D;  // bit encoded
const byte AUX_INPUT_STATUS                 = 0x1E;  // bit encoded
const byte RUN_TIME_SINCE_ENGINE_START      = 0x1F;  // sec

const byte SUPPORTED_PIDS_21_40             = 0x20;  // bit encoded
const byte DISTANCE_TRAVELED_WITH_MIL_ON    = 0x21;  // km           suported
const byte FUEL_RAIL_PRESSURE               = 0x22;  // kPa
const byte FUEL_RAIL_GUAGE_PRESSURE         = 0x23;  // kPa
const byte OXYGEN_SENSOR_1_B                = 0x24;  // ratio V
const byte OXYGEN_SENSOR_2_B                = 0x25;  // ratio V
const byte OXYGEN_SENSOR_3_B                = 0x26;  // ratio V
const byte OXYGEN_SENSOR_4_B                = 0x27;  // ratio V
const byte OXYGEN_SENSOR_5_B                = 0x28;  // ratio V
const byte OXYGEN_SENSOR_6_B                = 0x29;  // ratio V
const byte OXYGEN_SENSOR_7_B                = 0x2A;  // ratio V
const byte OXYGEN_SENSOR_8_B                = 0x2B;  // ratio V
const byte COMMANDED_EGR                    = 0x2C;  // %
const byte EGR_ERROR                        = 0x2D;  // %
const byte COMMANDED_EVAPORATIVE_PURGE      = 0x2E;  // %
const byte FUEL_TANK_LEVEL_INPUT            = 0x2F;  // %
const byte WARM_UPS_SINCE_CODES_CLEARED     = 0x30;  // count
const byte DIST_TRAV_SINCE_CODES_CLEARED    = 0x31;  // km
const byte EVAP_SYSTEM_VAPOR_PRESSURE       = 0x32;  // Pa
const byte ABS_BAROMETRIC_PRESSURE          = 0x33;  // kPa
const byte OXYGEN_SENSOR_1_C                = 0x34;  // ratio mA
const byte OXYGEN_SENSOR_2_C                = 0x35;  // ratio mA
const byte OXYGEN_SENSOR_3_C                = 0x36;  // ratio mA
const byte OXYGEN_SENSOR_4_C                = 0x37;  // ratio mA
const byte OXYGEN_SENSOR_5_C                = 0x38;  // ratio mA
const byte OXYGEN_SENSOR_6_C                = 0x39;  // ratio mA
const byte OXYGEN_SENSOR_7_C                = 0x3A;  // ratio mA
const byte OXYGEN_SENSOR_8_C                = 0x3B;  // ratio mA
const byte CATALYST_TEMP_BANK_1_SENSOR_1    = 0x3C;  // °C
const byte CATALYST_TEMP_BANK_2_SENSOR_1    = 0x3D;  // °C
const byte CATALYST_TEMP_BANK_1_SENSOR_2    = 0x3E;  // °C
const byte CATALYST_TEMP_BANK_2_SENSOR_2    = 0x3F;  // °C

const byte SUPPORTED_PIDS_41_60             = 0x40;  // bit encoded
const byte MONITOR_STATUS_THIS_DRIVE_CYCLE  = 0x41;  // bit encoded
const byte CONTROL_MODULE_VOLTAGE           = 0x42;  // V
const byte ABS_LOAD_VALUE                   = 0x43;  // %
const byte FUEL_AIR_COMMANDED_EQUIV_RATIO   = 0x44;  // ratio
const byte RELATIVE_THROTTLE_POSITION       = 0x45;  // %
const byte AMBIENT_AIR_TEMP                 = 0x46;  // °C
const byte ABS_THROTTLE_POSITION_B          = 0x47;  // %
const byte ABS_THROTTLE_POSITION_C          = 0x48;  // %
const byte ABS_THROTTLE_POSITION_D          = 0x49;  // %
const byte ABS_THROTTLE_POSITION_E          = 0x4A;  // %
const byte ABS_THROTTLE_POSITION_F          = 0x4B;  // %
const byte COMMANDED_THROTTLE_ACTUATOR      = 0x4C;  // %
const byte TIME_RUN_WITH_MIL_ON             = 0x4D;  // min
const byte TIME_SINCE_CODES_CLEARED         = 0x4E;  // min
const byte MAX_VALUES_EQUIV_V_I_PRESSURE    = 0x4F;  // ratio V mA kPa
const byte MAX_MAF_RATE                     = 0x50;  // g/s
const byte FUEL_TYPE                        = 0x51;  // ref table
const byte ETHANOL_FUEL_PERCENT             = 0x52;  // %
const byte ABS_EVAP_SYS_VAPOR_PRESSURE      = 0x53;  // kPa
const byte EVAP_SYS_VAPOR_PRESSURE          = 0x54;  // Pa
const byte SHORT_TERM_SEC_OXY_SENS_TRIM_1_3 = 0x55;  // %
const byte LONG_TERM_SEC_OXY_SENS_TRIM_1_3  = 0x56;  // %
const byte SHORT_TERM_SEC_OXY_SENS_TRIM_2_4 = 0x57;  // %
const byte LONG_TERM_SEC_OXY_SENS_TRIM_2_4  = 0x58;  // %
const byte FUEL_RAIL_ABS_PRESSURE           = 0x59;  // kPa
const byte RELATIVE_ACCELERATOR_PEDAL_POS   = 0x5A;  // %
const byte HYBRID_BATTERY_REMAINING_LIFE    = 0x5B;  // %
const byte ENGINE_OIL_TEMP                  = 0x5C;  // °C
const byte FUEL_INJECTION_TIMING            = 0x5D;  // °
const byte ENGINE_FUEL_RATE                 = 0x5E;  // L/h
const byte EMISSION_REQUIREMENTS            = 0x5F;  // bit encoded

const byte SUPPORTED_PIDS_61_80             = 0x60;  // bit encoded
const byte DEMANDED_ENGINE_PERCENT_TORQUE   = 0x61;  // %
const byte ACTUAL_ENGINE_TORQUE             = 0x62;  // %
const byte ENGINE_REFERENCE_TORQUE          = 0x63;  // Nm
const byte ENGINE_PERCENT_TORQUE_DATA       = 0x64;  // %
const byte AUX_INPUT_OUTPUT_SUPPORTED       = 0x65;  // bit encoded

The immediate thing you see, is that the first 2 code lines are:
. const byte start_Bytes[3] = { 0xC1, 0x33, 0xF1 };
. const byte start_Bytes_SLOW[3] = { 0x68, 0x6A, 0xF1 };
These '3 byte' patterns repeat throughout the lib file, with extra bytes for their respective purposes.
That to me, said it is using the Write data for a 'Slow' protocol version (not that I'm 100% sure).
So now, I'm wondering if it should be using the 'non-slow' Bytes: C1 33 F1

I'm going to Duplicate this PID.h file (to retain the original), then alter all the values to the Non-slow version.
I will see if I can accomplish this, and get back to you.
Cheers !

1 Like

Hello, my friend. Your progress has really caught my attention. I couldn't overcome the problem I was facing, and due to work, I had to pause my project. I'm currently working on another project, but I'm following your updates closely and looking forward to hearing good news from you.

Haha - sounds like you are just like me.
Never enough time in the day / week / month, & even Year.

I was reading another paper on the OBD codes that are exchanged (before I got sidetracked), and I might be a little wrong on my thoughts of the 'Slow' code, but will continue to look at it sometime in the next few days.
Will keep you updated...

Buddy, I’ve put incredible effort into this project. I live in a three-story house, and I’m on the third floor. I absolutely hate having to go up and down all the time. I can only find time to work on it at night, and there was one night when I went up and down 20-25 times. I changed the code, it didn’t work, so I tried a different approach. I’ve worked so hard on this. This project is extremely important to me, and while I might not achieve it today, I truly believe I’ll make it happen very soon. I’m fully committed to it.

:space_invader:
Success !!!

Tried lots of bits of code, but nothing worked. This included the code I'd mentioned above.
Changing all the '68 6A F1' to 'C1...' stuff didn't help.
So I went back & tried many other OBD code that I'd previously downloaded & played with... Nothing.
Then I went to the Examples in Arduino IDE, from iwanders/OBD9141.
I selected the 'Soft Serial' version.
In 'examples', this was under: OBD9141... ISO9141_rreader_softserial.ino
Worked straight off, although I had to do a few Tweaks.

First thing is that he has obviously designed it to use the SN65HVDA100 chip as an interface.
Therefore, he has defined 'EN_PIN = 10' followed by pinMode & Write code.
If not using that chip (like me), it's irrelevant and doesn't hinder anything, whether it's in the code or removed.
I used the Arduino Nano, and kept the same Tx/Rx Pins (8 & 9).
Just in case you haven't clicked (which I hadn't until recently), if using the Nano & possibly some others, you need to use some form of Alt' Serial driver code, as you need 2 Serial lines.
First is for the computer connection, and the second is to communicate with the OBD interface.

Don't forget to change the Serial Monitor speed if not using 9600... I use 115200.
In iwanders code, he had 3 PIDs listed, to display "Throttle, RPM, & Speed".
During first testing, only 2 would come through on the Serial Monitor - usually the 1st & 3rd, but not the 2nd.
I changed the order of the PIDs, which gave me the different PID, but still only the 1st & 3rd.... Never the 2nd one.
I added a 50ms delay between the PID requests, and that seemed to fix it.
I'm picking that the OBD protocol requires a delay between requests, therefore the 2nd one was being sent too soon after the 1st, and simply ignored by the car.
Then I added a couple of extra PID requests, each with a 50ms delay between.
Worked perfectly... as long as the PID you requested is Valid for/from your vehicle.

Here's the code I ended up with (still with the Irrelevant 'EN' code at the beginning:

#include "Arduino.h"
// Be sure that the AltSoftSerial library is available, download it from http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html"
#include "AltSoftSerial.h"

#include "OBD9141.h"

#define RX_PIN 8  // connect to transceiver Rx
#define TX_PIN 9  // connect to transceiver Tx
#define EN_PIN 10  //  pin will be set high (connect to EN pin of SN65HVDA100)

AltSoftSerial altSerial;
OBD9141 obd;

void setup()
{
  Serial.begin(115200);
  delay(2000);
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, HIGH); // enable the transceiver IC.
  obd.begin(altSerial, RX_PIN, TX_PIN);
}
    
void loop()
{
  Serial.println("Looping");
  bool init_success =  obd.init();
  Serial.print("init_success:");
  Serial.println(init_success);

  if (init_success)
  {
    bool res;
    while(1)
     {
      // FORMAT: obd.getCurrentPID =>> (address, number of bytes)
      res = obd.getCurrentPID(0x11, 1);
      if (res){
      Serial.print("Result 0x11 (Throttle): "); // 100/255 x data (or A / 2.55) = 0% to 100%
      Serial.println(obd.readUint8()/2.55);
     }
      delay(50);
      res = obd.getCurrentPID(0x0F, 1);
      if (res)
       {
        Serial.print("Result 0x0F (Air Intake Temp): ");
        Serial.println(obd.readUint8() -40);  // Temp = data -40. Need to remove 40 from rtnd data
       }
      delay(50);
      res = obd.getCurrentPID(0x05, 1);
      if (res)
       {
        Serial.print("Result 0x05 (Engine coolant temperature): ");
        Serial.println(obd.readUint8() -40);  // Temp = data -40. Need to remove 40 from rtnd data
       }
      delay(50); // 46
      res = obd.getCurrentPID(0x0C, 2);
      if (res)
       {
        Serial.print("Result 0x0C (RPM): "); // listed as: (256.A)+B /4  (??)
        Serial.println(obd.readUint16()/4);
       }
      delay(50);
      res = obd.getCurrentPID(0x0D, 1);
      if (res)
       {
        Serial.print("Result 0x0D (Speed): "); // 1:1 with data
        Serial.println(obd.readUint8());
       }
      Serial.println();
      delay(200);
    }
  }
  delay(3000);
}


Only other thing I am not yet certain of, is whether the returned values are being calculated correctly.
I've put a few comments in the code, next to my trial PIDs.
I'm only basing this off the ISO9141 data listed on Wikipedia.
Wikipedia OBD-II PIDs

Under the Service 01 - Show current data it lists the PID number (need to use the Hex number), along with the Number of Bytes that will be returned.
On the RHS of the PID info, it gives the 'Formula' required, to manipulate the returned data, to display in the form required.
For example: PID 0x05 (1 byte) 'Engine coolant temperature', the formula is A -40 to display correctly.
I had to add in the '-40' to the code as it was.
For the 'RPM' (2 bytes), his code already had data /4, but this is not what the ISO standard gives for the formula. That is "(256.A)+B /4".
And yet, with just my basic testing - sitting static in the car, the rpm's didn't seem too different from what I could see on the Dash. So ??

I Copy/Pasted 3 test tries of Serial Monitor data into a text page.
Usually, I pressed the accelerator, to increase the 'Throttle' & 'RPM' valued received.
This showed Real-World data was coming back.

This is what I got:
(You'll notice I made a comment in the 2nd lot, before I changed the Formula in the code)

Looping
init_success:1
Result 0x0C (RPM): 0
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 0
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 0
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 0
Result 0x11 (throttle): 24
Result 0x0D (speed): 0          // Started Engine:

Result 0x0C (RPM): 32
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 932
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1470
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1312
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1343
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1339
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1324
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1325
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1345
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1330
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1336
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1332
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1335
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1357
Result 0x11 (throttle): 33
Result 0x0D (speed): 0

Result 0x0C (RPM): 1763
Result 0x11 (throttle): 29
Result 0x0D (speed): 0

Result 0x0C (RPM): 1755
Result 0x11 (throttle): 30
Result 0x0D (speed): 0

Result 0x0C (RPM): 1724
Result 0x11 (throttle): 30
Result 0x0D (speed): 0

Result 0x0C (RPM): 1728
Result 0x11 (throttle): 30
Result 0x0D (speed): 0

Result 0x0C (RPM): 1766
Result 0x11 (throttle): 31
Result 0x0D (speed): 0

Result 0x0C (RPM): 1802
Result 0x11 (throttle): 31
Result 0x0D (speed): 0

Result 0x0C (RPM): 1827
Result 0x11 (throttle): 31
Result 0x0D (speed): 0

Result 0x0C (RPM): 1840
Result 0x11 (throttle): 30
Result 0x0D (speed): 0

Result 0x0C (RPM): 1820
Result 0x11 (throttle): 24
Result 0x0D (speed): 0

Result 0x0C (RPM): 1584
Result 0x11 (throttle): 24


Extras added...
Looping
init_success:1
Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66  *** Need to subtract 40 in the code **
Result 0x0C (RPM): 1337
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1340
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1332
Result 00D (speed): 0

Result 0x11 (throttle): 24
Result 00F (Air Intake Temp): 66
Result 0x0C (RPM): 1341
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1332
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1332
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1337
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1344
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1338
Result 0x0D (speed): 0

Result 0x11 (throttle): 44
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 2137
Result 0x0D (speed): 0

Result 0x11 (throttle): 33
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 2209
Result 0x0D (speed): 0

Result 0x11 (throttle): 32
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 2083
Result 0x0D (speed): 0

Result 0x11 (throttle): 32
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 2019
Result 0x0D (speed): 0

Result 0x11 (throttle): 32
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1998
Result 0x0D (speed): 0

Result 0x11 (throttle): 32
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1994
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1664
Result 0x0D (speed): 0

Result 0x11 (throttle): 24
Result 0x0F (Air Intake Temp): 66
Result 0x0C (RPM): 1405
Result 0x0D (speed): 0


Extra Extra data added...
Looping
init_success:1
Result 0x11 (Throttle): 9.41               // ** Changed Formula, to divide by 2.55 **
Result 0x0F (Air Intake Temp): 28
Result 0x05 (Engine coolant temperature): 35
Result 0x0C (RPM): 1340
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 35
Result 0x0C (RPM): 1348
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 11.76
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 35
Result 0x0C (RPM): 1736
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 14.51
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 35
Result 0x0C (RPM): 2331
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 15.69
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 35
Result 0x0C (RPM): 2640
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 15.69
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 2747
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 15.69
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 2766
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 15.69
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 2647
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 1601
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 1382
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 1386
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 13.73
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 36
Result 0x0C (RPM): 982
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 37
Result 0x0C (RPM): 1544
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 37
Result 0x0C (RPM): 139
Result 0x0D (Speed): 0

Result 0x11 (Throttle): 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 37
Result 0x0C (RPM): 1290
Result 0x0D (Speed): 0

Result 0x11 (Throttle: 9.41
Result 0x0F (Air Intake Temp): 27
Result 0x05 (Engine coolant temperature): 37
Result 0x0C (RPM): 1186
Result 0x0D (Speed: 0



I'm not completely convinced that these figures are Spot-on - particularly as the Outside Ambient Temp was only 19 degrees, so I can't see why the car would show the 'Air Intake Temp' as 27, particularly as the car hadn't been started-up until I got this code working.
Probably need to investigate further, or add a "Fudge Factor" to get it (& other PIDs) correct.
Also, I won't know if the 'Speed' data will be correct until I have time and a 2nd person to take the car out for a spin, while I monitor the data.
But it's PROGRESS at last !!!

Hope this helps...
:oncoming_automobile:

Hello my friend, you've got me really excited! After a long break, I'll be working with you again :slight_smile: Could you share the schematic of the circuit you've set up? I had tried it with the L9637D.

My friend, do you have a Bluetooth OBD reader that works with your phone to verify the accuracy of the data?

Buddy, this is the circuit I'm using, and I tried the code snippet you shared with me. The only response I got was init_Success 0.

Buddy, I'm going to proceed with a new method. This project is driving me crazy, so I'm going for a much simpler and more universal system. I'll connect the OBD reader directly with the Arduino. I've already ordered the components, and I'll come back to you with some good news!

I don't use a Bluetooth adaptor at all - just a direct connection to the OBD wires.
Otherwise, if the setup wasn't working it would have been 1 more unknown complexity in the chain... you'd never know if it was the Code / communication that wasn't working, or if it was just lost within the BT comms.
With my final setup, I'll be using an ESP32 with the 'ESP-NOW' feature.

I haven't used that L9637 chip, but I don't see why it wouldn't work.
Even the most basic interface should work.
This is one that I see shown a lot:


But there's one thing i Loathe about it, that being the single resistor (R2) going back to the Rx line.
This should be a Voltage Divider, not just a Limiting resistor.
You need to divide the car 12v down to the 5v (or 3.3v) for the microcontroller.
Past that, it will still work.

With respect to the L9637 chip - I haven't looked up the Specs...
But I was reading a post just yesterday that was talking about the TJA1021 chip vs the TJA1027.
Turns out that the 1021 has a Safety feature, which stops the chip holding the output low for too long. Even if the chip input line remained LOW, it 'Self Timed-out' after 50ms & released the K-Line.
This means it is Impossible to create the 5-baud init sequence, as that requires Low pulses as long as 400ms.
So - the solution was to use the 1027 chip, which did Not have that feature.

I have to run out the door right now, but will come back to this later...

Sorry - I misread your earlier question regarding the Bluetooth OBD reader.
You actually meant (effectively) "do I have an OBD Scan tool" to confirm the data.
Yes - I have a plug-in Scan Tool.
And until now, I hadn't thought to compare my readings with it (although I only just got it all up & running the other night).
Great idea - I can compare with that, and determine and 'Fudge-Factors' (if needed).

Now - I just looked up the Data Sheet for the L9637D driver chip.
It doesn't appear to have any form of 'Time Limiting' on the output [K] line, so should be fine with this circuit, and the 5-baud initialisation code word.
So it should work directly with your code...

If your Serial Monitor gave you init_success = 0, it means the 5-baud initialisation has failed.
Do you have any kind of oscilloscope to confirm what signals are appearing on the K-Line ?
This might be the quickest thing, as a 'First Step' to determining where the fault lies.
Let me know if I can help any further... happy to assist in any way I can !

Here's a MUCH Better version of the circuit above I saw previously...
(K Line communication help)


... Thank you abdf !

This will give you 0v to +4.95v on the Rx line (for Arduino etc).

If you were wanting to use a 3.3v microcontroller (ESP32 etc), you could use a divider ratio with R2 = 47K, and a 15K to ground (18K is pushing it a bit much).
If 15k is unobtainable, put a 6.8K & 8.2K resistor in series.

1 Like

Purely for info...
In my 'Success' post above (Post #9), I mentioned that I had to add in a delay between PID requests, to get it to work correctly.
I've searched & searched the ISO standards etc, and they're all a little Vague on that detail.
But I've finally found the following reference:

From the 'broken-grammar' English, I suspect it might be a foreign language translation.
This could account for why the searchable standards are all slightly vague.
Either way, it ties up with when I first tried adding a 20ms delay between PID calls, but that didn't help. I just jumped straight up to 50ms, which sorted the issue.
This document snippet tells me a 30ms delay should be suitable, although realistically, it makes little difference with respect to the overall number of requests per second.

Unfortunately, I don't have an oscilloscope. I had already tried both of the circuits you sent :slight_smile: but since I didn't get a positive result, I bought the L9637D. I'll definitely let you know once I succeed in the project."

"I had built the second schematic you sent exactly as it is, but I didn’t try changing the resistor value, my friend