4、CAN数据采集:CAN收发器(TJA1050)、CAN控制器(MCP2515)、SPI接口通信、数据采样率设置

好,咱们进入第四章。这一章是硬骨头,也是实战中最容易出问题的地方。

很多朋友觉得CAN通信嘛,不就是两根线一接,数据就来了?

其实没那么简单。你想想看,MCU的IO口电平是3.3V或者5V,而CAN总线上的差分信号是2.5V共模电压加上±1V的摆幅。这中间怎么搭桥?

答案就是:CAN收发器 + CAN控制器。

我个人习惯把这对组合叫做「CAN通信的左右护法」。收发器负责物理层,控制器负责数据链路层。而它们之间的通信桥梁,就是SPI。


4.1 CAN收发器 TJA1050:物理层的「翻译官」

TJA1050,恩智浦的经典片子。我最早接触它是在2015年做的一个商用车黑匣子项目上,当时选型就因为它皮实、抗干扰。

它的核心作用就两个:

  • 发送方向: 把控制器来的TX数字信号,转成CAN_H和CAN_L的差分信号。
  • 接收方向: 把总线上的差分信号,转成RX数字信号送回控制器。

说白了,它就是个电平转换+驱动增强器。

关键引脚速记:

  • TXD: 发送数据输入(低电平有效,注意!)
  • RXD: 接收数据输出
  • CANH / CANL: 总线差分对
  • Vref: 参考电压输出(2.5V,我一般悬空不用)
  • RS: 斜率控制/待机模式

我曾经踩过的坑:

有一次调试,总线一直报错。查了半天发现TXD引脚默认是高电平,而我初始化时忘了拉低。TJA1050的TXD是低电平使能发送,高电平是进入接收模式。这个逻辑跟很多人的直觉相反,一定要注意。

另外,RS引脚接一个10kΩ电阻到地,可以控制上升沿斜率,减少EMI。如果对电磁兼容要求高,这个电阻别省。


4.2 CAN控制器 MCP2515:数据链路层的「管家」

MCP2515是Microchip的独立CAN控制器。为什么不用MCU自带的CAN外设?

原因很简单:很多低成本MCU不带CAN控制器。而且MCP2515内置了3个发送缓冲器和2个接收缓冲器,还有6个29位ID的滤波器。这个配置对于黑匣子这种需要过滤大量报文的应用来说,非常实用。

MCP2515的主要职责:

  • 按照CAN协议(2.0A/B)对数据进行组帧和解帧
  • 处理仲裁、位填充、CRC校验
  • 管理错误状态和错误计数
  • 通过SPI接口与MCU交换数据

嗯,这里要注意:MCP2515内部有多个寄存器,操作起来有点像操作一个外置的「CAN协处理器」。你通过SPI写它的控制寄存器,它帮你完成底层的CAN通信。

我的个人习惯:

初始化MCP2515时,我一般先复位,然后配置位时序(后面会讲),再配置验收滤波器和屏蔽寄存器。最后把CANCTRL寄存器里的REQOP位设为0x00,进入正常模式。顺序错了,芯片可能不工作。


4.3 SPI接口通信:MCU与MCP2515的「高速公路」

SPI,全称Serial Peripheral Interface。MCP2515支持SPI模式0,0(CPOL=0, CPHA=0),时钟频率最高10MHz。

我建议你实际项目中跑5MHz左右,留点余量。

SPI通信的基本流程:

  1. MCU拉低CS片选引脚
  2. 发送指令字节(读、写、位修改、复位等)
  3. 发送地址字节(寄存器地址)
  4. 发送或接收数据字节
  5. 拉高CS片选引脚

下面是一个典型的写寄存器代码示例:

// SPI写MCP2515寄存器
void MCP2515_WriteReg(uint8_t addr, uint8_t data) {
    CS_LOW();                     // 拉低片选
    SPI_TransferByte(0x02);       // 写指令
    SPI_TransferByte(addr);       // 寄存器地址
    SPI_TransferByte(data);       // 写入数据
    CS_HIGH();                    // 拉高片选
}

读操作类似,只是指令变成0x03。还有一个很实用的指令是「位修改」指令0x05,可以只修改某个寄存器的特定位,不用先读后写。这个我在调试滤波器配置时经常用。

我曾经遇到的坑:

SPI通信时,CS片选必须在整个传输过程中保持低电平。有一次我代码里在发送指令和地址之间不小心拉高了CS,结果MCP2515直接丢弃了后续数据。查了两天才发现这个时序问题。


4.4 数据采样率设置:位时序的「黄金分割」

采样率,其实就是CAN总线的波特率。对于黑匣子来说,最常见的设置是500kbps和250kbps。

但设置波特率不是简单写个数字。MCP2515内部有一个位时序逻辑,你需要配置三个参数:

  • BRP(波特率预分频器): 决定一个位时间的基本时间单元TQ
  • TSEG1(时间段1): 包含传播段和相位缓冲段1
  • TSEG2(时间段2): 相位缓冲段2
  • SJW(同步跳转宽度): 用于补偿时钟偏差

一个CAN位时间 = 1个同步段 + TSEG1 + TSEG2。

采样点位置 = (1 + TSEG1) / (1 + TSEG1 + TSEG2)。

我个人习惯把采样点设置在87.5%左右。为什么?因为总线信号在传输过程中会有延迟,采样点靠后一些,能采到更稳定的电平。

下面是一个500kbps的配置示例(假设MCU时钟16MHz):

// 500kbps配置,采样点87.5%
// 16MHz / (2 * (1+8+3)) = 500kbps
MCP2515_WriteReg(CNF1, 0x01);   // BRP=1, SJW=1
MCP2515_WriteReg(CNF2, 0x90);   // TSEG1=8, 采样点1次
MCP2515_WriteReg(CNF3, 0x02);   // TSEG2=3

采样率设置速查表(16MHz晶振):

波特率BRPTSEG1TSEG2SJW采样点
1Mbps087156.25%
500kbps183187.5%
250kbps383187.5%
125kbps783187.5%

避坑指南:

我曾经在一个项目中,两端的CAN节点用了不同的晶振(一个16MHz,一个8MHz)。结果同样的配置参数,两边采样点不一样,导致通信时好时坏。后来我统一了晶振频率,问题解决。所以,同一条总线上的节点,晶振最好一致。


4.5 知识体系总览

下面这张图,是我自己画的一个数据流框架图。你可以把它当作本章的「地图」:

CAN数据采集框架图 MCU SPI主机 数据解析/存储 SPI SCK/MOSI/MISO/CS MCP2515 CAN控制器 SPI从机 TXD RXD TJA1050 CAN收发器 差分信号转换 CANH CANL 120Ω 数据流向:MCU → SPI → MCP2515 → TX/RX → TJA1050 → CANH/CANL → 总线 接收方向:总线 → TJA1050 → RXD → MCP2515 → SPI → MCU 采样率设置关键:BRP + TSEG1 + TSEG2 推荐采样点:87.5%(兼顾抗干扰与通信稳定性)

4.6 实战小结

这一章的内容,说白了就是三件事:

  1. TJA1050负责物理层——把数字信号变成差分信号,或者反过来。
  2. MCP2515负责数据链路层——通过SPI接收MCU的指令,完成CAN协议的处理。
  3. 采样率设置——通过配置位时序寄存器,让所有节点在同一个节奏上工作。

我在实际项目中,最常遇到的问题就是采样点不匹配。两个节点波特率一样,但采样点不同,就会出现偶发性的丢帧。所以,我建议你在调试阶段,先用示波器抓一下CAN_H和CAN_L的波形,看看位时间是否准确。

嗯,这一章就到这里。内容不少,但都是干货。你把这些吃透了,CAN数据采集这块基本就稳了。


公众号:蓝海资料掘金营,微信deep3321