第4章:CAN控制器与收发器——SJA1000、MCP2515、TJA1050等常用芯片介绍,以及MCU集成CAN外设的使用
好,咱们进入第4章。这一章聊的是硬件——CAN控制器和收发器。说白了,就是CAN通信的“大脑”和“嘴巴”。
很多刚入行的朋友,一上来就对着SJA1000、MCP2515、TJA1050这些型号发懵。我当年也一样,看着数据手册里密密麻麻的寄存器,头都大了。但别怕,今天我把它们掰开揉碎了讲清楚。
4.1 CAN控制器 vs 收发器:谁干什么活?
先理清一个基本概念:CAN控制器和收发器是两码事。
- CAN控制器:负责协议层的处理。比如帧的封装、仲裁、错误检测、位时序等等。它把你要发的数据,变成符合CAN协议的“数字信号”。
- CAN收发器:负责物理层的转换。它把控制器输出的“数字信号”(通常是3.3V或5V的逻辑电平),转换成CAN总线上的“差分信号”(CAN_H和CAN_L)。反过来也一样。
你可以这么理解:控制器是“大脑”,收发器是“声带和耳朵”。大脑想好说什么,声带把它喊出去;耳朵听到声音,再传给大脑处理。
重要提醒: 在BMS项目中,控制器和收发器必须配对使用。选型时要注意电压匹配和速率匹配。
4.2 经典CAN控制器:SJA1000
SJA1000,这可是CAN控制器里的“老前辈”了。它是NXP(原Philips)的产品,支持CAN 2.0B协议,也就是标准帧和扩展帧都支持。
我个人习惯,在早期的教学板或者一些工业控制卡上,经常能看到它的身影。它有两种工作模式:BasicCAN模式和PeliCAN模式。
- BasicCAN模式:兼容老旧的82C200,功能有限,只支持标准帧,发送缓冲区只有1个。
- PeliCAN模式:这才是SJA1000的完全体。支持标准帧和扩展帧,发送缓冲区有64字节的FIFO,还支持单次发送、自接收等功能。
避坑指南: 我曾经在一个项目中,发现SJA1000怎么都发不出数据。查了半天,原来是复位后默认进入了BasicCAN模式,而我配置的是扩展帧。记住,初始化时一定要切换到PeliCAN模式。
SJA1000的典型电路连接,一般需要外接一个晶振(通常是16MHz或24MHz),然后通过地址/数据总线与MCU相连。它的寄存器是8位的,操作起来比较直接。
// SJA1000 PeliCAN模式初始化示例(伪代码)
void SJA1000_Init(void) {
// 1. 进入复位模式
SJA1000_WriteReg(MOD, 0x01); // MOD.0 = 1, 进入复位模式
// 2. 配置时钟分频寄存器
SJA1000_WriteReg(CDR, 0x88); // 关闭CLKOUT, 选择PeliCAN模式
// 3. 配置验收滤波器(这里设置为接收所有帧)
SJA1000_WriteReg(ACR0, 0x00);
SJA1000_WriteReg(ACR1, 0x00);
SJA1000_WriteReg(ACR2, 0x00);
SJA1000_WriteReg(ACR3, 0x00);
SJA1000_WriteReg(AMR0, 0xFF);
SJA1000_WriteReg(AMR1, 0xFF);
SJA1000_WriteReg(AMR2, 0xFF);
SJA1000_WriteReg(AMR3, 0xFF);
// 4. 配置位时序(假设16MHz晶振,500kbps)
SJA1000_WriteReg(BTR0, 0x00); // SJW = 1, BRP = 1
SJA1000_WriteReg(BTR1, 0x1C); // TSEG1 = 14, TSEG2 = 3, SAM = 1
// 5. 退出复位模式,进入工作模式
SJA1000_WriteReg(MOD, 0x00);
}
4.3 独立CAN控制器:MCP2515
MCP2515是Microchip的产品。它和SJA1000最大的区别是:它通过SPI接口与MCU通信。这意味着,只要你的MCU有SPI接口,就能轻松扩展出一路CAN。
这在BMS项目中特别实用。你想想看,有些MCU本身不带CAN外设,或者CAN通道数不够用。这时候,挂一个MCP2515,问题就解决了。
MCP2515内部集成了3个发送缓冲器和2个接收缓冲器,还支持接收过滤和屏蔽。它的配置是通过SPI读写内部寄存器来实现的。
我的经验: MCP2515的SPI时钟频率最高可以到10MHz,但实际项目中,我建议不要跑满。留点余量,抗干扰能力会好很多。我一般设置在5MHz左右。
// MCP2515 SPI写寄存器示例
void MCP2515_WriteReg(uint8_t addr, uint8_t data) {
// 片选拉低
CS_LOW();
// 发送写指令
SPI_Transmit(0x02); // 写寄存器指令
SPI_Transmit(addr); // 寄存器地址
SPI_Transmit(data); // 要写入的数据
// 片选拉高
CS_HIGH();
}
4.4 常用CAN收发器:TJA1050
收发器这块,TJA1050是绝对的经典。它是NXP的产品,是TJA1040的升级版。它支持高达1Mbps的通信速率,而且电磁辐射(EME)很低。
为什么BMS里喜欢用TJA1050?因为它有一个很重要的特性:总线引脚上电时无源。这意味着,在系统上电或下电过程中,TJA1050不会对CAN总线造成干扰。这对于多节点、且节点可能随时上下电的BMS系统来说,太关键了。
TJA1050的引脚也很简单:
- TXD:发送数据输入(接控制器TXD)
- RXD:接收数据输出(接控制器RXD)
- CANH:CAN高电平总线
- CANL:CAN低电平总线
- VCC:电源(5V)
- GND:地
- RS:斜率控制/待机模式
RS引脚很有意思。把它接地,就是高速模式;接高电平,就进入待机模式;串一个电阻到地,可以控制上升/下降斜率,减少电磁干扰。
注意: TJA1050的VCC是5V。如果你的控制器是3.3V的,比如某些STM32,就需要做电平转换。或者直接选用3.3V的收发器,比如SN65HVD230。
4.5 MCU集成CAN外设:以STM32为例
现在很多MCU都集成了CAN外设,比如STM32的bxCAN(Basic Extended CAN)。这省去了外挂独立控制器的麻烦,也降低了BOM成本。
STM32的bxCAN支持CAN 2.0B,有3个发送邮箱和2个接收FIFO(每个FIFO有3个邮箱)。它还支持硬件过滤,可以大大减轻CPU的负担。
使用集成CAN外设,配置起来比独立控制器简单多了。主要就是配置GPIO、初始化CAN参数、然后配置过滤器。
// STM32 HAL库 CAN初始化示例
void MX_CAN1_Init(void) {
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 6; // 分频系数
hcan1.Init.Mode = CAN_MODE_NORMAL; // 正常模式
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_13TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = ENABLE; // 自动重发
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK) {
Error_Handler();
}
}
你看,代码量比SJA1000少了很多。而且HAL库把底层的寄存器操作都封装好了,我们只需要关心配置参数就行。
4.6 选型建议:BMS项目怎么选?
说了这么多,到底怎么选?我根据项目经验,给几个建议:
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| MCU自带CAN外设 | MCU集成CAN + TJA1050 | 成本低、体积小、配置简单 |
| MCU无CAN外设,需扩展1路 | MCP2515 + TJA1050 | SPI接口通用,灵活 |
| 需要多路CAN(2路以上) | MCP2515 × N + TJA1050 × N | 扩展方便,不受MCU限制 |
| 对实时性要求极高 | MCU集成CAN(如STM32 bxCAN) | 硬件处理,延迟低 |
| 老旧项目维护 | SJA1000 + TJA1050 | 兼容原有设计 |
核心建议: 新设计的BMS项目,我强烈推荐使用MCU集成CAN外设的方案。比如STM32F4或G4系列,自带多路CAN,性能足够,开发也快。除非你遇到的是MCU选型已经定了,没有CAN接口,才考虑外挂MCP2515。
好了,这一章的内容就到这。CAN控制器和收发器是硬件基础,选对了,后面的软件工作就顺了。下一章,我们聊聊CAN报文的结构和解析,那才是真正开始“对话”了。