STM32 CAN通信协议详解(一)
·
目录
一、 CAN的应用
1.为什么车载用CAN?
USART的问题:
① 一对一通信,不能多设备共用总线
一个USART只能接一个设备
车上几十个ECU,不可能每个都拉一对TX/RX
② 没有错误检测机制
数据被干扰了,收发双方都不知道
车上电磁干扰大,数据出错率比桌面上高得多
③ 没有优先级机制
紧急数据(刹车信号)和普通数据(车窗位置)
在同一个总线上没有优先级区分
SPI的问题:
① 线太多(4根+每设备一根CS)
车门里面没有空间拉这么多线
② 距离短(一般不超过30cm)
车上ECU分布在车头到车尾,距离几米到十几米
③ 没有多主机能力
不能两个ECU同时往总线上发数据
所以引入CAN:
车上需要这种通信系统:
① 所有ECU共用两根线(CANH/CANL)
—— 代替USART的一对一和SPI的多CS
② 任何ECU都可以随时发消息
—— 多主机,不需要主机轮询
③ 紧急消息优先发送
—— 刹车信号必须比车窗信号先发
④ 有完整的错误检测和重发机制
—— 数据错了能发现、能重发
⑤ 距离远(最长40m@1Mbps)
—— 满足车身长度需求
CAN全部做到了。
- CAN 与 USART SPI对比
对比项 USART SPI CAN
──────────────────────────────────────────────────────────
线数 2(TX/RX) 4+CS 2(CANH/CANL)
距离 几米 几十厘米 最长40米
速度 115200~921600 几MHz~几十MHz 最高1Mbps
(低速CAN到125kbps)
多设备 不支持 支持(需CS线) 支持(无CS线)
多主机 不支持 困难 原生支持
优先级 无 无 有(ID仲裁)
错误检测 无(只有奇偶校验) 无 有(CRC+ACK+位填充)
数据量 任意 任意 一帧最多8字节
(CAN FD最多64字节)
每帧固定格式 起始+数据+停止 无固定格式 SOF+ID+控制+数据+CRC+ACK+EOF
2. CAN连接示意
-
车载网络中:
发动机ECU ──┐ │ 变速箱ECU ──┤ │ ABS/ESP ───┼──── CANH ────┐ │ │ ┌───── 车窗ECU 车身BCM ───┤ ├─────────┤ │ │ └───── 车门ECU 气囊ECU ───┤ CANL ────┘ │ 仪表盘 ───┘ 所有ECU都挂在同一对CANH/CANL上 任何ECU都能发消息 任何ECU都能收到所有消息(但不一定处理) -
STM32连接到CAN总线:
STM32不能直接连CAN总线——需要CAN收发器。 CAN收发器 STM32 ┌──────────┐ CAN_TX ─┤ TX CANH├─── CANH │ │ CAN_RX ─┤ RX CANL├─── CANL │ │ └──────────┘ VCC=3.3V GND 常用CAN收发器芯片: TJA1050(5V供电,推荐) SN65HVD230(3.3V供电) TJA1040(带待机模式) STM32F103C8T6的CAN引脚: CAN1_RX = PA11 CAN1_TX = PA12
3. CAN物理层特性:
3.1 抗干扰
-
USART用一根TX线传输,SPI用一根MOSI线传输。CAN为什么用两根?因为抗干扰。
车上环境: 发动机点火线圈产生的高压脉冲 电机驱动产生的大电流突变 继电器吸合产生的电弧 这些都会在导线上感应出噪声电压 单端传输(USART/SPI): TX对GND的电压:0V或3.3V 如果干扰在线上感应了+2V噪声 你发3.3V,对方收到5.3V 你发0V,对方收到2V(可能被误判为1) 数据就错了差分传输(CAN): CANH和CANL两根线一起传 CANH - CANL 的差值代表数据 如果两根线同时被感应了+2V噪声 (CANH+2) - (CANL+2) = CANH - CANL 差值不变,数据不受影响
3.2 CAN总线电平逻辑
CAN总线的两种状态:
显性(Dominant):
CANH = 3.5V
CANL = 1.5V
差分电压 = 3.5 - 1.5 = 2.0V
逻辑值 = 0
为什么叫"显性"?
只要有一个ECU输出显性,总线就是显性
多个ECU同时输出时,显性覆盖隐性
隐性(Recessive):
CANH = 2.5V
CANL = 2.5V
差分电压 = 2.5 - 2.5 = 0V
逻辑值 = 1
为什么叫"隐性"?
所有ECU都输出隐性时,总线才是隐性
有一个ECU输出显性,总线就被拉成显性
- 显性–差分电压有值–逻辑为0;
- 隐性–差分电压为0–逻辑为1;
-
"线与"特性——和I2C的开漏类似:
多个ECU同时发送: 如果ECU_A发显性(0),ECU_B发隐性(1) 总线结果是显性(0) 因为显性驱动能力强(推挽),隐性靠电阻(类似上拉) 这就是CAN仲裁的物理基础
CAN控制器通过显性隐性机制实现无损仲裁:显性压倒隐性
例如:
发动机ECU : ID = 0X100 发送
ABS ECU : ID = 0X080 发送
两个同时发送,CAN 不会冲突,会自动仲裁:
规则: ID越小优先级越高;
所以ABS先发,发动机停止发送等待下一次(是等待,不是重发)
3.3 终端电阻
CAN总线两端必须各接一个120Ω电阻:
┌──────┐ ┌──────┐
│ ECU1 │──── CANH ────│ ECU2 │
│ │ 120Ω 120Ω │ │
│ │──── CANL ────│ │
└──────┘ └──────┘
为什么需要终端电阻?
防止信号反射
CAN总线上的信号频率高(最高1Mbps)
如果总线末端不匹配阻抗
信号会反射回来,和原始信号叠加
导致数据错误
为什么是120Ω?
CAN总线设计时定义的特性阻抗就是120Ω
汽车维修中经常遇到的故障就是"终端电阻丢失"
表现为CAN通信时好时坏
-
CAN总线:
120Ω │ CAN_H │ │ ECU1 │ ECU2 │ ECU3 │ CAN_L │ 120Ω
4. CAN内部结构
-
STM32F103内部CAN框图:
┌───────────┐ │ CPU │ └─────┬─────┘ │ ┌────────▼────────┐ │ bxCAN │ └───────┬─────────┘ │ ┌──────────┼──────────┐ │ │ │ ▼ ▼ ▼ TX邮箱(x3) Filter(14) RX FIFO(x2) │ │ └──────────┬───────────┘ ▼ CAN收发器 ▼ CAN总线操作CAN实际是在操作这3部分:
发送邮箱 接收FIFO 过滤器
4.1 发送邮箱(X Mailbox)
-
在前面时候,类似USRAT发送:
USART_SendData(); 直接发进寄存器;CAN不同,因为数据量大:
可能很多帧等待发送
所以CAN内部有缓存
-
STM32中提供3个发送邮箱:
Mailbox0 Mailbox1 Mailbox2 每个邮箱都能存1帧数据-
假设CPU发送:
Frame1 Frame2 Frame3则:
Mailbox0 -> Frame1 Mailbox1 -> Frame2 Mailbox2 -> Frame3然后CAN控制器自己决定:
谁先发 谁后发
-
4.2 接收FIF0
- 接收与发送不同
总线:
ECU1发送
ECU2发送
ECU3发送
都可能收到
如果CPU来不及处理–数据会丢失
所以CAN内部提供:
FIFO0
FIFO1
两个接收队列;
-
FIFO:
First In First Out–先进先出
例如:收到3帧:
Frame1
Frame2
Frame3
存储:
FIFO
┌───────┐
│Frame1 │
├───────┤
│Frame2 │
├───────┤
│Frame3 │
└───────┘
CPU读取:
先读Frame1
再读Frame2
再读Frame3
- 两个FIFO的作用:方便管理
可以对接收到的数据进行分类
例如:
发动机数据:
0x100
0x101
0x102
放:
FIFO0
诊断数据:
0x700
0x701
放:
FIFO1
4.3 过滤器(Filter)
- 不需要的数据直接丢弃:
CAN是广播
总线上:
发动机转速
车速
ABS状态
空调状态
电池电压
电池温度
GPS数据
...
可能上千条消息;
而对应ECU只关心:
电池电压
如果全部接收,过于消耗CPU;
所以CAN提供–过滤器:
不需要的数据直接丢弃;
需要的数据进进入--FIFO
-
过滤器工作位置 – 硬件执行
总线 ↓ Filter ↓ FIFO ↓ CPU -
过滤器模式:
掩码模式--Mask Mode--全部接收 列表模式--List Mode--直接指定ID-
掩码模式–Mask Mode–全部接收
例如: ID=0X100~0X1FF 全部接收; 通过: ID + MASK 实现 if((ID & MASK)==TARGET) { 接收 } -
列表模式–List Mode–直接指定ID
例如: 0x100 0x123 0x555 0x777 接收 其他全部拒绝
-
-
14组过滤器,每一组都有
FR1 FR2 两个32位寄存器
4.4 回环模式(LoopBack)
回环模式 即:
通过CAN发送Frame
直接返回自己的接收模块:
TX
↓
CAN内部
↓
RX
4.5 CAN波特率:
常用:
125K
250K
500K
1M
汽车中常见:
500kbps
新能源:
500kbps
1Mbps
CAN传输中所有节点波特率必须一致
更多推荐



所有评论(0)