CAN FD扩展帧

一、CAN FD扩展帧是什么?

1.1 标准帧 vs 扩展帧

特性 标准帧 扩展帧
ID位数 11位 29位
ID范围 0x000 ~ 0x7FF 0x00000000 ~ 0x1FFFFFFF
节点容量 最多2048个 最多5.36亿
应用场景 小型网络 大型复杂系统

扩展帧的29位ID为大型网络提供了海量的地址空间,是CAN FD的强大特性之一。

1.2 CAN FD vs 传统CAN

复制代码
传统CAN 2.0:
┌──────┬──────────┬──────┬─────┐
│ ID   │ DLC(≤8)  │ Data │ CRC │
│ 11/29│  4bit    │ 0-8B │15bit│
└──────┴──────────┴──────┴─────┘

CAN FD:
┌──────┬──────────┬──────┬───────┬─────┐
│ ID   │ DLC(≤64) │ Data │ Stuff │ CRC │
│ 11/29│  4bit    │0-64B │ Count │17/21│
└──────┴──────────┴──────┴───────┴─────┘
         ↑
    可指示最多64字节数据!

核心优势

  • 数据段速率可达8Mbps(传统CAN仅1Mbps)

  • 单帧最大64字节(传统CAN仅8字节)

  • 硬件CRC校验,无需软件组帧


二、扩展帧ID的位域设计

2.1 为什么需要自定义ID结构?

CAN FD的29位ID不仅仅是"地址",更是协议的载体。通过位域划分,可以在ID中编码丰富的语义信息。

2.2 实际案例:机器人关节控制协议

以下是一个真实项目的ID编码方案:

复制代码
/* 29位扩展ID的位域分配 */
#define CAN_DEV_ID_NUM       (7u)    // 设备ID:7位,0-127
#define CAN_DEV_ID_SHIFT     (0u)

#define CAN_PRODUCT_ID_NUM   (7u)    // 产品ID:7位
#define CAN_PRODUCT_ID_SHIFT (7u)    // 注意:从bit7开始!

#define CAN_RW_NUM           (1u)    // 读写标志:1位
#define CAN_RW_SHIFT         (14u)   // 0=读,1=写

#define CAN_REG_NUM          (8u)    // 寄存器号:8位
#define CAN_REG_SHIFT        (15u)

#define CAN_REG_ADD_NUM      (5u)    // 子地址:5位
#define CAN_REG_ADD_SHIFT    (23u)

// 广播地址
#define CAN_BROADCAST_DEV_ID (0u)

ID布局可视化

复制代码
Bit: 28 ...... 24 | 23 ...... 15 | 14 | 13 ...... 7 | 6 ...... 0
     [子地址 5位]   [寄存器 8位]  [R/W] [产品ID 7位] [设备ID 7位]

三、关键认知:ID里存的是源地址!

3.1 CAN总线的寻址哲学

这是初学者最容易混淆的地方:

总线类型 寻址方式 ID含义
I2C/SPI 目标寻址 我要跟谁通信
CAN 源地址广播 我是谁

3.2 为什么这样设计?

CAN总线是广播式通信,所有节点同时监听总线。发送方报出自己身份,接收方根据"谁发的"来决定是否处理。

复制代码
// 发送时:填写自己的ID
uint32_t u32_id = pack_id(MY_PRODUCT_ID, MY_DEV_ID, rw, reg, reg_add);

// 接收时:判断发送方是谁
if(u8_dev_id == MASTER_ID || u8_dev_id == BROADCAST_ID) {
    // 来自主控或广播,处理
}

3.3 目标地址放哪里?

如果需要点对点通信,目标地址放在数据区

复制代码
// 发送给设备5
uint8_t au8_data[64];
au8_data[0] = 0x05;  // 目标设备ID
// ... 其他数据

四、硬件过滤器的正确配置

4.1 过滤的是什么?

过滤的是"发送方ID",不是"目标地址"!

复制代码
// 错误理解:过滤"发给我的帧"
// 正确理解:过滤"我关心的发送方发的帧"

// 示例:只接收来自主控(0x01)和广播(0x00)的帧
uint32_t u32_master_id = pack_id(PRODUCT_ID, 0x01, 0, 0, 0);
uint32_t u32_broadcast_id = pack_id(PRODUCT_ID, 0x00, 0, 0, 0);

st_filter.FilterID1 = u32_master_id;
st_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;

4.2 多FDCAN外设的过滤器配置陷阱

问题现象:FDCAN1收不到数据,FDCAN2正常。

根本原因 :多个FDCAN外设共享同一个过滤器RAM,FilterIndex冲突导致覆盖。

复制代码
// ❌ 错误:两个外设使用相同的FilterIndex
// bsp_fdcan1_init()
st_filter.FilterIndex = 0;  // 被覆盖!
st_filter.FilterIndex = 1;  // 被覆盖!

// bsp_fdcan2_init()
st_filter.FilterIndex = 0;  // 覆盖了CAN1的配置
st_filter.FilterIndex = 1;  // 覆盖了CAN1的配置

✅ 正确方案1:错开FilterIndex

c

复制代码
// FDCAN1使用0~1
st_filter.FilterIndex = 0;
st_filter.FilterIndex = 1;

// FDCAN2使用2~3
st_filter.FilterIndex = 2;
st_filter.FilterIndex = 3;

✅ 正确方案2:使用全局过滤器(推荐)

复制代码
// FDCAN1:所有扩展帧进FIFO0
HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,
    FDCAN_REJECT, FDCAN_REJECT,
    FDCAN_FILTER_TO_RXFIFO0,  // 扩展数据帧
    FDCAN_FILTER_TO_RXFIFO0); // 扩展远程帧

// FDCAN2:所有扩展帧进FIFO1
HAL_FDCAN_ConfigGlobalFilter(&hfdcan2,
    FDCAN_REJECT, FDCAN_REJECT,
    FDCAN_FILTER_TO_RXFIFO1,
    FDCAN_FILTER_TO_RXFIFO1);
相关推荐
网络研究院16 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展
酣大智16 天前
ARP代理--工作原理
运维·网络·arp·arp代理
treesforest16 天前
AI安全系统如何识别异常访问?IP风险识别正在成为关键能力
网络·人工智能·tcp/ip·安全·web安全
shushangyun_16 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
2601_9618451516 天前
粉笔行测题库|系统班|刷题
网络·百度·微信·微信公众平台·facebook·新浪微博
程序猿阿伟16 天前
《Chrome离线扩展安装的底层逻辑与场景落地指南》
服务器·网络·chrome
InHand云飞小白16 天前
无人值守站点网络困境?工业级路由器IR315破解连接难题
网络·物联网·4g·工业路由器·4g路由器·iiot·蜂窝路由器
森G16 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt
江华森16 天前
TCP/IP 协议栈实战 — 7 个实验详解
网络·tcp/ip·智能路由器
酉鬼女又兒16 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php