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!"