CAN BUS INTERFACE

OBD-II CAN Bus
OLED Gauges

Unlock hidden diagnostic data straight from your vehicle's engine control network. Assemble an Arduino diagnostic unit that polls PIDs over the high-speed CAN bus network and draws beautiful metrics on a mini OLED screen.

COOLANT TEMP 96°C OK

How OBD-II PIDs Work

Vehicle diagnostic ports utilize standard Parameter IDs (PIDs) defined under the SAE J1979 framework. A diagnostic gauge polls the vehicle ECU by sending requests.

To ask for data, the controller transmits a CAN frame with ID 0x7DF containing the payload service ID and PID hex. The vehicle's ECU responds on ID 0x7E8 containing calculated parameter bytes.

Standard PID Hex codes

01 0C (Engine RPM): Value = ((A × 256) + B) / 4

01 05 (Coolant Temp): Value = A - 40 (Degrees Celsius)

01 11 (Throttle Position): Value = (A × 100) / 255 (Percent)

SPI Communication Network

Arduino microcontrollers are too slow to read raw 500kbps CAN networks directly. We use an MCP2515 CAN Controller chip with a TJA1050 driver interface.

SPI Bus Signals

The MCP2515 buffers incoming high-speed bitstreams, filters out unrelated frames, and relays data packet variables to the Arduino over a standard SPI bus: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCK (Serial Clock), and CS (Chip Select).

Bill of Materials

Everything you need to source to build this custom OBD-II OLED gauge module. Total cost is under $30.

Arduino Nano

Coordinates PID loop query commands and drives graphic buffers on the I2C OLED screen.

~$4.00

MCP2515 CAN Module

Receives and transmits vehicle network packets. TJA1050 translates physical voltage differences.

~$5.00

SSD1306 I2C OLED

Miniature 0.96" high-contrast graphical display. Connects via 4 wires over standard I2C SCL/SDA.

~$4.00

12V to 5V Converter

Taps into car battery line inside OBD port connector and regulates logic voltage rails.

~$2.00

OBD-II Shell Connector

A plastic 16-pin male OBD-II enclosure shell to neatly mount diagnostic wires inside.

~$6.00

Interactive Wiring Diagram

Hover or click on schematic elements to view pinout instructions, SPI cables, and I2C buses.

OBD-II PORT Pins: 6,14,16,4 MCP2515 SCK (D13) MISO (D12) MOSI (D11) CS (D10) CAN H CAN L ARDUINO NANO A4/A5 D10-13 5V GND 5V REGULATOR IN+ OUT+ SSD1306 OLED SDA (A4) SCL (A5) VCC/GND

Wiring Guide

Hover over any module or wire line in the schematic to inspect its installation details and connectivity logic.

OBD-II Port Differential CAN Wires
MCP2515 module SPI Interface bus
Arduino Nano SPI + I2C controller pins
SSD1306 screen I2C OLED Interface

Step-by-Step Assembly

Follow the assembly slides sequentially to wire and mount the CAN bus gauge.

Arduino Firmware Program

Upload this sketch program to your Arduino Nano board using the official Arduino IDE tool.

OBD2_CAN_Gauge.ino
#include <SPI.h>
#include <mcp_can.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define CAN_CS_PIN 10
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

MCP_CAN CAN(CAN_CS_PIN);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

unsigned long lastQueryTime = 0;
int currentTemp = 0;
int currentThrottle = 0;

void setup() {
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 20);
  display.print("Initializing...");
  display.display();

  // Try to initialize CAN at 500kbps (Standard OBD speed)
  while (CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) != CAN_OK) {
    display.clearDisplay();
    display.setCursor(10, 20);
    display.print("CAN Init Failed!");
    display.display();
    delay(500);
  }
  CAN.setMode(MCP_NORMAL);
}

void loop() {
  unsigned long currentTime = millis();
  if (currentTime - lastQueryTime >= 200) { // Query every 200ms
    lastQueryTime = currentTime;
    
    queryOBD2PID(0x05); // Query Coolant Temperature
    delay(20);
    queryOBD2PID(0x11); // Query Throttle Position
    
    updateScreen();
  }
}

void queryOBD2PID(byte pid) {
  // standard OBD frame query payload
  byte payload[8] = {0x02, 0x01, pid, 0x00, 0x00, 0x00, 0x00, 0x00};
  
  // Send 11-bit standard query frame
  CAN.sendMsgBuf(0x7DF, 0, 8, payload);
  
  // Wait short period and read buffer responses
  delay(10);
  long unsigned int rxId;
  unsigned char len = 0;
  unsigned char rxBuf[8];
  
  if (CAN.readMsgBuf(&rxId, &len, rxBuf) == CAN_OK) {
    if (rxId == 0x7E8 && rxBuf[1] == 0x41) { // Positive OBD response
      if (rxBuf[2] == 0x05) {
        currentTemp = rxBuf[3] - 40; // Coolant calculation
      } else if (rxBuf[2] == 0x11) {
        currentThrottle = (rxBuf[3] * 100) / 255; // Throttle calculation
      }
    }
  }
}

void updateScreen() {
  display.clearDisplay();
  
  // Header text
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("OBD-II LIVE TELEMETRY");
  
  // Draw Coolant Temperature
  display.setTextSize(2);
  display.setCursor(0, 16);
  display.print("TEMP: ");
  display.print(currentTemp);
  display.print(" C");

  // Draw Throttle Bar
  display.setTextSize(1);
  display.setCursor(0, 42);
  display.print("THR: ");
  display.print(currentThrottle);
  display.print("%");
  
  // Drawing throttle outline bar
  display.drawRect(50, 42, 75, 10, WHITE);
  int fillWidth = (currentThrottle * 71) / 100;
  display.fillRect(52, 44, fillWidth, 6, WHITE);

  display.display();
}

Firmware Features

SPI MCP2515 OBD-II PIDs I2C OLED SSD1306 Hex Decoders

Logic Explanation

The program utilizes the SPI bus to communicate with the MCP2515 CAN controller. Every 200ms, it transmits standard OBD request frames to PID 0x7DF.

Upon receiving matching response packets, it extracts raw hex bytes and maps them to decimal coolant temperatures and throttle percentages, printing the values to the I2C OLED screen.

Troubleshooting TIP

If initialization stalls on CAN Init failure, verify your MCP2515 quartz crystal speed frequency. Most cheap boards are equipped with 8MHz crystals, but some require setting 16MHz in the CAN.begin() arguments.

Live Interactive Simulator

Adjust the coolant and throttle sliders. Select different virtual layout buttons to change what renders on the virtual SSD1306 OLED panel screen.

Coolant Temperature 90°C
Throttle Position 0%
Select Screen Display Mode