【CP-06】CAN通信实战 - 从Frame到Signal的全流程【CP-06】CAN通信实战 - 从Frame到Signal的全流程【CP-06】CAN通信实战 - 从Frame到Signal的全流程前言在汽车电子系统中,CAN(Controller Area Network)总线是应用最广泛的通信协议之一。从车身BCM控制模块到动力总成ECM,从网关GW到智能座舱,CAN总线承载着整车超过70%的实时数据交互。在前几篇文章中,我们已经了解了AUTOSAR CP的整体架构(CP-02)、BSW通信栈模块(CP-03)、OS任务调度(CP-04)和RTE运行时环境(CP-05)。本文将深入剖析CAN通信在AUTOSAR架构中的完整数据流:从应用层的Signal(信号)如何打包成Frame(帧),穿越COM、PDURouter、CanIf、CanDriver各层,最终到达CAN总线的物理层;以及反向从CAN总线接收的Frame如何解析成应用层可用的Signal。理解这一完整流程,是掌握AUTOSAR通信栈、进行故障诊断和性能优化的基础。一、通信架构全景1.1 CAN通信栈层次结构在AUTOSAR分层架构中,CAN通信涉及以下模块层次:┌─────────────────────────────────────────────────────────────────┐ │ Application Layer (ASW) │ │ Software Components (SW-C) │ │ Signal-based Interface (发送/接收) │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ Runtime Environment (RTE) │ │ Signal Routing Port Interface │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ AUTOSAR COM Module │ │ Signal Packing/Unpacking │ Byte Order │ TM Selection │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ PDU Router │ │ I-PDU Routing │ Gateway │ TP │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ CAN Interface (CanIf) │ │ Tx Buffering │ Rx Filtering │ Controller Mode │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ CAN Driver (Can) │ │ Hardware Access │ ISR │ State Machine │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ Microcontroller Abstraction Layer (MCAL) │ │ CAN Controller Registers │ Hardware │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌───────────────┐ │ CAN Transceiver │ │ Physical Layer │ └───────────────┘ │ ═══════╪════════ CAN Bus1.2 关键概念辨析在深入学习之前,必须明确以下概念:概念定义在CAN通信中的角色Signal应用层的数据元素,代表一个物理量或逻辑值发送方:温度值、车速;接收方:期望收到的数据I-PDUInteraction Layer Protocol Data Unit,交互层协议数据单元COM模块处理的数据单元,可包含多个SignalL-PDUData Link Layer Protocol Data Unit,数据链路层协议数据单元CanIf/Can处理的帧数据,包含ID+DataFrameCAN总线上传输的完整数据帧物理层概念,包含SOF、ID、DLC、Data、CRC等Hardware ObjectCAN控制器内部的硬件缓冲区发送HOB和接收HRH/HRH1.3 Frame与Signal的映射关系一个CAN Frame可以承载多个Signal,这称为信号打包(Signal Packing):┌────────────────────────────────────────────────────────────────┐ │ CAN 2.0 Standard Frame │ │ ┌──────────┬─────────┬───────┬───────────────────────────┐ │ │ │ ID │ DLC │ Data Field (up to 8 bytes) │ │ │ │ 11 bits │ 4 bits │ │ │ │ └──────────┴─────────┴───────┴───────────────────────────┘ │ │ │ │ Example: EngineData (ID=0x100) │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ Byte 0 │ Byte 1-2 │ Byte 3 │ Byte 4-5 │ Byte 6 │ │ │ │ EngSpd[0] │ EngSpd[1] │ Gear │ Trq[0] │ Trq[1] │ │ │ │ (8bit) │ (16bit) │ (8bit) │ (16bit) │ (8bit) │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ 可以看到:1个Frame(ID=0x100) 包含 4个Signal │ └────────────────────────────────────────────────────────────────┘二、CAN协议基础2.1 CAN 2.0标准帧格式┌─────┬────────┬─────┬────────┬───────┬────┬──────┬─────┬────┐ │ SOF │ ID │ RTR │ Ctrl │ Data │ CRC │ ACK │ EOF │ IFS│ │ 1 │ 11bits │ 1 │ 2bits │ 0-8B │ 15 │ 2 │ 7 │ 3 │ └─────┴────────┴─────┴───────┴───────┴────┴──────┴─────┴────┘字段说明:字段长度说明SOF1bit帧起始位,显性电平(0)ID11bits标识符,数值越小优先级越高RTR1bit远程传输请求,0=数据帧,1=远程帧IDE1bit标识符扩展位,0=标准帧DLC4bits数据长度码,表示Data字节数(0-8)Data0-8B数据负载CRC15bits循环冗余校验ACK2bits应答位EOF7bits帧结束2.2 CAN FD协议特性CAN FD(Flexible Data-rate)在AUTOSAR R4.2之后得到支持:特性CAN 2.0CAN FDID长度11bits标准/29bits扩展相同数据长度0-8字节0-64字节波特率最高1Mbps数据段最高8Mbps帧格式固定可变比特率┌─────┬────────┬─────┬─────┬─────┬────────┬──────────┬────┬──────┬─────┬────┐ │ SOF │ ID │ RTR │ IDE │ FDF │ BRS │ DLC │Data│ CRC │ ACK │EOF│ │ 1 │ 11bits │ 1 │ 1 │ 1 │ 1 │ 4bits │64B │ 17/21 │ 2 │7 │ └─────┴────────┴─────┴─────┴─────┴──────┴──────────┴────┴──────┴─────┴────┘关键新增字段: -FDF(FD Frame): 1=CAN FD帧 -BRS(Bit Rate Switch): 1=切换到高速率 -ESI(Error State Indicator): 错误被动状态2.3 优先级仲裁机制CAN总线采用CSMA/CD+AMP(载波监听多路访问+非破坏性逐位仲裁)机制:场景:节点A(ID=0x100)和节点B(ID=0x200)同时发送 总线电平: ___ ___ ___ ___ ___ | | | | | | | | | ───── ── ── ── ── ── ── SOF | ID10| ID9 | ID8 | ... | ID0 | RTR 节点A发送: 0 1 0 0 0 0 (0x100=0001 0000 0000) 节点B发送: 0 1 0 0 1 1 (0x200=0010 0000 0000) 位逐次比较: Bit10-7: 相同(0) Bit6: A=0, B=1 → 总线0(显性) → A胜出 剩余位: A继续发送,B停止 结论:ID值越小,优先级越高2.4 错误检测机制CAN控制器内置5种错误检测:错误类型检测方式处理位填充错误连续5个相同电平后必须插入反向位发送错误帧CRC错误接收帧CRC与计算值不符发送错误帧ACK错误发送节点未检测到应答重发格式错误固定格式位(EOF/CRC delimiter)异常发送错误帧位错误发送与总线电平不一致发送错误帧三、CanDriver驱动层3.1 模块职责Can模块位于MCAL层,是直接操作CAN控制器硬件的驱动软件。它的职责包括:硬件抽象:提供独立于硬件的API发送服务:Can_Write()将L-PDU写入硬件发送缓冲区接收通知:通过回调函数CanIf_RxIndication()通知上层控制器管理:状态切换、波特率配置、休眠唤醒关键约束:Can模块的唯一上层用户是CanIf模块(SRS_SPAL_12092)。3.2 控制器状态机┌─────────────────────────────────────┐ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ │ │ UNINIT ──────────────────┼───┼─── Can_Init() │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ │ Can_Init() │ │ ▼ │ │ ┌─────────────────────────────┐ │ │ │ │ │ Can_DeInit() │ │ STARTED ◄─────────────┼───┤ Can_SetControllerMode(CAN_T_START) │ │ │ │ │ │ │ │ Can_SetController │ │ │ │ │ Mode(CAN_T_WAKEUP)│ │ │ │ ▼ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ STOPPED │──┼───┤ Can_SetControllerMode(CAN_T_STOP) │ │ │ │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ │ │ │ Can_SetController │ │ │ │ │ Mode(CAN_T_STANDBY)│ │ │ │ ▼ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ STANDBY │──┼───┤ Wakeup Event / Can_SetControllerMode │ │ │ │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────────┘状态说明:状态说明可执行操作UNINIT未初始化调用Can_Init()STARTED正常运行发送/接收STOPPED停止只可配置,不可通信STANDBY休眠等待唤醒3.3 硬件对象配置Can模块通过配置CanHardwareObject定义发送/接收缓冲区:/* Can.h 配置结构示例 */ typedef struct { Can_HwHandleType Hth; /* Transmit Handle */ Can_HwHandleType Hrh; /* Receive Handle */ uint8 ControllerId; /* 控制器ID */ CanObjectId CanHardwareObjectId; } Can_ConfigType; /* 硬件对象类型 */ typedef enum { CAN_HOH_TYPE_TRANSMIT = 0, /* 发送硬件对象 */ CAN_HOH_TYPE_RECEIVE = 1 /* 接收硬件对象 */ } Can_HohType; /* 硬件对象配置示例 */ CanHardwareObjectConfig CanHardwareObject_EngineDataTx = { .CanHandleType = CAN_HOH_TYPE_TRANSMIT, .CanIdValue = 0x100, /* 帧ID */ .CanObjectId = 0, .CanObjectPosted = TRUE, /* 中断使能 */ .CanObjectPriority = PRIORITY_NORMAL };3.4 发送处理源码分析/* Can.c - Can_Write() 实现 */ Std_ReturnType Can_Write(Can_HwHandleType Hth, const Can_PduType *PduInfo) { /* 1. 参数校验 */ if (Hth = CAN_MAX_HOBS || PduInfo == NULL_PTR) { return E_NOT_OK; } /* 2. 检查控制器状态 */ if (Can_ControllerState[CAN_GET_CONTROLLER(Hth)] != CAN_CS_STARTED) { return CAN_NOT_OK; /* 控制器未启动 */ } /* 3. 获取硬件资源锁(防止优先级反转)*/ Can_LockHth(Hth); /* 4. 查找空闲发送缓冲区 */ Can_HardwareObjectType * Hob = CAN_GET_HOB(Hth); if (Hob-CurrentPdu != NULL) { /* 发送缓冲区忙,尝试软件队列或直接返回 */ Can_UnlockHth(Hth); return CAN_BUSY; } /* 5. 复制数据到硬件缓冲区 */ Hob-CurrentPdu = PduInfo; /* 保存引用 */ CAN_HW_WRITE_DATA(Hob, PduInfo-sdu, PduInfo-length); CAN_HW_SET_ID(Hob, PduInfo-id); /* 6. 启动发送(硬件自动仲裁)*/ CAN_HW_TRIGGER_TRANSMIT(Hob); Can_UnlockHth(Hth); return E_OK; } /* 中断服务程序 - 发送完成回调 */ void Can_TxInterruptHandler(uint8 ControllerId) { /* 1. 读取中断状态寄存器 */ uint32 IrqStatus = CAN_READ_TX_IRQ_STATUS(ControllerId); /* 2. 遍历触发中断的硬件对象 */ while (IrqStatus != 0) { uint8 HohIndex = FIND_FIRST_SET_BIT(IrqStatus); IrqStatus = ~(1 HohIndex); /* 清除已处理位 */ /* 3. 获取硬件对象信息 */ Can_HardwareObjectType *Hob = Can_Config.HardwareObjects[HohIndex]; /* 4. 判断发送结果 */ if (CAN_HW_CHECK_TX_SUCCESS(Hob)) { /* 5. 清除缓冲区 */ Hob-CurrentPdu = NULL; /* 6. 通过CanIf通知发送成功 */ CanIf_TxConfirmation( Hob-PduHandleRef, /* PDU句柄 */ E_OK ); } else { /* 发送失败(如仲裁丢失) */ CAN_HW_RETRY_TRANSMIT(Hob); } } }3.5 接收处理源码分析/* Can.c - 接收中断处理 */ void Can_RxInterruptHandler(uint8 ControllerId) { /* 1. 读取接收中断状态 */ uint32 IrqStatus = CAN_READ_RX_IRQ_STATUS(ControllerId); /* 2. 处理每个接收到的消息 */ while (CAN_HW_HAS_RX_MESSAGE(ControllerId)) { /* 3. 从硬件FIFO读取数据 */ uint32 CanId; uint8 Data[64]; uint8 Dlc; Can_HwType HwObject; CAN_HW_READ_MESSAGE(ControllerId, CanId, Data[0], Dlc, HwObject); /* 4. 构造CanIf所需的信息 */ Can_PduType PduInfo; PduInfo.id = CanId; PduInfo.length = Dlc; PduInfo.sdu = Data; PduInfo.swPduHandle = HwObject.CanObjectId; /* 5. 调用CanIf的接收指示回调 */ CanIf_RxIndication(HwObject, PduInfo); } } /* 轮询模式下的MainFunction处理 */ void Can_MainFunction_Read(void) { for (uint8 Controller = 0; Controller CAN_MAX_CONTROLLERS; Controller++) { if (Can_ControllerConfig[Controller].CanPolling == TRUE) { /* 轮询检查接收 */ while (CAN_HW_HAS_RX_MESSAGE(Controller)) { /* 与中断模式相同的处理逻辑 */ Can_RxInterruptHandler(Controller); } } } }四、CanIf接口层4.1 模块职责CanIf(CAN Interface)是通信栈中的关键抽象层:统一接口:为上层(PDURouter)提供硬件无关的API发送缓冲:软件层面的发送缓冲管理
【CP-06】CAN通信实战 - 从Frame到Signal的全流程
发布时间:2026/5/27 11:03:07
【CP-06】CAN通信实战 - 从Frame到Signal的全流程【CP-06】CAN通信实战 - 从Frame到Signal的全流程【CP-06】CAN通信实战 - 从Frame到Signal的全流程前言在汽车电子系统中,CAN(Controller Area Network)总线是应用最广泛的通信协议之一。从车身BCM控制模块到动力总成ECM,从网关GW到智能座舱,CAN总线承载着整车超过70%的实时数据交互。在前几篇文章中,我们已经了解了AUTOSAR CP的整体架构(CP-02)、BSW通信栈模块(CP-03)、OS任务调度(CP-04)和RTE运行时环境(CP-05)。本文将深入剖析CAN通信在AUTOSAR架构中的完整数据流:从应用层的Signal(信号)如何打包成Frame(帧),穿越COM、PDURouter、CanIf、CanDriver各层,最终到达CAN总线的物理层;以及反向从CAN总线接收的Frame如何解析成应用层可用的Signal。理解这一完整流程,是掌握AUTOSAR通信栈、进行故障诊断和性能优化的基础。一、通信架构全景1.1 CAN通信栈层次结构在AUTOSAR分层架构中,CAN通信涉及以下模块层次:┌─────────────────────────────────────────────────────────────────┐ │ Application Layer (ASW) │ │ Software Components (SW-C) │ │ Signal-based Interface (发送/接收) │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ Runtime Environment (RTE) │ │ Signal Routing Port Interface │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ AUTOSAR COM Module │ │ Signal Packing/Unpacking │ Byte Order │ TM Selection │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ PDU Router │ │ I-PDU Routing │ Gateway │ TP │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ CAN Interface (CanIf) │ │ Tx Buffering │ Rx Filtering │ Controller Mode │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ CAN Driver (Can) │ │ Hardware Access │ ISR │ State Machine │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────────┐ │ Microcontroller Abstraction Layer (MCAL) │ │ CAN Controller Registers │ Hardware │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌───────────────┐ │ CAN Transceiver │ │ Physical Layer │ └───────────────┘ │ ═══════╪════════ CAN Bus1.2 关键概念辨析在深入学习之前,必须明确以下概念:概念定义在CAN通信中的角色Signal应用层的数据元素,代表一个物理量或逻辑值发送方:温度值、车速;接收方:期望收到的数据I-PDUInteraction Layer Protocol Data Unit,交互层协议数据单元COM模块处理的数据单元,可包含多个SignalL-PDUData Link Layer Protocol Data Unit,数据链路层协议数据单元CanIf/Can处理的帧数据,包含ID+DataFrameCAN总线上传输的完整数据帧物理层概念,包含SOF、ID、DLC、Data、CRC等Hardware ObjectCAN控制器内部的硬件缓冲区发送HOB和接收HRH/HRH1.3 Frame与Signal的映射关系一个CAN Frame可以承载多个Signal,这称为信号打包(Signal Packing):┌────────────────────────────────────────────────────────────────┐ │ CAN 2.0 Standard Frame │ │ ┌──────────┬─────────┬───────┬───────────────────────────┐ │ │ │ ID │ DLC │ Data Field (up to 8 bytes) │ │ │ │ 11 bits │ 4 bits │ │ │ │ └──────────┴─────────┴───────┴───────────────────────────┘ │ │ │ │ Example: EngineData (ID=0x100) │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ Byte 0 │ Byte 1-2 │ Byte 3 │ Byte 4-5 │ Byte 6 │ │ │ │ EngSpd[0] │ EngSpd[1] │ Gear │ Trq[0] │ Trq[1] │ │ │ │ (8bit) │ (16bit) │ (8bit) │ (16bit) │ (8bit) │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ 可以看到:1个Frame(ID=0x100) 包含 4个Signal │ └────────────────────────────────────────────────────────────────┘二、CAN协议基础2.1 CAN 2.0标准帧格式┌─────┬────────┬─────┬────────┬───────┬────┬──────┬─────┬────┐ │ SOF │ ID │ RTR │ Ctrl │ Data │ CRC │ ACK │ EOF │ IFS│ │ 1 │ 11bits │ 1 │ 2bits │ 0-8B │ 15 │ 2 │ 7 │ 3 │ └─────┴────────┴─────┴───────┴───────┴────┴──────┴─────┴────┘字段说明:字段长度说明SOF1bit帧起始位,显性电平(0)ID11bits标识符,数值越小优先级越高RTR1bit远程传输请求,0=数据帧,1=远程帧IDE1bit标识符扩展位,0=标准帧DLC4bits数据长度码,表示Data字节数(0-8)Data0-8B数据负载CRC15bits循环冗余校验ACK2bits应答位EOF7bits帧结束2.2 CAN FD协议特性CAN FD(Flexible Data-rate)在AUTOSAR R4.2之后得到支持:特性CAN 2.0CAN FDID长度11bits标准/29bits扩展相同数据长度0-8字节0-64字节波特率最高1Mbps数据段最高8Mbps帧格式固定可变比特率┌─────┬────────┬─────┬─────┬─────┬────────┬──────────┬────┬──────┬─────┬────┐ │ SOF │ ID │ RTR │ IDE │ FDF │ BRS │ DLC │Data│ CRC │ ACK │EOF│ │ 1 │ 11bits │ 1 │ 1 │ 1 │ 1 │ 4bits │64B │ 17/21 │ 2 │7 │ └─────┴────────┴─────┴─────┴─────┴──────┴──────────┴────┴──────┴─────┴────┘关键新增字段: -FDF(FD Frame): 1=CAN FD帧 -BRS(Bit Rate Switch): 1=切换到高速率 -ESI(Error State Indicator): 错误被动状态2.3 优先级仲裁机制CAN总线采用CSMA/CD+AMP(载波监听多路访问+非破坏性逐位仲裁)机制:场景:节点A(ID=0x100)和节点B(ID=0x200)同时发送 总线电平: ___ ___ ___ ___ ___ | | | | | | | | | ───── ── ── ── ── ── ── SOF | ID10| ID9 | ID8 | ... | ID0 | RTR 节点A发送: 0 1 0 0 0 0 (0x100=0001 0000 0000) 节点B发送: 0 1 0 0 1 1 (0x200=0010 0000 0000) 位逐次比较: Bit10-7: 相同(0) Bit6: A=0, B=1 → 总线0(显性) → A胜出 剩余位: A继续发送,B停止 结论:ID值越小,优先级越高2.4 错误检测机制CAN控制器内置5种错误检测:错误类型检测方式处理位填充错误连续5个相同电平后必须插入反向位发送错误帧CRC错误接收帧CRC与计算值不符发送错误帧ACK错误发送节点未检测到应答重发格式错误固定格式位(EOF/CRC delimiter)异常发送错误帧位错误发送与总线电平不一致发送错误帧三、CanDriver驱动层3.1 模块职责Can模块位于MCAL层,是直接操作CAN控制器硬件的驱动软件。它的职责包括:硬件抽象:提供独立于硬件的API发送服务:Can_Write()将L-PDU写入硬件发送缓冲区接收通知:通过回调函数CanIf_RxIndication()通知上层控制器管理:状态切换、波特率配置、休眠唤醒关键约束:Can模块的唯一上层用户是CanIf模块(SRS_SPAL_12092)。3.2 控制器状态机┌─────────────────────────────────────┐ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ │ │ UNINIT ──────────────────┼───┼─── Can_Init() │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ │ Can_Init() │ │ ▼ │ │ ┌─────────────────────────────┐ │ │ │ │ │ Can_DeInit() │ │ STARTED ◄─────────────┼───┤ Can_SetControllerMode(CAN_T_START) │ │ │ │ │ │ │ │ Can_SetController │ │ │ │ │ Mode(CAN_T_WAKEUP)│ │ │ │ ▼ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ STOPPED │──┼───┤ Can_SetControllerMode(CAN_T_STOP) │ │ │ │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ │ │ │ Can_SetController │ │ │ │ │ Mode(CAN_T_STANDBY)│ │ │ │ ▼ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ STANDBY │──┼───┤ Wakeup Event / Can_SetControllerMode │ │ │ │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────────┘状态说明:状态说明可执行操作UNINIT未初始化调用Can_Init()STARTED正常运行发送/接收STOPPED停止只可配置,不可通信STANDBY休眠等待唤醒3.3 硬件对象配置Can模块通过配置CanHardwareObject定义发送/接收缓冲区:/* Can.h 配置结构示例 */ typedef struct { Can_HwHandleType Hth; /* Transmit Handle */ Can_HwHandleType Hrh; /* Receive Handle */ uint8 ControllerId; /* 控制器ID */ CanObjectId CanHardwareObjectId; } Can_ConfigType; /* 硬件对象类型 */ typedef enum { CAN_HOH_TYPE_TRANSMIT = 0, /* 发送硬件对象 */ CAN_HOH_TYPE_RECEIVE = 1 /* 接收硬件对象 */ } Can_HohType; /* 硬件对象配置示例 */ CanHardwareObjectConfig CanHardwareObject_EngineDataTx = { .CanHandleType = CAN_HOH_TYPE_TRANSMIT, .CanIdValue = 0x100, /* 帧ID */ .CanObjectId = 0, .CanObjectPosted = TRUE, /* 中断使能 */ .CanObjectPriority = PRIORITY_NORMAL };3.4 发送处理源码分析/* Can.c - Can_Write() 实现 */ Std_ReturnType Can_Write(Can_HwHandleType Hth, const Can_PduType *PduInfo) { /* 1. 参数校验 */ if (Hth = CAN_MAX_HOBS || PduInfo == NULL_PTR) { return E_NOT_OK; } /* 2. 检查控制器状态 */ if (Can_ControllerState[CAN_GET_CONTROLLER(Hth)] != CAN_CS_STARTED) { return CAN_NOT_OK; /* 控制器未启动 */ } /* 3. 获取硬件资源锁(防止优先级反转)*/ Can_LockHth(Hth); /* 4. 查找空闲发送缓冲区 */ Can_HardwareObjectType * Hob = CAN_GET_HOB(Hth); if (Hob-CurrentPdu != NULL) { /* 发送缓冲区忙,尝试软件队列或直接返回 */ Can_UnlockHth(Hth); return CAN_BUSY; } /* 5. 复制数据到硬件缓冲区 */ Hob-CurrentPdu = PduInfo; /* 保存引用 */ CAN_HW_WRITE_DATA(Hob, PduInfo-sdu, PduInfo-length); CAN_HW_SET_ID(Hob, PduInfo-id); /* 6. 启动发送(硬件自动仲裁)*/ CAN_HW_TRIGGER_TRANSMIT(Hob); Can_UnlockHth(Hth); return E_OK; } /* 中断服务程序 - 发送完成回调 */ void Can_TxInterruptHandler(uint8 ControllerId) { /* 1. 读取中断状态寄存器 */ uint32 IrqStatus = CAN_READ_TX_IRQ_STATUS(ControllerId); /* 2. 遍历触发中断的硬件对象 */ while (IrqStatus != 0) { uint8 HohIndex = FIND_FIRST_SET_BIT(IrqStatus); IrqStatus = ~(1 HohIndex); /* 清除已处理位 */ /* 3. 获取硬件对象信息 */ Can_HardwareObjectType *Hob = Can_Config.HardwareObjects[HohIndex]; /* 4. 判断发送结果 */ if (CAN_HW_CHECK_TX_SUCCESS(Hob)) { /* 5. 清除缓冲区 */ Hob-CurrentPdu = NULL; /* 6. 通过CanIf通知发送成功 */ CanIf_TxConfirmation( Hob-PduHandleRef, /* PDU句柄 */ E_OK ); } else { /* 发送失败(如仲裁丢失) */ CAN_HW_RETRY_TRANSMIT(Hob); } } }3.5 接收处理源码分析/* Can.c - 接收中断处理 */ void Can_RxInterruptHandler(uint8 ControllerId) { /* 1. 读取接收中断状态 */ uint32 IrqStatus = CAN_READ_RX_IRQ_STATUS(ControllerId); /* 2. 处理每个接收到的消息 */ while (CAN_HW_HAS_RX_MESSAGE(ControllerId)) { /* 3. 从硬件FIFO读取数据 */ uint32 CanId; uint8 Data[64]; uint8 Dlc; Can_HwType HwObject; CAN_HW_READ_MESSAGE(ControllerId, CanId, Data[0], Dlc, HwObject); /* 4. 构造CanIf所需的信息 */ Can_PduType PduInfo; PduInfo.id = CanId; PduInfo.length = Dlc; PduInfo.sdu = Data; PduInfo.swPduHandle = HwObject.CanObjectId; /* 5. 调用CanIf的接收指示回调 */ CanIf_RxIndication(HwObject, PduInfo); } } /* 轮询模式下的MainFunction处理 */ void Can_MainFunction_Read(void) { for (uint8 Controller = 0; Controller CAN_MAX_CONTROLLERS; Controller++) { if (Can_ControllerConfig[Controller].CanPolling == TRUE) { /* 轮询检查接收 */ while (CAN_HW_HAS_RX_MESSAGE(Controller)) { /* 与中断模式相同的处理逻辑 */ Can_RxInterruptHandler(Controller); } } } }四、CanIf接口层4.1 模块职责CanIf(CAN Interface)是通信栈中的关键抽象层:统一接口:为上层(PDURouter)提供硬件无关的API发送缓冲:软件层面的发送缓冲管理