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: 1
  • HC-05 Comadandos.pdf
    83.7 KB · Visitas: 1
Última edición:
Atrás
Arriba