Hi all,
I am using the ELMduino library with an Arduino Uno, HC05 bluetooth module and 20x4 LCD display.
I've gone into the AT settings menu on the HC05 (as shown here), and have successfully paired, bound and linked my ELM327 OBD dongle. As a side note, for anyone struggling at the HC05 stage, if your module has V3 firmware, try this link - it was the only source that worked for me. Anyway, this seems to work fine. On startup, the HC05 quickly flashes twice every 5s, which I believe means connected. Great.
I am struggling to establish reliable data transfer. At first I would constantly get the error "NO DATA" when using the debugging printout, but very occasionally a correct value would be sent over. I would say roughly every 20 seconds a correct RPM value is sent over. More often a value of 0 is sent over, and the vast majority of the time NO DATA is sent.
I was using SoftwareSerial, but have now switched to hardware using pins 0 and 1. Moving the HC05 closer to the ELM327 seems to make no difference so I don't think its a bluetooth signal issue. I am using soldered connections, and wiggling pins also seems to change nothing, so I don't think its a wiring issue. I'm almost more confused that it occasionally pings a correct value across.
The final idea is to display several PID values, which is why my code is adapted from the "multiple_pids" example in the library, but even when testing the "hardwareserial" example querying only RPM, the same very very sporadically successful behaviour was seen.
Any thoughts? Code below.
EDIT: I should also say I am using a voltage divider, and have checked voltages. In fact the USB cable I'm using was only giving around 4.5V, so resistances were adjusted to make sure the HC-05 datalines get 3.3V, so I don't think its that either.
One other potential clue is that even just setting the correct AT commands when pairing the HC05, signals always sent fine, and rarely ever failed, but the return message characters were very often garbled. For example sending like AT+UART?, which should return something like AT+UART:115,200,20, would actually send something like AT+UdRT:11f,20b,20. Not specifically, but often garbled.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "ELMduino.h"
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
#define ELM_PORT Serial
ELM327 myELM327;
typedef enum { RPM,
COOLANT,
AIR,
OIL } obd_pid_states;
obd_pid_states obd_state = RPM;
float rpm = 0;
float coolant_temp = 0;
float air_temp = 0;
float oil_temp = 0;
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("RPM:");
lcd.setCursor(0, 1);
lcd.print("Tc:");
lcd.setCursor(0, 2);
lcd.print("Ta:");
lcd.setCursor(0, 3);
lcd.print("To:");
ELM_PORT.begin(115200);
if (!myELM327.begin(ELM_PORT, false, 2000))
{
while (1);
}
}
void loop() {
switch (obd_state){
case RPM: {
float temp_rpm = myELM327.rpm();
if (myELM327.nb_rx_state == ELM_SUCCESS){
rpm = temp_rpm;
obd_state = COOLANT;
}
else if (myELM327.nb_rx_state != ELM_GETTING_MSG){
obd_state = COOLANT;
}
break;
}
case COOLANT:{
float coolant_temp_temp = myELM327.engineCoolantTemp();
if (myELM327.nb_rx_state == ELM_SUCCESS)
{
coolant_temp = coolant_temp_temp;
obd_state = AIR;
}
else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
{
obd_state = AIR;
}
break;
}
case AIR:{
float air_temp_temp = myELM327.intakeAirTemp();
if (myELM327.nb_rx_state == ELM_SUCCESS)
{
air_temp = air_temp_temp;
obd_state = OIL;
}
else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
{
obd_state = OIL;
}
break;
}
case OIL:{
float oil_temp_temp = myELM327.oilTemp();
if (myELM327.nb_rx_state == ELM_SUCCESS)
{
oil_temp = oil_temp_temp;
obd_state = RPM;
}
else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
{
obd_state = RPM;
}
break;
}
}
update_lcd();
}
void update_lcd(){
lcd.setCursor(4, 0);
lcd.print(" ");
lcd.setCursor(4, 1);
lcd.print(" ");
lcd.setCursor(4, 2);
lcd.print(" ");
lcd.setCursor(4, 3);
lcd.print(" ");
lcd.setCursor(5, 0);
lcd.print(rpm);
lcd.setCursor(4, 1);
lcd.print(coolant_temp);
lcd.setCursor(4, 2);
lcd.print(air_temp);
lcd.setCursor(4, 3);
lcd.print(oil_temp);
}