CAPL 编程系列教程的第十八期内容,终于开始讲解 CAPL 中与 CAN 通信直接相关的核心内容:报文 (Message) 的处理,本期重点是定义报文变量并发送报文。
CAPL 编程系列教程 - 第十八期:Message 类型与报文发送
一、 课程回顾与本期目标
- 回顾: 前面学习了 CAPL 的基础语法,包括数据类型、变量、运算符、控制流(分支、循环)、函数、定时器等。
- 本期目标: 学习如何在 CAPL 中定义代表 CAN 报文的变量,给报文变量赋值(设置 DLC 和数据字节),并使用
output()函数将报文发送到总线上。 - 核心概念: 在 CAPL 中,CAN 报文被抽象为一种特殊的数据类型,关键字为
message。
二、 定义/声明 message 类型的变量
- 关键字:
message。 - 两种主要声明方式:
- 基于报文 ID:
- 语法:
message <ID> VariableName; <ID>: 指定报文的 CAN ID。推荐使用十六进制(以0x开头),但十进制也可以。VariableName: 自定义的报文变量名。- 适用场景: 当 DBC 文件中没有定义该报文,或者不想依赖 DBC 文件时。
- 示例:
message 0x1A5 msg1;声明一个 ID 为 0x1A5 的报文变量msg1。
- 语法:
- 基于 DBC 中的报文名称:
- 语法:
message <DBC_MessageName> VariableName; <DBC_MessageName>: 在已加载的 DBC 文件中定义的报文的符号名称。- 优点: 代码可读性更好,不易出错。
- 前提: CANoe 工程中必须已加载包含该报文名称的 DBC 文件。
- 示例:
message EngineState msg_engine;(假设 DBC 中有名为EngineState的报文)。(本期主要演示基于 ID 的方式,基于名称的方式将在后续讲解)
- 语法:
- 基于报文 ID:
- 声明位置: 与其他变量一样,
message变量的声明也必须放在其所在代码块(如on key)的最前面。
三、 给 message 变量赋值
-
目的: 在发送报文前,需要设置其属性,主要是数据长度码 (DLC) 和数据域 (Data Bytes)。
-
访问属性 (使用选择器 Selectors): 通过点运算符 (
.) 访问message变量的属性(选择器)。- 设置 DLC:
- 选择器:
.dlc - 语法:
VariableName.dlc = value;(value 通常是 0-8) - 作用: 指定报文数据域的字节长度。
- 默认值: 如果不设置,DLC 默认为 0。
- 示例:
msg1.dlc = 8;
- 选择器:
- 设置数据字节:
- 按字节设置 (
.byte()):- 选择器:
.byte(index) - 语法:
VariableName.byte(index) = byte_value; index: 字节索引,从 0 开始 (0 到 7)。byte_value: 要设置的字节值,推荐使用十六进制 (如0xC7)。- 示例:
msg1.byte(0) = 0xC7; msg1.byte(1) = 0x95;
- 选择器:
- 按字设置 (
.word()):- 选择器:
.word(index) - 语法:
VariableName.word(index) = word_value; index: 字的起始字节索引 (通常是偶数 0, 2, 4, 6)。word_value: 要设置的字(2 字节)的值,推荐使用十六进制 (如0x95C7)。- 字节序 (Byte Order): 注意!
.word()赋值时,word_value的低字节会赋给index指定的字节,高字节会赋给index + 1的字节。 - 示例:
msg3.word(0) = 0x95C7;效果等同于msg3.byte(0) = 0xC7; msg3.byte(1) = 0x95;(低字节 C7 在前,高字节 95 在后)。 - 示例:
msg3.word(2) = 0x3F6B;效果等同于msg3.byte(2) = 0x6B; msg3.byte(3) = 0x3F;(低字节 6B 在前,高字节 3F 在后)。
- 选择器:
- 其他选择器: 教程提到还有
.dword()(4字节) 和.qword()(8字节) 选择器,用法类似.word(),也需注意字节序。
- 按字节设置 (
- 未赋值字节: 如果设置的 DLC 大于实际赋值的字节数,未被赋值的数据字节默认为 0。
- 设置 DLC:
-
声明时初始化:
- 可以在声明
message变量的同时,使用花括号{}初始化列表为其属性赋初值,类似结构体初始化。 - 语法:
message <ID or Name> VarName = { dlc = value, byte(0) = val0, byte(1) = val1, ... }; - 示例:
Code snippet
message 0x2B6 msg2 = { dlc = 4, byte(0) = 0x2D, byte(1) = 0x3F }; // 初始化 DLC 为 4,前两个字节赋值,后两个字节默认为 0
- 可以在声明
四、 发送报文 (output() 函数)
- 作用: 将一个配置好的
message变量发送到其关联的总线上(由 CAPL 节点所在的仿真总线决定)。 - 语法:
output(MessageVariable); MessageVariable: 要发送的报文变量名。- 示例:
output(msg1); output(msg2); - 调用时机: 可以在任何需要发送报文的逻辑点调用,如
on key,on timer, 函数内部等。
五、 示例代码与验证
- 教程演示了在
on key 'a'事件中:- 声明
message 0x1A5 msg1;。 - 设置
msg1.dlc = 8;。 - 设置
msg1.byte(0)到msg1.byte(3)的值。 - 声明并初始化
message 0x2B6 msg2 = {dlc = 4, byte(0) = 0x2D, byte(1) = 0x3F};。 - 声明
message 0x3C7 msg3;。 - 设置
msg3.dlc = 8;。 - 使用
msg3.word(0) = 0x95C7;和msg3.word(2) = 0x3F6B;赋值。 - 调用
output(msg1); output(msg2); output(msg3);发送报文。
- 声明
- 验证: 在 CANoe 的 Trace 窗口中观察,当按下 'A' 键后,是否出现了 ID 为 0x1A5, 0x2B6, 0x3C7 的报文,并且其 DLC 和数据字节是否与代码中设置的一致。
六、 总结与后续
- 本期学习了 CAPL 中处理报文的基础:使用
message关键字定义报文变量(通过 ID 或 DBC 名称),使用点运算符和选择器(.dlc,.byte(),.word()等)设置报文属性,以及使用output()函数发送报文。 - 理解了赋值和初始化的不同方式,特别是
.word()的字节序问题。 - 下一期 (第 19 期) 将讲解如何利用 DBC 文件,通过信号名称来更方便地操作报文数据,以及报文事件的处理。