š OBD-II CAN Bus Car Scanner
Decode live engine data from any modern car using MCP2515 and OBD-II PIDs.
Overview
Every modern car (1996+ in the US, 2001+ in Europe) has an OBD-II port that exposes the CAN bus ā a robust automotive serial protocol. The MCP2515 is a standalone CAN controller that communicates via SPI with Arduino. By sending standard OBD-II Parameter IDs (PIDs), we can request engine RPM, vehicle speed, coolant temperature, throttle position, and read fault codes.
What you'll learn: CAN bus physical layer (CAN-H, CAN-L, differential signalling), MCP2515 SPI initialization and baud rate matching (500kbps for OBD-II), OBD-II request/response PID format, decoding multi-byte responses, and displaying data on TFT or OLED.
Estimated time: 2ā3 hours. Difficulty: āāāā Advanced.
Components Needed
| Component | Specification | Qty | Notes |
|---|---|---|---|
| Arduino Nano | ATmega328P, 5V | 1 | Compact, easy to mount in car |
| MCP2515 CAN Module | SPI, 16MHz crystal | 1 | CAN bus controller + TJA1050 transceiver |
| OBD-II Breakout Connector | Standard 16-pin J1962 | 1 | Plugs into car dashboard port |
| 0.96" OLED Display | I2C SSD1306 | 1 | Compact dashboard display |
| Wires & Enclosure | 1 set | Mount near OBD port |
Step-by-Step Tutorial
Wire MCP2515 to Arduino
Connect to OBD-II Port
Install CAN Library
mcp_can by Cory Fowler from Library Manager. Initialize at 500kbps: CAN.begin(CAN_500KBPS).Send OBD-II PID Requests
Decode Responses & Display
response[4] == requestedPID before decoding the value.Code / Configuration
// OBD-II CAN Bus Scanner - Volt X
#include <SPI.h>
#include <mcp_can.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
MCP_CAN CAN(10); // CS on Pin 10
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
// OBD-II PID codes (Mode 01)
#define PID_RPM 0x0C
#define PID_SPEED 0x0D
#define PID_COOLANT 0x05
#define PID_THROTTLE 0x11
void requestPID(byte pid) {
byte msg[8] = {0x02, 0x01, pid, 0x00, 0x00, 0x00, 0x00, 0x00};
CAN.sendMsgBuf(0x7DF, 0, 8, msg); // 0x7DF = OBD-II broadcast ID
}
int decodePID(byte pid, byte b3, byte b4) {
switch (pid) {
case PID_RPM: return ((b3 * 256) + b4) / 4;
case PID_SPEED: return b3;
case PID_COOLANT: return b3 - 40;Reviews & Ratings
Sign in to leave a review
Loading reviews...