4. Application SWC建模实战

应用层SWC(Application Software Component)是AUTOSAR虚拟功能总线(VFB)上最贴近控制策略的软件单元。它不直接操作寄存器,也不关心CAN帧或LIN调度,只负责把输入信号按算法转换为输出信号,并通过RTE(Runtime Environment)与其它SWC或BSW交互。本节以一个“车窗防夹控制”应用SWC为例,完整走通从创建SWC、定义Runnable Entity、绑定触发事件到RTE端口映射的建模过程。示例中的参数、周期和阈值均为教学假设,不代表任何具体车型的实测标定值。

一、先明确SWC的边界与接口

在DaVinci Developer中新建SWC时,第一步不是急着画内部逻辑,而是先确定它对外暴露什么。车窗防夹SWC需要三类接口:

  • 输入:车窗位置(0~100%,来自位置传感器SWC)、防夹力(N,来自电流采样SWC)、车窗开关命令(上升/下降/停止,来自车身控制SWC)。
  • 输出:电机驱动占空比(0~100%)、车窗状态(初始化/运行/防夹/故障)。
  • 标定参数:防夹力阈值(示例取80 N)、防夹反转时间(示例取300 ms)、软停止区间(示例取95%~100%)。

这些接口在DaVinci Developer中分别对应Sender-Receiver端口和Parameter端口。输入用Require端口,输出用Provide端口,标定参数用Parameter端口。端口方向一旦确定,后续RTE生成的数据类型和访问函数就基本定型,因此建议在创建SWC时就把端口一次性建全,避免后期反复调整。

二、创建SWC并定义Runnable Entity

在DaVinci Developer的“Application Component”视图中新建一个SWC,命名为Swc_WindowAntiPinch。随后在“Runnable”页签中添加Runnable Entity。Runnable是SWC内部可被RTE调度的最小执行单元,它不直接对应操作系统任务,而是由RTE根据触发事件映射到具体Task上运行。

本示例定义两个Runnable:

  • RE_AntiPinch_10ms:周期10 ms执行,负责采样防夹力、判断是否超过阈值、输出电机占空比。
  • RE_WindowState_Init:初始化时执行一次,负责把车窗状态置为“初始化”,并清零内部积分量。

在Runnable的属性中需要设置minimumStartInterval(最小启动间隔)。对RE_AntiPinch_10ms,示例设为0.01 s,与10 ms周期一致;对初始化Runnable,可设为0或留空,表示由初始化事件触发。Runnable的并发属性canBeInvokedConcurrently应保持false,因为防夹算法内部有状态变量,不允许重入。

三、触发事件:让Runnable真正跑起来

Runnable本身只是函数体,必须绑定触发事件才会被RTE调用。DaVinci Developer中常用的触发事件有三类:

  • TimingEvent:周期触发,适合控制算法。本示例给RE_AntiPinch_10ms绑定一个周期为0.01 s的TimingEvent。
  • OperationInvokedEvent:由Client-Server接口调用触发,适合服务型Runnable。
  • InitEvent:初始化触发,给RE_WindowState_Init绑定。

绑定TimingEvent时要注意:周期值必须与后续RTE映射到的Task周期兼容。如果Task周期是10 ms,而TimingEvent写成5 ms,RTE生成阶段会报周期不匹配。因此建议在建模阶段就与基础软件工程师确认Task周期,再回填到TimingEvent中。

车窗防夹应用SWC:Runnable、触发事件与RTE端口映射关系 Swc_WindowAntiPinch RE_AntiPinch_10ms 周期:10 ms | 最小启动间隔:0.01 s 读取防夹力 → 与阈值比较 → 输出占空比 内部状态:积分量、防夹标志、反转计时 RE_WindowState_Init 初始化触发 | 状态置“初始化” 清零积分量与防夹标志 R-Port 输入 P-Port 输出 Parameter 标定 TimingEvent 周期 0.01 s InitEvent 初始化触发 RTE Rte_Runnable Rte_Read / Rte_Write Rte_Call Rte_Parameter 映射到 OS Task 周期 10 ms RTE端口映射结果(示例) Rte_Read_WindowPos() | Rte_Read_PinchForce() | Rte_Read_SwitchCmd() | Rte_Write_MotorDuty() | Rte_Write_WindowState() | Rte_Parameter_PinchThreshold()

四、RTE端口映射:把SWC接到VFB上

端口映射的本质是告诉RTE:SWC的哪个端口对应哪个数据元素,以及Runnable通过什么API访问它。在DaVinci Developer中,端口映射分为两步:先在SWC内部把端口与数据元素关联,再在系统层面把SWC端口与其它SWC端口或BSW端口连接。

以输入端口为例,R-Port_WindowPos关联数据元素DE_WindowPosition,类型为uint8,范围0~100。RTE会据此生成Rte_Read_R-Port_WindowPos_DE_WindowPosition()这样的读取函数。在RE_AntiPinch_10ms中调用它,即可拿到当前车窗位置。输出端口P-Port_MotorDuty关联DE_MotorDuty,RTE生成Rte_Write_P-Port_MotorDuty_DE_MotorDuty()。

标定参数端口P-Port_PinchThreshold关联DE_PinchThreshold,类型为uint16,单位N。RTE生成Rte_Parameter_P-Port_PinchThreshold_DE_PinchThreshold(),在初始化阶段读取一次即可,不必每个周期都读。这样既减少运行开销,也避免标定值在运行中被意外改写。

五、一个可执行的Runnable伪代码示例

下面给出RE_AntiPinch_10ms的核心逻辑伪代码,用于说明RTE API在Runnable内部如何被调用。示例中的阈值和反转时间均为教学假设值。

void RE_AntiPinch_10ms(void)
{
    uint8  windowPos;
    uint16 pinchForce;
    uint8  switchCmd;
    uint8  motorDuty;
    uint16 threshold;

    /* 通过RTE读取输入 */
    Rte_Read_RPort_WindowPos_DE_WindowPosition(&windowPos);
    Rte_Read_RPort_PinchForce_DE_PinchForce(&pinchForce);
    Rte_Read_RPort_SwitchCmd_DE_SwitchCmd(&switchCmd);

    /* 读取标定参数 */
    Rte_Parameter_PPort_PinchThreshold_DE_PinchThreshold(&threshold);

    /* 防夹判断:力超过阈值且车窗处于上升区间 */
    if ((pinchForce > threshold) && (switchCmd == CMD_UP)) {
        motorDuty = 0;                 /* 立即停转 */
        Rte_Write_PPort_WindowState_DE_WindowState(STATE_ANTIPINCH);
        /* 启动300 ms反转计时,此处用静态变量示意 */
        antiPinchTimer = 30;           /* 10 ms × 30 = 300 ms */
    } else if (antiPinchTimer > 0) {
        motorDuty = 60;                /* 反转占空比示例值 */
        antiPinchTimer--;
        Rte_Write_PPort_WindowState_DE_WindowState(STATE_REVERSING);
    } else {
        motorDuty = (switchCmd == CMD_UP) ? 80 : 0;
        Rte_Write_PPort_WindowState_DE_WindowState(STATE_RUNNING);
    }

    Rte_Write_PPort_MotorDuty_DE_MotorDuty(motorDuty);
}

这段代码里,所有跨SWC的数据访问都通过RTE API完成,没有直接读写全局变量。这正是Application SWC建模的核心约束:SWC只依赖RTE,不依赖具体ECU的硬件和OS。

六、建模完成后的检查要点

在DaVinci Developer中完成上述建模后,建议按以下顺序做一次一致性检查:

  • 每个Runnable是否都绑定了触发事件,且TimingEvent周期与目标Task周期一致。
  • 每个端口是否都关联了数据元素,数据类型和范围是否与信号实际物理量匹配。
  • 标定参数是否放在Parameter端口而非Sender-Receiver端口,避免运行期被误写。
  • Runnable的canBeInvokedConcurrently是否为false,防止状态变量重入。
  • 端口映射后,RTE生成的API名称是否与Runnable中调用的名称一致。
如果RTE生成阶段报“port not mapped”或“data element type mismatch”,优先回到SWC的端口定义和数据元素关联处检查,而不是直接改Runnable代码。建模阶段的错误应在建模阶段解决。