第4章 车机CAN硬件接口:CAN控制器芯片、CAN收发器、SPI/UART接口通信

好,咱们今天聊点硬核的。车机要跟CAN总线打交道,光有软件协议栈可不够,你得先搞定硬件接口。说白了,就是让Android系统能“摸到”CAN总线上的信号。

我刚开始做车机项目时,也踩过不少坑。比如选错了收发器,结果通信距离一长就丢包。或者SPI时钟没配好,控制器死活不响应。嗯,这些今天咱们都聊透。

4.1 CAN控制器芯片:MCP2515与SJA1000

CAN控制器,负责把CPU发来的数据,打包成CAN帧,再通过收发器发出去。反过来也一样,它负责解析总线上的帧。

市面上常见的独立CAN控制器,我接触最多的就是Microchip的MCP2515和NXP的SJA1000。两者定位不同,选型时要注意。

特性 MCP2515 SJA1000
接口 SPI(最高10MHz) 并行/复用地址总线
供电 2.7V - 5.5V 5V
CAN标准 CAN 2.0B CAN 2.0B + BasicCAN
接收缓冲 2个接收缓冲 + 3个发送缓冲 64字节FIFO
典型应用 嵌入式Linux/Android SPI外设 工业控制、传统MCU

MCP2515 是我个人最推荐在车机上用的。为什么?因为它走SPI接口。Android主板(比如RK3399、i.MX8)通常有丰富的SPI引脚,直接连上就能用。而且它内部有独立的时钟振荡器,不需要外部晶振,省事。

我在项目中遇到过一个问题:MCP2515的SPI时钟频率不能设太高。手册说最高10MHz,但实际在长线缆下,5MHz以上就容易出现CRC错误。我后来统一降到4MHz,稳得很。

关键点:MCP2515的SPI模式必须配置为模式0(CPOL=0, CPHA=0)。很多新手上来就配成模式3,结果通信失败。我当年也犯过这个错。

SJA1000 呢?它是个老将了。并行接口,速度更快,但占用GPIO多。在车机上,除非你用的是FPGA或者大容量MCU,否则我不建议用。它需要外部晶振,而且供电必须5V,跟现在主流的3.3V系统不搭。

不过SJA1000有个优点:它的PeliCAN模式支持更多错误诊断功能。如果你在做车载诊断仪,可以考虑它。

4.2 CAN收发器:TJA1050与SN65HVD230

控制器负责逻辑,收发器负责物理。它把控制器的差分信号,转换成CAN总线上的CAN_H和CAN_L电平。

收发器选型,核心看三点:供电电压、速率、共模电压范围。

型号 供电 速率 共模范围 特点
TJA1050 5V 最高1Mbps -2V ~ +7V 低功耗、待机模式
SN65HVD230 3.3V 最高1Mbps -2V ~ +7V 3.3V供电、低EMI

TJA1050 是经典款。5V供电,跟MCP2515搭配很常见。它有个待机模式,通过STB引脚控制。车机休眠时,可以拉高STB让收发器进入低功耗状态。我建议你在设计时,把STB引脚接到一个GPIO上,方便软件控制。

我曾经遇到一个坑:TJA1050的CANH和CANL引脚,如果接反了,整个总线都会瘫痪。而且它没有反接保护。所以布线时一定要仔细核对。

SN65HVD230 是3.3V系统的福音。现在很多车机主控都是3.3V IO,用这个收发器可以直接匹配,省去电平转换。它的EMI性能也不错,适合对电磁干扰敏感的车载环境。

我的经验:如果车机供电是12V系统,建议在CANH和CANL上各串一个100Ω电阻,再并一个120Ω终端电阻。这样能有效抑制反射。我有个项目,不加电阻时,总线长度超过5米就丢包,加上后稳如老狗。

4.3 SPI/UART接口通信

控制器和收发器选好了,接下来就是怎么跟Android主控通信。常见的有两种:SPI和UART。

4.3.1 SPI接口

SPI是同步串行接口,速度快,适合大数据量传输。MCP2515就是走SPI的。

SPI通信的典型接线:

Android主控 (SPI Master)    MCP2515 (SPI Slave)
SCLK  -------------------->  SCK
MOSI  -------------------->  SI
MISO  <--------------------  SO
CS    -------------------->  CS
INT   <--------------------  INT

注意那个INT引脚。MCP2515收到CAN帧后,会拉低INT引脚,通知主控来读。我建议把这个引脚接到Android主控的一个GPIO中断上,这样能及时响应。

SPI通信的速率,我前面说了,别贪快。4MHz是个安全值。另外,SPI的片选CS一定要用GPIO控制,不要用硬件自动片选。因为MCP2515的片选时序有特殊要求:CS拉低后,必须等待至少一个SPI时钟周期才能开始传输数据。

警告:SPI总线上的走线不要太长。如果超过10cm,建议加33Ω串联电阻抑制振铃。我见过一个项目,SPI线走了20cm,结果MCP2515经常无响应。剪短到5cm后,问题消失。

4.3.2 UART接口

UART是异步串行接口,简单,但速度慢。有些CAN控制器(比如某些集成CAN的MCU)会通过UART透传CAN数据。

UART通信的典型接线:

Android主控 (UART)          CAN控制器 (UART)
TX  --------------------->  RX
RX  <---------------------  TX
GND --------------------->  GND

UART的波特率,我建议用115200或更高。如果数据量不大,9600也能用。但要注意,UART没有硬件流控,所以数据包要加帧头帧尾,防止粘包。

我有个项目,用UART接一个CAN转串口模块。一开始没加校验,结果偶尔出现乱码。后来在数据包末尾加了CRC16,问题解决。嗯,UART通信一定要加校验。

4.4 硬件设计避坑指南

最后,我总结几个实战中容易踩的坑:

  • 电源滤波:CAN收发器的VCC引脚,一定要加100nF去耦电容。我见过不加电容的板子,总线上一有干扰,收发器就重启。
  • 终端电阻:CAN总线两端必须各有一个120Ω电阻。如果车机是总线的一端,就在板子上焊一个。否则信号反射会导致通信失败。
  • 共模扼流圈:在CANH和CANL上串一个共模扼流圈,能有效抑制共模干扰。我建议选TDK的ACT45B系列,效果不错。
  • ESD保护:CAN总线是暴露在车外的,容易受静电冲击。在CANH和CANL对地各加一个TVS管,比如PESD1CAN。我曾经因为没加TVS,一个雷雨天烧了三块板子。

一句话总结:CAN硬件接口,选对芯片、配好电源、加好保护,剩下的就是软件的事了。但硬件一旦出问题,软件再牛也救不回来。所以,硬件设计上多花点心思,绝对值得。

好,这一章就到这。下一章咱们聊聊怎么在Android上写CAN驱动,让系统真正跑起来。