Electronic OBDII Gauge on Luminardo

Let’s make something more complex using Luminardo, a Bluetooth dongle, a OBDII translator ELM327 and a 128×64 pixels graphical monochrome OLED display SSD1306. The plan would be to utilise USB host functionality to communicate to ELM327 via SPP interface and represent such parameters as engine RPM, vehicle speed, battery voltage, remaining fuel on a display. In a way it will be like the well known OBDuino, however, we are going to take full advantage of a graphical display and in our case we are going to have a wireless communication interface. For simplicity sake we won’t implement trip computer to calculate distance traveled, fuel consumption per 100 km or tank distance, instead, we will be focusing on user interface and modular firmware architecture which would allow to integrate additional functionality later and with minimum development effort.

The information displayed on a display in mostly numeric, some of them more significant, some of them less, so most probably we will need to have several font sizes (or fonts). We strongly believe that it this application numeric data would be looked more professional if seven segment font is used. And if so, we would need to add more seven segment fonts as we have only 32×50 sevenSegNumBigFont. To add more options we will introduce 25×40 sevenSegNumMediumFont and 10×16 sevenSegNumSmallFont fonts and define them in glcdfont.h.

Next step is to prepare icons, the plan would be to display a number next to icon so that it would be intuitively clear and obvious what kind of information a number represents. For example, a battery icon for voltage readings, a fuel dispenser icon for tank level, a thermometer icon for temperature readings, well, you’ve got the idea. The will be two icons of the same type – one which fills the whole display for warnings in case of critical levels and one is of a regular size, 18 pixels maximum in height to roughly match with the small seven segment font. We would need the following icons: a car battery, a bluetooth, a fuel dispenser, a thermometer, a ‘car doors open’, a clock. The last two are ‘just in case’. All these icons will be defined in Icons.h.

Let’s also specify the most important architectural considerations. First of all, we will be heavily relying on Bluetooth communication between our Luminardo board and ELM327 OBDII adapter. Therefore, we will have to indicate explicitly connection status and upon boot up don’t progress to any screen with numbers until the connection is successfully established. It would be also necessary to distinguish two different states of connection: successful pairing/connection with ELM327 and successful recognition of the OBDII protocol with ability to communicate to a vehicle. That way to will definitely detect situations when Luminardo can communicate to ELM327 but ELM327 can’t communicate to a vehicle. It would be also highly desirable to display additional information about ELM327 upon connection – for example, its firmware revision number.

Next, we won’t be using delays in our code as it is very wasteful style of programming, especially for embedded devices with their limited computational power and battery power sources. Given that we have only single thread process (which is a limitation of most 8-bit microprocessor systems including Arduino) required delays between subsequent operations will be achieved by introduction states and counters, holding number of milliseconds passed since the previous operation. That way in the main loop we will be checking each counter whether it is time to progress to the next state, execute next operation and update counter with a new value or simply move on to check next counter. The code execution flow in this case will be non-blocking as this is exactly what we want.

Some parameter values will be refreshed less frequent than others. For example, engine RPM and vehicle speed will be requested from the vehicle every time when display is refreshed whereas tank level, battery voltage and temperature values change much slower and therefore they need to be retrieved and updated on the screen less frequent. Given, that from our previous experiments with display we discovered that full frame refresh takes longer than the actual transfer of block of data from microcontroller to OLED, we will be updating only those areas on the screen which are changing. In other words, if we retrieved just new values for PRM and speed we will be updating only appropriate numbers on the screen and nothing else.

With modularity and simplicity in mind, the sketch will be subdivided into several logical parts: the main part Luminardo_OBDII_BT_128x64_i2c.ino with top level logic, settings, definitions and global variables in Luminardo_OBDII_BT_128x64_i2c.h, string constants in Messages.h, auxiliary/utility functions in Utils.h and graphics in Icons.h.

There are two things to be configured before your Luminardo board will be able to find and connect to your ELM327. It is ELM327 Bluetooth address and pin code. Note, that Bluetooth address is specified in reversed order as shown in the code below:

//40:22:11:00:69:58 ELM327 OBDII
uint8_t remote_addr[6] = {0x58, 0x69, 0x00, 0x11, 0x22, 0x40};
SPPi SerialBT(&Btd, "Luminardo", "1234", true, (uint8_t*)&remote_addr);

It is also possible to adjust warning thresholds, these are: battery low voltage level (in volts multiplied by 10) and tank level (percentage remain) as shown in the code below:

#define BATTERY_VOLTAGE_WARN_THRESHOLD 110 //Multiplied by 10
#define TANK_LEVEL_WARN_THRESHOLD 30 //Percentage remain

Luminardo was specifically designed with slim form factor in mind and more small but useful features if compare with Arduino boards. However, given that Luminardo is an Arduino clone, it is possible to build the same functionality using an Arduino board. The final result will be rather bulky but nevertheless, it is still very much possible.

The final source code is freely available below.


1. Luminardo_OBDII_BT_SSD1306_2015_04_29.zip Luminardo OBDII sketch with customised SSD1306 OLED library;

2. USB_Host_Shield_2_SPP_Client_Support_2015_05_05.zip Customised USB Host 2.0 library with SPP client support;

3. Github repository with Luminardo core for Arduino environment;