3. CAPL实现周期报文发送与信号更新
任务拆解与报文定义
本例在已导入 DBC 的 CANoe 工程中,用 CAPL 节点周期发送一条发动机转速报文,并让转速信号按固定步长递增。先明确报文与信号参数,再写 CAPL 代码,最后在 Trace 窗口验证。
| 对象 | 取值 | 说明 |
|---|---|---|
| 报文名称 | EngineSpeed_Msg | DBC 中已定义的发送报文 |
| 报文 ID | 0x180 | 标准帧,DLC = 8 |
| 发送周期 | 100 ms | 用 setTimer 循环触发 |
| 信号名称 | EngineSpeed | 起始位 0,长度 16 bit,小端 |
| 信号因子/偏移 | 0.25 rpm / 0 | 物理值 = 原始值 × 0.25 |
| 更新步长 | +250 rpm | 每个周期递增一次 |
| 有效范围 | 0 ~ 8000 rpm | 超出后回绕到 0 |
CAPL 实现
在 Simulation Setup 中新建一个 CAPL 节点,把下面的代码写入该节点的 .can 文件。代码用 100 ms 定时器驱动发送,每次触发时先更新 EngineSpeed 物理值,再调用 output() 发出报文。
/* EngineSpeedSender.can
* 周期发送 EngineSpeed_Msg,转速按 +250 rpm 步长更新
*/
variables
{
msTimer tSend; // 100 ms 周期定时器
float gSpeed = 0.0; // 当前转速物理值,单位 rpm
const float kStep = 250.0; // 每周期步长
const float kMax = 8000.0;// 上限,超出回绕
}
on start
{
gSpeed = 0.0;
setTimer(tSend, 100); // 启动第一个周期
write("EngineSpeedSender started, period = 100 ms");
}
on timer tSend
{
// 1) 更新信号物理值
gSpeed = gSpeed + kStep;
if (gSpeed > kMax)
{
gSpeed = 0.0; // 回绕,便于观察周期性变化
}
// 2) 写入报文信号(DBC 自动完成物理值到原始值换算)
EngineSpeed_Msg.EngineSpeed = gSpeed;
// 3) 发送报文
output(EngineSpeed_Msg);
// 4) 重新装载定时器,形成周期
setTimer(tSend, 100);
}
on stopMeasurement
{
cancelTimer(tSend);
write("EngineSpeedSender stopped at speed = %f rpm", gSpeed);
}
若 DBC 中信号名或报文名不同,只需替换
EngineSpeed_Msg.EngineSpeed 这一处;其余逻辑与周期、步长无关,可保持不变。信号更新与发送时序
下图给出一个发送周期内的处理顺序:定时器到期 → 转速累加并判断回绕 → 写入信号 → 发出报文 → 重装定时器。Trace 窗口中每个 100 ms 应出现一帧 ID 为 0x180 的报文,其 EngineSpeed 物理值按 250 rpm 递增。
验证与判读
- 启动 Measurement,在 Trace 窗口按 ID 过滤
0x180,确认报文以约 100 ms 间隔连续出现。 - 展开报文的信号列,观察
EngineSpeed物理值:应从 0 开始,每帧增加 250 rpm,即 0、250、500、750…… - 当数值超过 8000 rpm 后应回绕到 0,说明回绕分支生效。
- 若报文不出现,检查 CAPL 节点是否已加入 Simulation Setup 并处于激活状态;若周期明显偏离 100 ms,检查是否在
on timer中遗漏了setTimer重装。
CAPL 中
output() 发送的是 DBC 中该报文的发送方向;若 DBC 把该报文定义为接收报文,需在数据库属性中改为发送,否则节点不会真正发出帧。