4. 基于事件触发的CAN消息发送
任务定义
在CANoe中,周期型发送的CAN消息无法满足“仅在特定条件发生时发送”的场景(如车门解锁、档位切换等)。本案例要求实现一个基于事件触发的CAN消息发送脚本:当检测到某个输入信号(例如点火状态从OFF变为ON)时,立即发送一条自定义CAN消息(例如0x123),且该消息仅在事件发生时发送一次,不进行周期发送。
实现方案
使用CAPL程序,通过系统变量或环境变量作为事件源。本案例采用系统变量作为触发源(便于手动仿真验证),在系统变量值变化时触发发送逻辑。核心思路:
- 在CANoe仿真节点中编写CAPL程序;
- 监控系统变量
SysVar::IgnitionState(整型,0=OFF,1=ON); - 当变量值从0变为1时,调用
output()函数发送CAN消息0x123; - 消息数据域填充当前时间戳(秒为单位)和事件计数器。
CAPL代码实现
/* 事件触发发送节点 - EventSender.can */
variables
{
message 0x123 EventMsg = { dlc = 8 };
int lastIgnitionState = 0; // 记录上一次点火状态
int eventCounter = 0; // 事件计数器
}
on sysvar SysVar::IgnitionState
{
int currentState = @this;
// 检测上升沿:OFF(0) -> ON(1)
if (currentState == 1 && lastIgnitionState == 0)
{
eventCounter++;
EventMsg.byte(0) = eventCounter & 0xFF; // 计数器低字节
EventMsg.byte(1) = (eventCounter & 0xFF00) >> 8; // 计数器高字节
EventMsg.byte(2) = timeNow() & 0xFF; // 时间戳低字节
EventMsg.byte(3) = (timeNow() >> 8) & 0xFF; // 时间戳高字节
EventMsg.byte(4) = 0xAA; // 固定标识
EventMsg.byte(5) = 0x55; // 固定标识
EventMsg.byte(6) = 0x00; // 保留
EventMsg.byte(7) = 0x00; // 保留
output(EventMsg); // 发送消息
write("事件触发: 0x123 已发送, 计数器=%d", eventCounter);
}
lastIgnitionState = currentState;
}
on start
{
write("事件发送节点已启动,等待点火状态变化...");
}
工程配置与运行步骤
- 创建系统变量:在CANoe的Simulation Setup中,打开System Variables窗口,新建变量
IgnitionState(类型Integer,初始值0)。 - 添加CAPL节点:在Simulation Setup中添加一个Network Node,将上述代码粘贴到该节点的CAPL编辑器中。
- 配置CAN通道:确保该节点连接到CAN总线(如CAN 1),消息0x123的发送通道与节点所在通道一致。
- 启动测量:点击“Start Measurement”开始仿真。
- 触发事件:在System Variables窗口或使用Write窗口的
setSysVar(SysVar::IgnitionState, 1)命令,将点火状态从0改为1。
验证方法与判定标准
验证步骤:
- 启动测量后,在Trace窗口添加CAN消息过滤,只显示ID=0x123的消息;
- 在Write窗口执行
setSysVar(SysVar::IgnitionState, 1); - 观察Trace窗口是否出现一条0x123消息;
- 再次执行
setSysVar(SysVar::IgnitionState, 0),再执行setSysVar(SysVar::IgnitionState, 1),观察是否出现第二条0x123消息。
判定标准:
- 每次点火状态从0变为1时,Trace窗口恰好新增一条0x123消息;
- 点火状态保持为1不变时,不产生新的0x123消息;
- 消息数据域中:byte(0)和byte(1)组成的计数器值逐次递增1;byte(2)和byte(3)组成的时间戳与当前仿真时间一致(允许±1秒误差);byte(4)=0xAA,byte(5)=0x55。
关键说明
- 本实现仅响应系统变量
IgnitionState的上升沿,不响应下降沿,也不进行周期发送; - 计数器
eventCounter在每次事件触发时递增,用于验证事件确实发生; - 时间戳使用
timeNow()函数获取仿真时间(单位秒),便于与Trace窗口时间对照; - 若需改为真实信号触发,只需将
on sysvar替换为on message或on signal,并在相应事件中判断信号值变化即可。