Banner publicitario de PCBWay

Comunicación Bluetooth con HC-05, OLED128x64 I2C y ELM327

torres.electronico

Well-known-Alfil
buenas, como va?
estoy armando una interface de comunicacion entre un arduino nano (+ HC05 + OLED128x64 I2c) y el ELM327 y estoy teniendo problemas con el HC-05...

Como no queria depender de librerias, arranque con un formato de comandos de comunicacion estandar del ELM327 y note que no tenia respuesta alguna (hice mas de 7 versiones distintas y nada...)
CSS:
#include <U8glib.h>
#include <SoftwareSerial.h>

// ------------------- OLED SH1106 -------------------
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE);

// ------------------- HC-05 (SoftwareSerial) -------------------
SoftwareSerial HC05(10, 11); // RX, TX

// ------------------- Variables OBD -------------------
int rpm = 0;
float boost = 0;
float tempRefrig = 0;
float voltaje = 0;

// ------------------- Setup -------------------
void setup() {
  Serial.begin(115200);  // Debug PC
  HC05.begin(9600);      // HC-05 maestro ya configurado

  // Debug inicial en OLED
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    u8g.drawStr(0,0,"DEBUG INICIAL");
    u8g.drawStr(0,15,"HC-05 configurado a 9600");
    u8g.drawStr(0,30,"Rol: Maestro");
    u8g.drawStr(0,45,"Nombre: HC05_OBD");
  } while(u8g.nextPage());
  delay(1000);

  // Inicialización ELM327
  sendELM("ATZ");
  sendELM("ATE0");
  sendELM("ATL0");
  sendELM("ATS0");
  sendELM("ATH0");
  sendELM("ATSP0");
}

// ------------------- Loop -------------------
void loop() {
  // Leer PIDs reales desde ELM327
  rpm = leerPID("010C");        // RPM
  boost = leerPID("010B")/10.0; // Boost bar
  tempRefrig = leerPID("0105"); // Temp C
  voltaje = leerPID("012F")/10.0; // Voltaje

  // Mostrar en pantalla
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    u8g.drawStr(0,0,"RPM / BOOST / TEMP / VOLT");

    char buf[20];
    sprintf(buf,"RPM: %d", rpm);
    u8g.drawStr(0,15,buf);
    sprintf(buf,"Boost: %.2f bar", boost);
    u8g.drawStr(0,30,buf);
    sprintf(buf,"Temp: %.1f C", tempRefrig);
    u8g.drawStr(0,45,buf);
    sprintf(buf,"Volt: %.1f V", voltaje);
    u8g.drawStr(0,60,buf);
  } while(u8g.nextPage());

  delay(500);
}

// ------------------- Funciones -------------------

// Enviar comando al ELM327 y mostrar debug
void sendELM(String cmd) {
  HC05.println(cmd);
  delay(300);

  String resp = "";
  unsigned long t = millis();
  while(millis()-t < 300) {
    while(HC05.available()) {
      char c = HC05.read();
      resp += c;
    }
  }

  Serial.print("CMD: "); Serial.print(cmd);
  Serial.print(" RESP: "); Serial.println(resp);

  // Debug en OLED
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    u8g.drawStr(0,0,("CMD: "+cmd).c_str());
    u8g.drawStr(0,15,("RESP: "+resp).c_str());
  } while(u8g.nextPage());

  delay(200);
}

// ------------------- Leer PID simple -------------------
int leerPID(String pid) {
  HC05.println(pid);
  delay(200);

  String resp = "";
  unsigned long t = millis();
  while(millis()-t < 300) {
    while(HC05.available()) {
      char c = HC05.read();
      if(c != '\r' && c != '\n') resp += c;
    }
  }
  resp.trim();
  resp.toUpperCase();

  // Extraer los últimos 2-4 bytes de la respuesta
  if(resp.length() >= 4) {
    int a = strtoul(resp.substring(resp.length()-4,resp.length()-2).c_str(),NULL,16);
    int b = strtoul(resp.substring(resp.length()-2).c_str(),NULL,16);
    return a*256 + b;
  }
  return 0;
}

llegue al punto de dudar si realmente me estaba respondiendo el HC-05, asi que arme el siguiente sketch para ver si podía configurar el modulo bluetooth y de ahi, usando el monitor configurar manualmente todo para que quede guardada la mac y despues se conecte solo:

CSS:
#include <SoftwareSerial.h>
SoftwareSerial BT(10,11); // RX,TX

long bauds[] = {9600, 38400};
void setup(){
  Serial.begin(115200);
  Serial.println(F("=== HC-05 AUTO TEST ==="));
  delay(200);
  for(int i=0;i<2;i++){
    long b = bauds[i];
    Serial.print("Probar baud "); Serial.println(b);
    BT.end();
    delay(50);
    BT.begin(b);
    delay(200);
    // enviar AT simple y AT+VERSION?
    Serial.print("-> Enviando 'AT' a "); Serial.println(b);
    BT.print("AT\r\n");
    delay(400);
    readDump();
    Serial.print("-> Enviando 'AT+VERSION?' a "); Serial.println(b);
    BT.print("AT+VERSION?\r\n");
    delay(600);
    readDump();
    Serial.println("-------------------------");
    delay(300);
  }
  Serial.println("FIN PRUEBA. Ahora escribe comandos (monitor -> BT).");
}

void loop(){
  if (Serial.available()) BT.write(Serial.read()); // lo que escribas va a HC-05
  if (BT.available()) Serial.write(BT.read());     // lo que responda HC-05 va al monitor
}

void readDump(){
  unsigned long t = millis();
  String r="";
  while(millis()-t < 800){
    while(BT.available()){
      char c = (char)BT.read();
      r += c;
    }
  }
  if(r.length()) {
    Serial.print(" RESPUESTA: '"); Serial.print(r); Serial.println("'");
  } else {
    Serial.println(" RESPUESTA: (sin datos)");
  }
}

los comandos implementados fueron:
AT
AT+NAME=HC05_OBD
AT+PSWD=1234
AT+ROLE=1
AT+UART=9600,0,0 (probe casi todas)
AT+CMODE=0
AT+BIND=1C,A1,35,69,8D,C5
AT+LINK=1C,A1,35,69,8D,C5

AT+RESET

y nada....

AT
AT+ROLE=1
AT+CMODE=0
AT+INQM=1,9,48
AT+INIT

AT+INQ

espere ver la mac y nunca respondio...asi que me fije desde una app del telefono la mac y...

AT+PAIR=1C,A1,35,69,8D,C5,20
AT+BIND=1C,A1,35,69,8D,C5
AT+LINK=1C,A1,35,69,8D,C5

AT+RESET

Todo esto me dio errores (0/6y16)... la verdad no recuerdo exactamente el orden, pero en fin... Intente hacer algo de emparejamiento automatico:

CSS:
#include <SoftwareSerial.h>

SoftwareSerial BT(10, 11);  // RX, TX

void setup() {
  Serial.begin(9600);
  Serial.println("=== HC-05 Auto-Link ELM327 ===");

  BT.begin(38400); // Modo AT completo

  delay(1000);
  enviar("AT");
  enviar("AT+RESET");
  enviar("AT+ROLE=1");    // Modo maestro
  enviar("AT+CMODE=1");   // Permitir conexión con cualquier dispositivo
  enviar("AT+INIT");
  enviar("AT+INQ");       // Buscar dispositivos cercanos
  delay(5000);

  Serial.println("Intentando conectar al ELM327...");
  enviar("AT+LINK=1C,A1,35,69,8D,C5");  // tu dirección (ajustar si cambia)
  delay(5000);

  Serial.println("Listo. Si LED del HC-05 queda fijo, se conectó al ELM327.");
  Serial.println("Podés cargar ahora el sketch principal.");
}

void loop() {
  if (BT.available()) Serial.write(BT.read());
  if (Serial.available()) BT.write(Serial.read());
}

void enviar(String cmd) {
  Serial.print(">> "); Serial.println(cmd);
  BT.print(cmd); BT.print("\r\n");
  delay(500);
  while (BT.available()) Serial.write(BT.read());
}
y seguia sin comunicacion... Al parecer, este modulo es muy chino y viene con una version de firmware muy vieja (eso interpreto de los foros que lei) y no reconoce muchos comandos... la cosa es que no pude hacerlo funcionar, asi que cai en una libreria :rolleyes: (ELMDuino) y tampoco funciono...

CSS:
#include <Wire.h>
#include <U8glib.h>
#include <SoftwareSerial.h>
#include "ELMduino.h"

// --- OLED U8glib ---
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE);

// --- SoftwareSerial para HC-05 / ELM327 ---
#define ELM_RX 10
#define ELM_TX 11
SoftwareSerial elmSerial(ELM_RX, ELM_TX);
ELM327 myELM327;

// --- Variables OBD ---
float rpmVal = 0;
float speed = 0;
float coolantTemp = 0;
float batteryV = 0;
float boostKPa = 0;

unsigned long lastUpdate = 0;
const unsigned long updateInterval = 500; // ms
unsigned long lastDataTime = 0;
const unsigned long timeoutComm = 3000; // ms antifreeze

typedef enum { ENG_RPM, SPEED, COOLANT_TEMP, BATT_VOLT, BOOST } obd_pid_states;
obd_pid_states obd_state = ENG_RPM;

// --- Setup ---
void setup() {
  Serial.begin(115200);
  Wire.begin();
  delay(250);

  // Inicializar OLED
  Serial.println("Iniciando OLED...");
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    u8g.drawStr(10, 30, "OLED OK!");
  } while(u8g.nextPage());
  Serial.println("OLED inicializado correctamente");

  // Inicializar ELM327
  elmSerial.begin(38400); // coincide con HC-05 configurado
  myELM327.begin(elmSerial);
  lastDataTime = millis();
  Serial.println("Esperando datos del ELM327...");
}

// --- Loop ---
void loop() {
  unsigned long currentMillis = millis();
  if(currentMillis - lastUpdate >= updateInterval){
    lastUpdate = currentMillis;
    bool newData = false;

    // --- Lectura PID ---
    switch(obd_state){
      case ENG_RPM:
        rpmVal = myELM327.rpm();
        obd_state = SPEED;
        newData = true; break;
      case SPEED:
        speed = myELM327.kph();
        obd_state = COOLANT_TEMP;
        newData = true; break;
      case COOLANT_TEMP:
        coolantTemp = myELM327.engineCoolantTemp();
        obd_state = BATT_VOLT;
        newData = true; break;
      case BATT_VOLT:
        batteryV = myELM327.batteryVoltage();
        obd_state = BOOST;
        newData = true; break;
      case BOOST:
        boostKPa = myELM327.manifoldPressure();
        obd_state = ENG_RPM;
        newData = true; break;
    }

    if(newData) lastDataTime = millis();

    // --- Dibujar en pantalla ---
    u8g.firstPage();
    do {
      drawData();
    } while(u8g.nextPage());
  }
}

// --- Función para dibujar datos ---
void drawData() {
  char buf[20];
  u8g.setFont(u8g_font_6x10);

  // Fila 1: Voltaje
  sprintf(buf, "Volt: %.1f V", batteryV);
  u8g.drawStr(0, 10, buf);

  // Fila 2: RPM
  sprintf(buf, "RPM: %.0f", rpmVal);
  u8g.drawStr(0, 22, buf);

  // Fila 3: Temp
  sprintf(buf, "Temp: %.0f C", coolantTemp);
  u8g.drawStr(0, 34, buf);

  // Fila 4: Boost
  if(millis() - lastDataTime > timeoutComm){
    u8g.drawStr(0, 46, "Perdida de comunicacion");
  } else {
    sprintf(buf, "Boost: %.0f kPa", boostKPa);
    u8g.drawStr(0, 46, buf);
  }
}

estoy suponiendo que el problema esta en el modulo bluetooth... si alguien experimento lo mismo y me puede dar una mano, le agradezco de antemano... La otra que me queda, es implementar un esp32 que tengo guardadito como oro por ahi, pero es caro para este proyecto...
El hardware en esta beta es sencillo:
-Arduino NANO
-Oled SH1106 I2c
-HC-05
 
Intenta primero comunicarte vía Bluetooth con tu teléfono, para poder asegurarte que estás configurando todo correctamente, luego intentas con el ELM.
 
Asegúrate que el ELM327 no esté conectado a ningún otro dispositivo mientras intentas esta conexión, parece que lo conectaste previamente a algún otro celular o teléfono, desactiva el Bluetooth y luego asegúrate que haya tiempos de espera entre estos comandos.

Una vez logres la conexión debes configurar el ELM327 mediante los correspondientes comandos AT para establecer el estándar ISO y así sucesivamente, para ello debes seguir una secuencia para su respectiva conexión:

MAC Address del ELM327 = 1C,A1,35,69,8D,C5

AT+RESET
AT+ROLE=1
AT+CMODE=0
AT+INIT
AT+BIND=1C,A1,35,69,8D,C5
AT+PAIR=1C,A1,35,69,8D,C5,20
AT+LINK=1C,A1,35,69,8D,C5


Si esto no te funciona es porque el HC-05 debe tener algún problema o conflicto tal como lo comentas, y lo mas factible es que pruebes con otro teléfono y otro HC-05, con su respectiva secuencia.
 

Adjuntos

  • HC-05 AT Command.pdf
    91.2 KB · Visitas: 3
  • HC-05 Comadandos.pdf
    83.7 KB · Visitas: 3
Última edición:
Asegúrate que el ELM327 no esté conectado a ningún otro dispositivo mientras intentas esta conexión, parece que lo conectaste previamente a algún otro celular o teléfono, desactiva el Bluetooth y luego asegúrate que haya tiempos de espera entre estos comandos.

Una vez logres la conexión debes configurar el ELM327 mediante los correspondientes comandos AT para establecer el estándar ISO y así sucesivamente, para ello debes seguir una secuencia para su respectiva conexión:

MAC Address del ELM327 = 1C,A1,35,69,8D,C5

AT+RESET
AT+ROLE=1
AT+CMODE=0
AT+INIT
AT+BIND=1C,A1,35,69,8D,C5
AT+PAIR=1C,A1,35,69,8D,C5,20
AT+LINK=1C,A1,35,69,8D,C5


Si esto no te funciona es porque el HC-05 debe tener algún problema o conflicto tal como lo comentas, y lo mas factible es que pruebes con otro teléfono y otro HC-05, con su respectiva secuencia.
millon de gracias por el aporte. Efectivamente comprobe que tengo unos HC-05 clones con firmware reducido. Son copias muy malas, asi que opte por seguir el proyecto directamente con el bluetooth nativo del ESP32... Me resulto mucho mas practico y sencillo por el momento, ya que la librería ELMDuino, ya viene justamente preparada para trabajar específicamente con un ESP32 y su Bluetooth. Hoy justamente habia terminado de pulir una de las betas y con tanta mala suerte rompí el TFT :facepalm:
WhatsApp Image 2025-11-04 at 5.05.59 PM.jpeg

Asi que ahora voy a editar la base que ya tengo y trabajarlo por el momento con el monitor serial para poder trabajar la parte de los PIDs estandar que soporta el ELM327 (RPM, tension de bateria, temperatura del refrigerante, rpm, entre otros mas) y los PIDs propietarios (presion del turbo, presion de aceite, entre otros) que son los PIDs especificos que emplean las marcas de vehiculos y el llamado a la lectura se hace con otros comandos de la libreria... Termino de depurar las 5 betas que tengo :ROFLMAO: y ni bien pueda terminar de dejar tan solo una perfecta, ahi vamos por la publicacion de una base para que despues puedan replicarlo y averiguando los PID de determinadas marcas,modificar los llamados y tener un circuito a medida de la necesidad de cada uno... Como no tengo todos los PIDs de la NISSAN FRONTIER 4x4 diesel modelo 2008, use google y me meti en varios foros de los cuales pude sacar algunos numeros medios raros de algunas funciones, asi que arme este sketch para rastrear cual es el correcto

CSS:
#include <BluetoothSerial.h>
#include <ELMduino.h>

BluetoothSerial SerialBT;
ELM327 myELM327;

#define ELM_NAME "OBDII"                       // Cambia según el nombre de tu ELM327
const char* ELM327_MAC = "1C:A1:35:69:8D:C5";  // Esta es la direccion MAC de mi ELM327

// Estructura y lista de PIDs
struct PIDTest { const char* pid; const char* desc; };
PIDTest testPIDs[] =
                   {
                    {"210D", "Boost/Presión Turbo (Nissan Consult)"},
                    {"2133", "Presión de Aceite Motor (Consult)"},
                    {"2142", "Temperatura de Aceite Motor (Consult)"},
                    {"2161", "Sensor Presión de Aceite alternativo"},
                    {"2134", "Presión circuito alternativo"},
                    {"0142", "Voltaje ECU/Batería estándar"},
                    {"0B",   "MAP/Presión colector admisión estándar"},
                   };
const int N_PIDS = sizeof(testPIDs) / sizeof(testPIDs[0]);
float kPaToPSI(float kpa) { return kpa / 6.895; }

void setup()
    {
     Serial.begin(115200);
     Serial.println("Iniciando...");
     if (!SerialBT.connect(ELM327_MAC))
        {
         Serial.println("No se pudo conectar al ELM327 por MAC");
         while (1);
        }
     Serial.println("Conectado al ELM327!");

     if (!myELM327.begin(SerialBT, false, 2000))
        {
         Serial.println("No se pudo inicializar comunicación con ELM327");
         while (1);
        }
     Serial.println("ELM327 inicializado correctamente!");
    }

void loop() 
     {
      Serial.println("--- PRUEBA DE PIDs EXTENDIDOS ---");
      for (int i = 0; i < N_PIDS; i++) 
          {
           Serial.print("Consultando PID: "); Serial.print(testPIDs[i].pid);
           Serial.print(" ["); Serial.print(testPIDs[i].desc); Serial.println("]");
          // 1. Enviamos el comando
          myELM327.sendCommand(testPIDs[i].pid);
         // 2. Recuperamos el resultado "payload" y lo mostramos como string
         Serial.print("Respuesta cruda: ");
         Serial.println(myELM327.payload);
        // 3. Si quiero convertir a valor numérico, tengo que parsear el payload aca
        Serial.println("-----------------------------");
       delay(1500);
      }
    Serial.println("Reiniciando barrido en 15 segundos...");
   delay(15000);
}

Cómo funciona el sketch? Consulta todos los PIDs (estándar + extendidos/propietarios) uno por uno y los muestra en el monitor serial: PID, descripción, valor en kPa, valor en PSI y respuesta cruda (un string que despues tengo que meter unas lineas mas para desglosar)...
Básicamente la idea es ver si obtengo un valor válido en PSI que cambia según las condiciones de la camioneta, y con eso verifico que ese es el PID correcto para mi variable. Mañana comento mas al respevto, y es bienvenido todo aquel que se quiera sumar al proyecto.... igualmente, voy a mostrar las cosas que intente con el nano y el hc-05 por si alguien quiere probar con su hc-05. saludos
 
Bien, en base a las pruebas y errores, ya puedo ir tirando algunos hilos para que queden a modo de tutorial algunos pasos relevantes cuando queremos comunicar un ESP32S (con bluetooth nativo) con un ELM327 Bluetooth y post a esto, establecer el protocolo de comunicación con la ECU con la librería ELMduino.

Los protocolos que puede manejar esta librería son:
AUTOMATIC
SAE_J1850_PWM_41_KBAUD
SAE_J1850_PWM_10_KBAUD
ISO_9141_5_BAUD_INIT
ISO_14230_5_BAUD_INIT
ISO_14230_FAST_INIT
ISO_15765_11_BIT_500_KBAUD
ISO_15765_29_BIT_500_KBAUD
ISO_15765_11_BIT_250_KBAUD
ISO_15765_29_BIT_250_KBAUD
SAE_J1939_29_BIT_250_KBAUD
USER_1_CAN
USER_2_CAN

Tanto el ESP como la librería, no tiene soporte para establecer el PIN de emparejamiento con el ELM327, ni tampoco funciona conectar directamente desde el nombre o la dirección MAC (en versiones antiguas de la librería me funciono, actualice y bue, perdí ese hilo y re arranque de cero) así que para ello, también les mostrare como hacerlo sin morir en el intento… Para cerrar esta primer parte del hilo, además de ver un poco de como usar la libreria ELMduino, vamos a ver un opción que me saco canas verdes pero quedo funcional para auto detectar el protocolo de comunicación de la ecu, que luego nos abrirá la puerta que tanto deseamos: “Consultar PIDs”…


1. Materiales:
ESP32 (con bluetooth)
ELM327 Bluetooth (OBD-II)
Automóvil con puerto OBD-II
PC con Arduino IDE

2. Instalación de librería ELMduino



A_ El PIN "1234":

El emparejamiento con el ELM327 suele requerir el PIN 1234 si es nuevo o por defecto. Una vez que hay un emparejamiento, ya no lo solicita nunca más. Como no tenemos forma de hacerlo manualmente, vamos a recurrir al siguiente bloque, que se coloca al inicio, antes de iniciar el Bluetooth (SerialBT.begin)

CSS:
extern "C" {
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
}

void setup()
    {
     esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
     esp_bt_pin_code_t pin_code = {'1','2','3','4'}; // PIN por defecto
     esp_bt_gap_set_pin(pin_type, 4, pin_code);
    }

B_ Detectar la MAC de tu ELM327 Bluetooth
Para conectar directamente y evitar problemas de emparejamiento, necesitas la MAC address del ELM327... Para hacerlo mas fácil, podemos implementar nuestra notebook con bluetooth, o bien, instalando en nuestro teléfono Android la app “Car Scanner”…. Activamos bluetooth, seleccionamos el dispositivo (En mi caso se llama “OBDII”) y luego, desde “Dispositivos conectados/Ver Todo” aparecerá un listado con todos los dispositivos bluetooth que vinculamos alguna vez. Damos click sobre este dispositivo (en mi caso hay un engranaje) y no aparecerá el nombre del dispositivo, la dirección MAC y si queremos conectar o olvidar. Esta dirección MAC suele verse en la app del teléfono o PC como un HEX de 6 bytes. En mi caso, la MAC de mi dispositivo es: 1C:A1:35:69:8D:C5 o sea {0x1C, 0xA1, 0x35, 0x69, 0x8D, 0xC5}

C_ Iniciando la conexión Bluetooth con el ELM327

CSS:
BluetoothSerial SerialBT;
SerialBT.begin("ESP32Cruise", true); // true = modo master
delay(500);
bool elmConnected = SerialBT.connect(address); // address = MAC array
if (!elmConnected)
  {
   Serial.println("No conecta. Verifica MAC, visibilidad y PIN.");
   while(1); // Bloquea si falla
  }
myELM327.begin(SerialBT); // Inicializa ELMduino con el canal Bluetooth

D_ Detección automática del protocolo OBD-II de la ECU
Por defecto, ELMduino hace la inicialización de protocolo al primer queryPID.
Si el auto soporta ISO 9141, 14230, 15765 (CAN), el ELM327 negocia automáticamente.
Puedes forzar el protocolo con comandos AT, pero casi nunca es necesario.
Ejemplo:

SerialBT.print("ATSP 0\r\n"); // Autoselect protocolo

E_ Consulta de PIDs (Parámetros OBD)
Les muestro el formato simple de como confeccionar el llamado a las funciones correspondientes para poder leer los PIDs standar

CSS:
//Ejemplo: Leer velocidad del vehículo (PID 0x0D)

if (myELM327.queryPID("0D"))
   { // PID string
    int velocidad = myELM327.speedo(); // Valor en km/h
    Serial.print("Velocidad actual: ");
    Serial.println(velocidad);
   }
   else
   {
    Serial.println("Error al consultar velocidad. Sin datos válidos.");
   }

Otros PIDs útiles soportados por la libreria y el ELM327:

CSS:
//-------------------------------------------------------------------------------------//
// PIDs (https://en.wikipedia.org/wiki/OBD-II_PIDs)
//-------------------------------------------------------------------------------------//
//PID hex | Descripción | Método directo ELMduino | Unidades
0x04 | Engine Load | myELM327.engineLoad() | %
0x05 | Coolant Temp | myELM327.engineCoolantTemp() | °C
0x06 | Short Term Fuel Trim Bank 1 | myELM327.shortTermFuelTrimBank1() | %
0x07 | Long Term Fuel Trim Bank 1 | myELM327.longTermFuelTrimBank1() | %
0x08 | Short Term Fuel Trim Bank 2 | myELM327.shortTermFuelTrimBank2() | %
0x09 | Long Term Fuel Trim Bank 2 | myELM327.longTermFuelTrimBank2() | %
0x0A | Fuel Pressure | myELM327.fuelPressure() | kPa
0x0B | Intake Manifold Pressure | myELM327.intakeManifoldPressure() | kPa
0x0C | Engine RPM | myELM327.rpm() | rpm
0x0D | Vehicle Speed | myELM327.speedo() | km/h
0x0E | Timing Advance | myELM327.timingAdvance() | ° before TDC
0x0F | Intake Air Temp | myELM327.intakeAirTemp() | °C
0x10 | MAF Flow Rate | myELM327.mafRate() | g/s
0x11 | Throttle Position | myELM327.throttle() | %
0x13 | O2 Sensors Present (2 banks) | myELM327.oxygenSensorsPresent2Banks() | bit encoded
0x14 | O2 Sensor 1 | myELM327.o2SensorVolt(1) | V
0x15 | O2 Sensor 2 | myELM327.o2SensorVolt(2) | V
0x16 | O2 Sensor 3 | myELM327.o2SensorVolt(3) | V
0x17 | O2 Sensor 4 | myELM327.o2SensorVolt(4) | V
0x1C | OBD Standards | myELM327.obdStandards() | Código/desc.
0x1F | Run Time Since Engine Start | myELM327.runTimeSinceEngineStart() | segundos
0x21 | Distance with MIL On | myELM327.distanceTraveledWithMILOn() | km
0x2F | Fuel Tank Level Input | myELM327.fuelTankLevel() | %
0x33 | Barometric Pressure | myELM327.barometricPressure() | kPa
0x3C | Catalyst Temp Bank 1 Sensor 1 | myELM327.catalystTempBank1Sensor1() | °C
0x3D | Catalyst Temp Bank 2 Sensor 1 | myELM327.catalystTempBank2Sensor1() | °C
0x3E | Catalyst Temp Bank 1 Sensor 2 | myELM327.catalystTempBank1Sensor2() | °C
0x3F | Catalyst Temp Bank 2 Sensor 2 | myELM327.catalystTempBank2Sensor2() | °C
0x42 | Control Module Voltage | myELM327.controlModuleVoltage() | Volts
0x43 | Absolute Load Value | myELM327.absoluteLoad() | %
0x45 | Relative Throttle Position | myELM327.relativeThrottlePosition() | %
0x46 | Ambient Air Temp | myELM327.ambientAirTemp() | °C
0x47 | Absolute Throttle Position B | myELM327.absoluteThrottlePositionB() | %
0x48 | Absolute Throttle Position C | myELM327.absoluteThrottlePositionC() | %
0x49 | Accelerator Pedal Position D | myELM327.acceleratorPedalPositionD() | %
0x4A | Accelerator Pedal Position E | myELM327.acceleratorPedalPositionE() | %
0x4B | Accelerator Pedal Position F | myELM327.acceleratorPedalPositionF() | %
0x4C | Commanded Throttle Actuator | myELM327.commandedThrottleActuator() | %
0x51 | Fuel Type | myELM327.fuelType() | Código/desc.
0x52 | Ethanol Fuel % | myELM327.ethanolFuel() | %
0x5C | Engine Oil Temp | myELM327.engineOilTemp() | °C
0x5D | Fuel Injection Timing | myELM327.fuelInjectionTiming() | °
0x5E | Engine Fuel Rate | myELM327.engineFuelRate() | L/h
0x59 | Fuel Rail Abs Pressure | myELM327.fuelRailAbsPressure() | kPa

Nota:
No todos los autos responden todos los PIDs; la librería puede devolver “NO DATA” si la ECU no lo soporta.

F_Sketch de ejemplo simple:

Bien, en base a todos los paso que les mencione anteriormente, les voy a mostrar un simple programa para conectar / emparejar el ESP32 con el ELM327, configurar el protocolo y luego monitorear los PIDs de Velocidad y RPM

CSS:
#include <BluetoothSerial.h>
#include "ELMduino.h"

extern "C" {
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
}

uint8_t address[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
BluetoothSerial SerialBT;
ELM327 myELM327;

void setup()
    {
     Serial.begin(115200);
     // PIN 1234 configuración
     esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
     esp_bt_pin_code_t pin_code = {'1','2','3','4'};
     esp_bt_gap_set_pin(pin_type, 4, pin_code);
     SerialBT.begin("ESP32Cruise", true);
     delay(500);
     if (!SerialBT.connect(address))
        {
         Serial.println("No conecta.");
         while(1);
        }
     myELM327.begin(SerialBT);
     Serial.println("Bluetooth listo, ELM conectado.");
    }

void loop()
   {
    if (myELM327.queryPID("0D"))
       {
        Serial.print("Velocidad: ");
        Serial.println(myELM327.speedo());
       }
       else
       {
        Serial.println("Sin datos de velocidad.");
       }
   delay(1000);
  }


Nota: "Consejos de diagnóstico"

-Sigue los mensajes del monitor serial en cada paso.
-Si no hay respuesta, revisa fuente, cableado y que el ELM327 esté en modo visible (Luz roja indicador de energizado, lux verde indicador de emparejado con un dispositivo).
-Si el protocolo no negocia solo, prueba manualmente:

SerialBT.print("ATSP 0\r\n"); (autoselección)
SerialBT.print("ATSP 6\r\n"); (CAN 11bit 500kbps, común en autos modernos)

De seguro, te preguntaras por que incluyo “\r\n”… Bien, en las librerías viejas no había problemas con tan solo enviar el comando crudo, pero con la actualización de la librería, tuve que optar de sumarlos para indicar un salto de línea, indicando que la línea actual ha terminado y que el próximo carácter debe comenzar en una línea nueva…
Como llegue a esta conclusión, o como llegue a entender el problema que tenia de eco y que no me contestara?
Tenia conexión con el ELM327, pero al hacerle consultas, solo tenia eco y ninguna respuesta… se me ocurrió usar una app de Android (Serial Bluetooth terminal) para mandar algunos comandos, y ahí note que el formato que estaba implementando, estaba incompleto… paso seguido, arme este sketch corto para ver bien cual era el formato correcto:

CSS:
#include <BluetoothSerial.h>
#include "ELMduino.h"

extern "C" {
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
}

uint8_t address[6] = {0x1C, 0xA1, 0x35, 0x69, 0x8D, 0xC5};
BluetoothSerial SerialBT;

void setup()
    {
     Serial.begin(115200);
     delay(1500);
     Serial.println("Iniciando Bluetooth y configurando PIN 1234...");
     // Configura el PIN de emparejamiento (ajusta si tu dongle es otro)
     esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
     esp_bt_pin_code_t pin_code = {'1','2','3','4'};
     esp_bt_gap_set_pin(pin_type, 4, pin_code);
     SerialBT.begin("OBDII", true);
     delay(500);
     Serial.println("Intentando conectar con ELM327 por Bluetooth...");
     bool elmConnected = SerialBT.connect(address);
     if (elmConnected)
        {
         Serial.println("¡Conectado con ELM327 por Bluetooth!\n");
         Serial.println("*** MENÚ DE PRUEBA AT ***");
         Serial.println("a: Enviar 'ATI' + \\n");
         Serial.println("b: Enviar 'ATI' + \\r");
         Serial.println("c: Enviar 'ATI' + \\r\\n");
         Serial.println("d: Enviar comando AT/PID personalizado (terminación \\r\\n)");
         Serial.println("q: Salir (bloquea loop)");
         Serial.println("Ingresa opción y ENTER:");
        }
        else
        {
         Serial.println("NO se pudo conectar con ELM327. Verifica MAC, encendido, visibilidad y PIN.");
         while (1);
        }
   }

void loop()
    {
     if (Serial.available())
        {
         String input = Serial.readStringUntil('\n');
         input.trim();
         if (input == "a")
            {
             Serial.println("Enviando 'ATI\\n'...");
             SerialBT.print("ATI\n");
             delay(500);
             while (SerialBT.available()) Serial.write(SerialBT.read());
             }
         else if (input == "b")
            {
             Serial.println("Enviando 'ATI\\r'...");
             SerialBT.print("ATI\r");
             delay(500);
             while (SerialBT.available()) Serial.write(SerialBT.read());
            }
         else if (input == "c")
            {
             Serial.println("Enviando 'ATI\\r\\n'...");
             SerialBT.print("ATI\r\n");
             delay(500);
             while (SerialBT.available()) Serial.write(SerialBT.read());
            }
        else if (input == "d")
            {
             Serial.println("Ingresa el comando AT/PID (sin terminador), y ENTER:");
             while (!Serial.available()) {}
             String cmd = Serial.readStringUntil('\n');
             cmd.trim();
             String toSend = cmd + "\r\n";
             SerialBT.print(toSend);
             delay(500);
             while (SerialBT.available()) Serial.write(SerialBT.read());
             }
        else if (input == "q")
            {
             Serial.println("Fin del loop de prueba.");
             while (1);
            }
        else
            {
             Serial.println("Opción inválida.");
            }
        }
    }

Lo cual, me dio como resultado en el terminal:

CSS:
Iniciando Bluetooth y configurando PIN 1234...
Intentando conectar con ELM327 por Bluetooth...
¡Conectado con ELM327 por Bluetooth!
*** MENÚ DE PRUEBA AT ***
a: Enviar 'ATI' + \n
b: Enviar 'ATI' + \r
c: Enviar 'ATI' + \r\n
d: Enviar comando AT/PID personalizado (terminación \r\n)
q: Salir (bloquea loop)
Ingresa opción y ENTER:

Enviando 'ATI\n'...
ATI
ELM327 v1.5
>Enviando 'ATI\r'...
ATI          // esto es un eco
ELM327 v1.5  // esto es la respuesta del ELM327
>Enviando 'ATI\r\n'...
ATI         // esto es un eco
ELM327 v1.5 // esto es la respuesta del ELM327
>Ingresa el comando AT/PID (sin terminador), y ENTER:
100
BUS INIT: Fin del loop de prueba.

G_CONSEJOS FINALES

-Revisa el monitor serial para ver si hay errores de conexión.
-Asegurarse de que el ELM327 esté energizado antes que el ESP32.
-Si logras leer datos pero no tienen sentido, prueba con otro PID o revisa si tu auto es compatible OBD-II.


En las próximas actualizaciónes, les voy a mostrar mas como interpretar las respuestas de los datos cuando consultamos el estado de un PIDs... Vamos a intentar rescatar el viejo proyecto con el HC-05 y el Arduino NANO, y de postre, dos proyectos que se estan cocinandon en el horno:
Un DashBOARD con funcion VIGIA (podes monitorear estado de algunos sensores y tener alarmas criticas), y el control de velocidad crucero
Saludos desde la Patagonia Argentina
 

Adjuntos

  • Libreria ELMduino.rar
    6.7 KB · Visitas: 1
Última edición:
Atrás
Arriba