三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

STM32 CAN通信协议详解(一)

STM32 CAN通信协议详解(一)

目录

  • 引言
  • 一、CAN的应用
    • 1. 为什么车载用CAN?
    • 2. CAN连接示意
    • 3. CAN物理层特性
      • 3.1 抗干扰
      • 3.2 CAN总线电平逻辑
      • 3.3 终端电阻
    • 4. CAN内部结构
      • 4.1 发送邮箱(X Mailbox)
      • 4.2 接收FIFO
      • 4.3 过滤器(Filter)
      • 4.4 回环模式(LoopBack)
      • 4.5 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+CS2(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)RXFIFO(x2)│ │ └──────────┬───────────┘ ▼ CAN收发器 ▼ CAN总线

    操作CAN实际是在操作这3部分:

    发送邮箱 接收FIFO 过滤器
4.1 发送邮箱(X Mailbox)
  1. 在前面时候,类似USRAT发送:

    USART_SendData();直接发进寄存器;

    CAN不同,因为数据量大:

    ​ 可能很多帧等待发送

    ​ 所以CAN内部有缓存

  2. STM32中提供3个发送邮箱:

    Mailbox0 Mailbox1 Mailbox2 每个邮箱都能存1帧数据
    • 假设CPU发送:

      Frame1 Frame2 Frame3

      则:

      Mailbox0->Frame1 Mailbox1->Frame2 Mailbox2->Frame3

      然后CAN控制器自己决定:

      谁先发 谁后发
4.2 接收FIF0
  1. 接收与发送不同

总线:

ECU1发送 ECU2发送 ECU3发送 都可能收到

如果CPU来不及处理–数据会丢失
所以CAN内部提供:

FIFO0 FIFO1

两个接收队列;

  1. FIFO:

    First In First Out–先进先出

例如:收到3帧:

Frame1 Frame2 Frame3

存储:

FIFO ┌───────┐ │Frame1 │ ├───────┤ │Frame2 │ ├───────┤ │Frame3 │ └───────┘

CPU读取:

先读Frame1 再读Frame2 再读Frame3
  1. 两个FIFO的作用:方便管理
    可以对接收到的数据进行分类

例如:

发动机数据:0x1000x1010x102放: FIFO0 诊断数据:0x7000x701放: FIFO1
4.3 过滤器(Filter)
  1. 不需要的数据直接丢弃:

CAN是广播
总线上:

发动机转速 车速 ABS状态 空调状态 电池电压 电池温度 GPS数据...

可能上千条消息;
而对应ECU只关心:

电池电压

如果全部接收,过于消耗CPU;

所以CAN提供–过滤器:

不需要的数据直接丢弃; 需要的数据进进入--FIFO
  1. 过滤器工作位置 – 硬件执行

    总线 ↓ Filter ↓ FIFO ↓ CPU
  2. 过滤器模式:

    掩码模式--Mask Mode--全部接收 列表模式--List Mode--直接指定ID
    • 掩码模式–Mask Mode–全部接收

      例如: ID=0X100~0X1FF全部接收; 通过: ID+MASK 实现if((ID&MASK)==TARGET){接收}
    • 列表模式–List Mode–直接指定ID

      例如:0x1000x1230x5550x777接收 其他全部拒绝
  3. 14组过滤器,每一组都有

    FR1 FR2 两个32位寄存器
4.4 回环模式(LoopBack)

回环模式 即:

通过CAN发送Frame 直接返回自己的接收模块: TX ↓ CAN内部 ↓ RX
4.5 CAN波特率:

常用:

125K250K500K1M

汽车中常见:

500kbps

新能源:

500kbps1Mbps

CAN传输中所有节点波特率必须一致

← 返回列表