3. 接收CAN消息并解析信号值
任务说明
本案例要求使用CANoe CAPL脚本接收指定CAN报文,并从中解析出目标信号的物理值。以动力系统中常见的发动机转速报文(ID 0x1F4)为例,该报文包含8个数据字节,其中转速信号(EngineSpeed)位于字节2和字节3(共16位,Intel格式,因子0.25 rpm/bit,偏移量0)。完成目标:在CANoe仿真环境中,当总线上出现该报文时,CAPL程序能够正确提取转速原始值并转换为带单位的物理值,通过Write窗口输出。
实现方案
在CANoe中新建CAPL测试节点,通过on message事件处理器捕获目标报文。使用this.byte()函数按字节索引读取数据,按Intel格式组合16位原始值,再应用线性转换公式物理值 = 原始值 × 因子 + 偏移量得到最终转速。程序结构包含报文定义、信号解析函数和输出逻辑三部分。
CAPL代码实现
/* 接收CAN消息并解析信号值 - 发动机转速示例 */
/* 适用于CANoe 10.x及以上版本 */
variables
{
message 0x1F4 g_EngineSpeedMsg; // 目标报文:发动机转速
const int g_StartBit = 16; // 信号起始位(bit 16 = 字节2的bit0)
const int g_SignalLength = 16; // 信号长度16位
const double g_Factor = 0.25; // 因子:0.25 rpm/bit
const double g_Offset = 0.0; // 偏移量:0 rpm
double g_EngineSpeedPhys; // 解析后的物理值
}
/* 信号解析函数:从报文数据中提取指定起始位、长度的Intel格式信号 */
double SignalExtract(message *msg, int startBit, int signalLength, double factor, double offset)
{
int rawValue = 0;
int byteIndex;
int bitInByte;
int i;
// Intel格式(小端):信号从起始位开始,逐位向高字节方向排列
for (i = 0; i < signalLength; i++)
{
byteIndex = (startBit + i) / 8;
bitInByte = (startBit + i) % 8;
if ((msg.byte(byteIndex) & (1 << bitInByte)) != 0)
{
rawValue |= (1 << i);
}
}
// 线性转换:物理值 = 原始值 × 因子 + 偏移量
return (rawValue * factor + offset);
}
/* 报文接收事件处理 */
on message 0x1F4
{
// 调用解析函数获取转速物理值
g_EngineSpeedPhys = SignalExtract(this, g_StartBit, g_SignalLength, g_Factor, g_Offset);
// 输出解析结果
write("收到报文 ID=0x%X, 原始数据: %02X %02X %02X %02X %02X %02X %02X %02X",
this.id,
this.byte(0), this.byte(1), this.byte(2), this.byte(3),
this.byte(4), this.byte(5), this.byte(6), this.byte(7));
write("发动机转速 = %.1f rpm", g_EngineSpeedPhys);
}
代码说明
上述代码的核心逻辑如下:
- 报文定义:通过
message 0x1F4声明需要接收的CAN报文ID。 - 信号参数:起始位16对应字节2的bit0,长度16位,因子0.25,偏移量0。
- 解析函数:
SignalExtract逐位检查报文数据,按Intel格式组装原始值,再完成线性换算。该函数可复用,只需修改起始位、长度和因子即可解析同一报文中的其他信号。 - 事件处理:
on message 0x1F4在每次收到该ID报文时自动触发,调用解析函数并输出结果。
验证方法
在CANoe中按以下步骤验证:
- 新建工程并添加CAN通道,在Simulation Setup中插入一个CAPL测试节点,将上述代码粘贴到节点的CAPL编辑器中。
- 在IG(Interaction Generator)或CAN IG模块中,配置发送ID为0x1F4的周期性报文,并设置数据字节。例如设置字节2=0x00、字节3=0x64,则原始值=0x6400=25600,物理值=25600×0.25=6400.0 rpm。
- 启动测量(按F5或点击Start),观察Write窗口输出。
判定标准:当IG发送字节2=0x00、字节3=0x64的报文时,Write窗口显示“发动机转速 = 6400.0 rpm”,且原始数据打印为“00 64 00 00 00 00 00 00”,即表示解析正确。可修改字节2和字节3的值(如0x10、0x27对应原始值0x2710=10000,物理值2500.0 rpm)再次验证,输出应随输入线性变化。
关键点提示
- Intel格式(小端)中,信号低位字节在前,因此字节2是低8位,字节3是高8位,组合公式为
raw = byte(2) | (byte(3) << 8)。 - 若信号为Motorola格式(大端),位排列顺序相反,需调整提取逻辑,但本案例仅针对Intel格式。
- 因子0.25表示原始值每增加1,物理转速增加0.25 rpm,因此16位原始值最大65535对应16383.75 rpm,满足发动机转速范围。