3. CAN网关概述

好,咱们进入第三章。前面聊了CAN协议的基础,说白了就是一堆电信号在总线上跑。那这些信号是谁产生的?又是谁把它变成差分电压的?答案就是今天的主角——CAN控制器和收发器。

我经常跟学员说一句话:控制器是大脑,收发器是嘴巴和耳朵。大脑想说什么,嘴巴把它喊出去;耳朵听到声音,再传给大脑。就这么简单。

3.1 CAN控制器:SJA1000 vs MCP2515

先看控制器。市面上主流的独立CAN控制器,绕不开两个型号:NXP的SJA1000和Microchip的MCP2515。我两个都用过,各有脾气。

3.1.1 SJA1000——老将出马

SJA1000是飞利浦(现NXP)的经典产品,从90年代就开始服役了。它支持两种模式:BasicCAN和PeliCAN。PeliCAN是扩展模式,支持2.0B协议,也就是29位标识符。

特性 SJA1000 MCP2515
接口 并行(8位) SPI(最高10MHz)
支持协议 CAN 2.0A/B CAN 2.0A/B
接收缓冲 64字节FIFO 2个接收缓冲 + 3个掩码
工作电压 5V 3.3V / 5V
封装 DIP28 / SO28 SOIC18 / DIP18

SJA1000最大的特点就是并行接口。这意味着你需要至少8根数据线加若干控制线才能跟MCU通信。我记得第一次用SJA1000搭电路,光布线就折腾了半天,引脚太多,走线绕来绕去。

我的经验:SJA1000适合资源丰富的MCU,比如带外部总线接口的ARM7或C51。如果你MCU引脚紧张,别碰它,否则你会被IO口不够用逼疯。

3.1.2 MCP2515——后起之秀

MCP2515是Microchip推出的SPI接口CAN控制器。它只有18个引脚,通过SPI跟MCU通信,只需要4根线:SCK、MOSI、MISO、CS。省引脚,省布线,省心。

我做过一个项目,MCU只有20个IO口,还要控制LCD、按键、传感器。如果用SJA1000,IO口根本不够分。换成MCP2515,只用了4个SPI引脚,剩下的全给外设。嗯,这就是它存在的意义。

MCP2515内部有2个接收缓冲器和3个验收滤波掩码。你可以配置只接收特定ID的报文,减少MCU的负担。这一点在网关项目中特别有用——比如只让发动机相关的报文通过,其他的一律过滤掉。

选型建议:
  • MCU引脚多、要求实时性高 → SJA1000(并行访问速度快)
  • MCU引脚少、追求布线简单 → MCP2515(SPI接口省引脚)
  • 需要多路CAN → 两个都能用,但MCP2515更容易扩展

3.2 TJA1050收发器——信号的中转站

控制器输出的是逻辑电平(0或1),但CAN总线需要的是差分信号(CAN_H和CAN_L之间的电压差)。这个转换工作,就交给收发器。

TJA1050是NXP出品的高速CAN收发器,支持最高1Mbps的速率。它替代了早期的TJA1040和PCA82C250,在电磁兼容性上做了优化。

3.2.1 TJA1050的引脚功能

引脚 名称 功能
1 TXD 发送数据输入(来自控制器)
2 GND 地
3 VCC 电源(5V)
4 RXD 接收数据输出(给控制器)
5 VREF 参考电压输出(一般悬空)
6 CANL CAN低电平总线
7 CANH CAN高电平总线
8 STB 待机模式控制(低电平待机)

TJA1050有个待机模式,通过STB引脚控制。拉低STB,收发器进入低功耗状态,电流降到微安级。这在车载ECU休眠时特别有用。我曾经调试过一个项目,总线上的节点在休眠后还在发报文,查了半天发现是STB引脚没拉高,收发器根本没睡。

注意:TJA1050的TXD引脚不能长时间拉低。如果TXD持续低电平超过约1ms,收发器会进入故障模式,总线被强制显性,导致整个网络瘫痪。我见过有人写代码时忘了释放TXD,结果一上电总线就死了。

3.3 硬件接口设计——从原理图到PCB

好了,芯片选完了,怎么把它们连起来?我画个结构图给你看。

CAN节点硬件架构 MCU (STM32/AVR/ARM) CAN控制器 SJA1000/MCP2515 CAN收发器 TJA1050 并行/SPI TXD/RXD CAN总线 CAN_H / CAN_L 差分信号 关键说明: 1. MCU通过并行总线或SPI与CAN控制器交换数据 2. 控制器将数据转换为TXD/RXD逻辑信号给收发器 3. 收发器将逻辑信号转换为CAN_H/CAN_L差分信号

3.3.1 典型电路设计

下面是一个MCP2515 + TJA1050的典型电路。我直接给你看关键部分。

// MCP2515与TJA1050连接示意
// MCU (SPI) → MCP2515 → TJA1050 → CAN总线

// MCP2515引脚分配
// CS   → PB0 (片选)
// SCK  → PB1 (SPI时钟)
// SI   → PB2 (MOSI)
// SO   → PB3 (MISO)
// INT  → PD2 (中断输出)

// TJA1050连接
// TXD  → MCP2515 TXCAN
// RXD  → MCP2515 RXCAN
// STB  → GND (正常模式)
// VREF → 悬空

// 总线终端电阻
// CAN_H 与 CAN_L 之间接 120Ω 电阻
// 总线两端各一个,不能少

这里有个细节:终端电阻。CAN总线两端必须各接一个120Ω电阻,作用是匹配阻抗、消除信号反射。我见过有人偷懒只接一个,结果总线在高速通信时波形乱七八糟,丢帧严重。

避坑指南:我曾经在一个项目中,总线长度只有30厘米,想着这么短就不用终端电阻了。结果一上1Mbps,通信时好时坏。加上120Ω电阻后,问题立刻消失。所以,不管总线多短,终端电阻必须加。

3.3.2 电源与去耦

CAN收发器工作时会产生瞬态电流,电源必须做好去耦。我的习惯是:

  • 每个芯片的VCC引脚旁边放一个100nF陶瓷电容,尽量靠近引脚
  • 再加一个10μF电解电容做储能
  • 电源走线要宽,至少20mil
  • CAN_H和CAN_L走线要平行,远离时钟线

嗯,这些看起来是小细节,但往往就是这些小细节决定了产品能不能过EMC测试。

3.3.3 共模扼流圈与保护

车载环境很恶劣,总线可能会受到各种干扰。我建议在CAN_H和CAN_L上串联共模扼流圈(Common Mode Choke),它能抑制共模干扰,同时不影响差分信号。

另外,别忘了加ESD保护管。我选的是NUP2105L,专门用于CAN总线,结电容低,不影响信号质量。

警告:不要用普通的TVS管代替ESD保护管。普通TVS结电容太大,会严重衰减高速信号。我见过有人用1N4148做钳位,结果总线速率降到100kbps才能工作。

3.4 实战案例:一个双节点CAN通信系统

最后,我带你走一遍实际搭建过程。假设我们要做两个节点:

  • 节点A:STM32F103 + MCP2515 + TJA1050
  • 节点B:STM32F103 + MCP2515 + TJA1050
  • 总线:双绞线,两端各一个120Ω电阻

接线步骤:

  1. 两个节点的CAN_H接在一起,CAN_L接在一起
  2. 总线两端各并联一个120Ω电阻
  3. 所有节点共地(GND连在一起)
  4. 上电,用示波器看CAN_H和CAN_L的波形

正常波形应该是:隐性时CAN_H≈2.5V,CAN_L≈2.5V;显性时CAN_H≈3.5V,CAN_L≈1.5V。如果你看到波形不对,先检查终端电阻和电源。

调试口诀:
  • 波形不对 → 查终端电阻
  • 通信丢帧 → 查电源去耦
  • 节点不上线 → 查TXD是否被拉低
  • 速率上不去 → 查共模扼流圈和ESD管