CAN 总线分析仪实战:汽车诊断工具 DIY,读懂车轮上的网络

CAN 总线分析仪实战:汽车诊断工具 DIY,读懂车轮上的网络

CAN 总线分析仪实战:汽车诊断工具 DIY,读懂车轮上的网络

作为一名嵌入式开发者,你是否好奇汽车内部是如何通信的?今天我们就来动手制作一台 CAN 总线分析仪,不仅能读取汽车 OBD-II 数据,还能用于工业 CAN 网络调试。花不到 200 元,就能拥有专业级诊断工具的核心功能!

需要准备什么?

物品型号/规格价格
主控板STM32F103C8T6 (Blue Pill)¥15
CAN 模块TJA1050 CAN 收发器¥8
OBD-II 接口16 针 OBD 母头¥12
显示屏0.96 寸 OLED I2C¥10
杜邦线公对公/公对母¥5
外壳3D 打印/塑料盒¥20
稳压模块AMS1117 3.3V¥3
总计¥73

如果直接购买成品 CAN 分析仪,价格通常在 300-800 元。我们 DIY 的成本只有四分之一,而且还能完全掌控源代码!

步骤 1:理解 CAN 总线基础

在动手之前,我们先快速了解 CAN 总线的核心概念:

CAN 是什么?

  • Controller Area Network,控制器局域网

  • 由博世 1986 年开发,最初用于汽车

  • 现在广泛应用于工业、医疗、航空航天

关键特性:

  • 双线差分信号(CAN_H 和 CAN_L)

  • 多主架构,无需主机

  • 自带错误检测和重发机制

  • 标准帧 11 位 ID,扩展帧 29 位 ID

  • 常见波特率:125K/250K/500K/1M bps

汽车 OBD-II 引脚定义:

OBD-II 接口(从上往下看):
┌─────────────────────────────────┐
│  ○ 1  ○ 2  ○ 3  ○ 4  ○ 5  ○ 6  ○ 7  ○ 8  │
│  ○ 9  ○10  ○11  ○12  ○13  ○14  ○15  ○16  │
└─────────────────────────────────┘

关键引脚:
- Pin 4: 底盘接地 (GND)
- Pin 5: 信号接地 (GND)
- Pin 6: CAN_H (ISO 15765-4)
- Pin 14: CAN_L (ISO 15765-4)
- Pin 16: 电池正极 (+12V)

⚠️ 注意事项: 汽车电瓶电压是 12V,但我们的 STM32 工作在 3.3V!必须使用稳压模块,否则会烧毁芯片。

步骤 2:硬件连接

按照下图连接电路:

STM32F103C8T6 ←→ TJA1050 CAN 模块
─────────────────────────────────────
3.3V            ←→ VCC
GND             ←→ GND
PA11 (USB_DM)   ←→ CAN_RX (实际是 TX)
PA12 (USB_DP)   ←→ CAN_TX (实际是 RX)

TJA1050 ←→ OBD-II 接口
─────────────────────────────────────
CAN_H       ←→ Pin 6
CAN_L       ←→ Pin 14
GND         ←→ Pin 4 或 Pin 5
+12V        ←→ Pin 16 (经 AMS1117 稳压到 3.3V)

OLED 显示屏 ←→ STM32
─────────────────────────────────────
VCC         ←→ 3.3V
GND         ←→ GND
SCL         ←→ PB6
SDA         ←→ PB7

接线技巧:

  1. $1

  2. $1

  3. $1

步骤 3:软件环境搭建

我们使用 Arduino IDE 开发,配合 CAN 库:

# 安装 Arduino IDE(如果还没有)
sudo apt-get update
sudo apt-get install arduino arduino-core-avr

# 安装 STM32 核心(通过 Boards Manager)
# 1. 打开 Arduino IDE
# 2. 文件 → 首选项 → 附加开发板管理器 URL
# 3. 添加:https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
# 4. 工具 → 开发板 → 开发板管理器 → 搜索\"STM32\" → 安装

# 安装 CAN 库
#  sketch → 加载库 → 管理库 → 搜索\"CAN\" → 安装\"CAN\" by sandeep mistry

开发板配置:

  • 开发板:Generic STM32F1 series

  • 型号:STM32F103C8

  • Upload method: STM32CubeProgrammer (SWD)

  • CPU Speed: 72MHz

  • Optimize: Smallest (-Os)

步骤 4:核心代码实现

#include 
#include 
#include 
#include 

// OLED 配置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// CAN 配置
#define CAN_RX_PIN PA11
#define CAN_TX_PIN PA12
#define CAN_BAUDRATE 500000  // 500Kbps (汽车常用)

// 按钮引脚(可选,用于切换页面)
#define BUTTON_PIN PA0

unsigned long lastMsgTime = 0;
int currentPage = 0;
unsigned long canMsgCount = 0;

// OBD-II PID 请求
const uint8_t OBD_REQUEST[] = {0x02, 0x01, 0x0C};  // 请求发动机转速

void setup() {
  Serial.begin(115200);
  while (!Serial);

  // 初始化 OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F(\"SSD1306 allocation failed\"));
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(\"CAN 分析仪初始化...\");
  display.display();

  // 初始化 CAN
  pinMode(CAN_RX_PIN, INPUT);
  pinMode(CAN_TX_PIN, OUTPUT);
  CAN.setPins(CAN_RX_PIN, CAN_TX_PIN);

  if (!CAN.begin(CAN_BAUDRATE)) {
    display.println(\"CAN 初始化失败!\");
    display.display();
    Serial.println(\"Starting CAN failed!\");
    while (1);
  }

  display.println(\"CAN 初始化成功!\");
  display.print(\"波特率:\");
  display.print(CAN_BAUDRATE / 1000);
  display.println(\"Kbps\");
  display.display();

  Serial.println(\"CAN 总线分析仪就绪\");
  Serial.print(\"波特率:\");
  Serial.println(CAN_BAUDRATE);

  // 发送 OBD-II 初始化请求(模式 01)
  sendOBDRequest(0x01, 0x00);
  delay(100);
}

void loop() {
  // 接收 CAN 消息
  int packetSize = CAN.parsePacket();
  if (packetSize) {
    canMsgCount++;

    uint32_t canId = CAN.packetId();
    uint8_t data[8];
    int dataLen = 0;

    while (CAN.available()) {
      if (dataLen  5000) {
    displayStandbyScreen();
  }

  // 每秒发送一次 OBD 请求
  if (millis() % 1000 = 3) {
    display.println(\"--- OBD 响应 ---\");
    parseOBDResponse(data, len);
  }

  display.display();
}

// 解析 OBD-II 响应
void parseOBDResponse(uint8_t* data, int len) {
  if (len >= 3 && data[1] == 0x41) {  // 模式 01 响应
    uint8_t pid = data[2];

    if (pid == 0x0C && len >= 5) {  // 发动机转速
      // 转速 = (A*256 + B) / 4
      int rpm = ((data[3] * 256) + data[4]) / 4;
      display.print(\"转速:\");
      display.print(rpm);
      display.println(\" RPM\");
    }
    else if (pid == 0x0D && len >= 4) {  // 车速
      uint8_t speed = data[3];
      display.print(\"车速:\");
      display.print(speed);
      display.println(\" km/h\");
    }
    else if (pid == 0x0F && len >= 4) {  // 冷却液温度
      int temp = data[3] - 40;
      display.print(\"水温:\");
      display.print(temp);
      display.println(\" °C\");
    }
  }
}

// 串口输出 CAN 消息(CSV 格式,方便导入电脑分析)
void printCanMessage(uint32_t canId, uint8_t* data, int len) {
  Serial.print(millis());
  Serial.print(\",\");
  Serial.print(canId, HEX);
  Serial.print(\",\");
  for (int i = 0; i  500) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println(\"等待 CAN 消息...\");
    display.print(\"总计数:\");
    display.println(canMsgCount);
    display.display();
    lastBlink = millis();
  }
}

代码说明:

  1. $1

  2. $1

  3. $1

  4. $1

  5. $1

步骤 5:测试验证

测试步骤:

  1. $1

  2. $1

预期效果:

  • OLED 显示实时 CAN 消息

  • 发动机启动后显示 RPM 数据

  • 串口监视器输出 CSV 格式数据

常见问题排查

问题 1:CAN 初始化失败

  • 原因: 引脚配置错误或波特率不匹配

  • 解决: 检查 PA11/PA12 是否正确连接,尝试不同波特率(125K/250K/500K)

问题 2:收不到任何消息

  • 原因: 终端电阻缺失或接线错误

  • 解决: 在 CAN_H 和 CAN_L 之间添加 120Ω电阻,检查 OBD 引脚定义

问题 3:显示乱码

  • 原因: OLED 地址错误(常见 0x3C 或 0x3D)

  • 解决: 修改 display.begin(SSD1306_SWITCHCAPVCC, 0x3C) 中的地址

问题 4:OBD 响应解析错误

  • 原因: 不同车型的 OBD 协议可能不同

  • 解决: 先打印原始数据,根据实际响应调整解析逻辑

问题 5:设备发热严重

  • 原因: 稳压模块负载过大

  • 解决: 检查是否有短路,添加散热片,避免长时间从 OBD 取电

扩展功能建议

完成基础版本后,你可以考虑以下升级:

  1. $1

  2. $1

  3. $1

  4. $1

  5. $1

总结

通过这个项目,我们:

  • 理解了 CAN 总线的工作原理

  • 掌握了 TJA1050 CAN 收发器的使用方法

  • 学会了 OBD-II 协议的基本解析

  • 制作了一台成本不到 100 元的 CAN 分析仪

这台设备不仅可以用于汽车诊断,还能用于工业 CAN 网络调试、智能家居系统分析等场景。更重要的是,你完全掌握了源代码,可以根据需求自由定制功能。

下一步,你可以尝试:

  • 解析更多 OBD-II PID(故障码、油耗等)

  • 开发电脑端分析软件(Python + PyQt)

  • 制作精美外壳,变成便携式工具

希望这篇博客文章对您有所帮助!


相关资源:

  • CAN 总线协议详解

  • OBD-II PID 列表

  • STM32 CAN 库文档

  • 本项目 GitHub 仓库

  • TJA1050 数据手册