带你入门
Posted 蚂蚁小兵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你入门相关的知识,希望对你有一定的参考价值。
- 🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用
- 🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】
- 🍅 玩转CANoe,博客目录大全,点击跳转👉
📘前言
-
🍅 本章内容,面向CAPL初学者,超过两万字,超全超详细。
-
🍅 本节内容大量引用,翻译下面的Vector 官方文档:capl_programming ,资料我放在下方公众号网盘了,有需自取!
目录
- 📘前言
- 📙1 CAPL 简介
- 📙2 CAPL 语法基础
- 🌎总结
📙1 CAPL 简介
-
CAPL(发音为“kapple”),是 Communication Access Programming Language 的缩写。CAPL是基于C语言开发的,专门用于CANalyzer和CANoe工具环境,但是CAPL简化了C语言,移除了复杂的指针概念,和一些不常用的关键字等,也融入了一些C++的概念,比如函数重载等。就学习难度而言 CAPL < C< C++。
-
CANalyzer或CANoe工具本身无需CAPL程序,就足以执行简单的测量和分析。采用CAPL程序,大大扩展了CAN通信的测量和分析。
如果没有CAPL,该工具无法执行的是涉及计时的分析。CAPL可以使分析更加高效 -
CAPL 脚本是基于事件驱动的,和常规语言不同,CAPL没有 main()函数,没有程序入口,任何事件都有可能触发CAPL脚本的执行,比如,按键事件,定时器事件,执行测试等;如果没有事件发生,那么CAPL程序是“闲置的”。
-
任何语言都需要编译之后才能运行,我们编写CAPL 的IDE叫做 CAPL Browser ,是CNAoe 整个开发环境的一部分组件;因为CAPL Browser的整体结构基于事件的概念,并且是专门组织的围绕不同的事件类,软件开发过程比传统的组织要简单得多C程序。关于CAPL的事件结构更详细的解读,参考后面章节博客内容。
📙2 CAPL 语法基础
🍅2.1 CAPL和C语言的主要不同点
- 下图可以看出,C语言支持很多概念,CAPL都舍弃掉了,或者只取其一小部分支持,让CAPL语言更加简便和易懂
- 比如CAPL是基础事件驱动的,所以不需要main()函数入口
- 持指针操作,宏定义,头文件都不在支持
- 下图有点老,博主基于CANoe 11版本,枚举和结构体类型都是支持的。
- 在c语言中,使用函数之前,必须要进行声明,而CAPL是不需要的。
Note:
1,在CAPL中,默认所有的局部变量都是静态的,在C语言中,需要用关键字static 修饰的变量才是静态的。这一点新手在写脚本要特别注意 点击,了解 CAPL脚本中关于 局部变量 容易忽略的一点
2,void 在CAPL中只支持函数返回值类型,表示函数没有返回值
3,CAPL中使用了一些标准的C函数。这些函数通常是数学函数或字符串函数(例如,abs(),strncpy())已经在CAPL内部预定义了。
4,CAPL没有完整的ANSI C标准库,但它有CAPL特有的库,称为CAPL dll。dll编程需要有一定的编程经验
5,字符串数据类型在CAPL中不支持;但是,您可以使用字符数组(例如,char temp[6]= " Hello "😉。
🍅2.1 CAPL和C语言中等价的函数
- 对于C程序员来说,了解一些等价的函数是很有帮助的。下面是一个类似的简明列表函数,但有关CAPL函数如何使用的更多详细信息,请参阅CAPL函数参考手册。
🍅2.2 注释
- CAPL 的注释方式和大多数语言都一样,都是通过 // 或者 /**/ 来实现的,下面四种注释方法都是合法的。
- CAPL Brower中注释代码的默认快捷键 选中你要注释的代码,先按住组合键 Ctrl + K ,然后在按组合键Ctrl +C ; 解除注释是 先按住组合键 Ctrl + K ,然后在按组合键Ctrl +U ;
1. /* This is a comment.*/
2. /* This comment is spread
over two lines.*/
3. /*
You can do this, too.
*/
4. // CAPL also accepts the C++ comment.
🍅2.3 变量的命名规范
-
变量名、函数名和数组名可以由字母和数字和下划线组成,但是首字母不能是数字
-
下面的命名都是合法的:
sum
number_of_units
J5x7
_sysflag -
下面的命名都是不合法的:
int // because it is a reserved keyword
sum$value // the $ is not a recognized character
3Times // because a variable name cannot begin with a number
number of units // because spaces are not allowed
🍅2.4 区分大小写
-
在使用CAPL编写时,一定要记住,对于用户定义的变量,小写字母和大写字母是不同的变量
-
下面三个变量是三个不同的变量
input_1
Input_1
INPUT_1 -
但是CAPL支持的关键字是不区分大小写的,比如 INT a; 和int a;是一样的。
🍅2.5 CAPL 关键字
- 关键字不能用来命名变量或函数。CAPL使用C编程中保留的关键字语言。但是,CAPL不支持一些常见的C关键字。
下面是保留关键字的列表,包括CAPL支持的和不支持的关键字 - 本图较老,emum和struct现在是支持的。
🍅2.6 CAPL 支持的数据类型
- 下表列出了支持的部分数据类型,不全,不过足以介绍CAPL支持的基本数据类型,以及所占的字节数,还有是是有符号数等等。message 和timer等是CAPL独有的数据类型,这里不描述
🍅2.7 变量声明
- CAPL 变量有局部变量和全局变量,在CAPL 中Variables中定义的是全局变量
- 数据类型float和double都是占8个字节,它们指定符合IEEE的64位浮点数标准,它们彼此兼容。
- 变量的初始化在声明期间是可选的,定义的时候如果没有初始化,
整形数据则默认是0;
char 型默认是null ;
message 类型默认的数据段是0;
定时器timer ,不需要初始化 - 下面的变量声明是合法的
char letter_a = “a”;
int number_days_in_year = 365;
message wake-up xxx; // 后面再说
timer one_second; // 定时器必须全局变量 后面再说
int j, k = 2; // 如果变量不初始化,默认j = 0
double x = 33.7;
char p;
🍅2.8 数据类型转换
- CAPL支持类型转换,隐形和显性都可以
-下面 第一个赋值语句使用隐形转换,即将1.6和1.7添加到结果3.3,但是sum是整形,所以自动截断,结果就是3
-下面 第二个赋值语句使用显性转换,即1+1 =2 ,最后结果就是2
int sum;
sum = 1.6 + 1.7;
sum = (int) 1.6 + (int) 1.7;
🍅2.9 常量
- 初始化一个变量意味着给它赋一个初始值或开始值。在CAPL中,这可以在同一行中完成变量声明。当值在声明期间赋值时,它们被视为常量
整形
- 整形可以是十进制和十六进制
int value = 20;
int value2 = 0x14;
浮点数
- 浮点数可以是十进制数,或者科学计数法,以下都是合法的
float value = 0.23;
float value2 = 23E-2;
2.1
2.1e0
3.1415
0.00034
22e+3
1E-6
字符
- 字符常量 是用单引号,括起来的一个字符
char value = ‘B’;
char value2 = ‘8’;
char value3 = ‘?’;
- CAPL支持使用ASCII字符集。上面的三个字符赋值可以用十六进制分别
char value = 0x42;
char value2 = 0x38;
char value3 = 0x3F;
字符串
- 字符串常量由一系列由双引号括起来的一个或多个连续字符组成。
- 字符串存储在char类型的数据元素数组中。最后一个元素包含空字符\\0,即用于指示字符串的结束。
- 要确保字符串数组定义时的大小总是字符串长度 + 1,因为结束符\\0也占用一个字符
char value[30] = “Here’s a string in C and CAPL”;
char value2[19] = “spaces are allowed”;
char value3[31] = “with a tab escape sequence \\t”;
- 如果已经定义过了一个字符串数组,不可以直接给它赋值的,下面代码时不允许的
char value3[31] ;
value3 = “with a tab escape sequence ”;
- 可行的一种方法,是通过CAPL自带的字符串操作函数实现
char value3[31] ;
strncpy(value3, “with a tab escape sequence ”, elcount(value3));
宏定义
- 在C语言中,下面代码是合法的,但是在CAPL中是不可以的。
#define TRUE 1
#define FALSE 0
🍅 2.10 数组
-
数组时同一种数据类型的集合,元素必须小于等于指定的大小
-
下面时26个字母,但是我们必须定义27个大小,因为数据类型时char , 结束符\\0要占一个字节
char alphabet[27] = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
我们通过下表索引可以获取数组中的数值,比如 alphabet[0] 就是 ‘A’ -
整形或者浮点型数组,大小可以和声明的元素数量一致,比如
int sample_data[4] = 100, 300, 500, 600 ; -
如果,定义时,数组没有完全舒适化,其余的用默认值0填充
int sample_data[10] = 100, 300, 500, 600 ; -
也可以定义二维数组
int M[4][5] =
10, 5, -3, 17, 82 ,
9, 0, 0, 8, -7 ,
32, 20, 1, 0, 14 ,
0, 0, 8, 7, 6
; -
要确定数组中元素的数量,可以使用elCount()函数,如下面的例子所示:
nt i, j;
for ( j = 0; j < elCount(array); j++ )
for ( i = 0; i <= elCount(array[j]); i++ )
. . .
🍅 2.11 枚举类型
- 枚举类型在CAPL中定义的方式与在C中完全相同
enum Colors Red, Green, Blue ; // 默认 从 0开始,每个元素+1
enum State State_Off = -1, State_On = 1 ; //可以指定值
- 定义完成后,可以直接使用enum的成员变量
on key 'c'
enum Colors Red, Green, Blue ; // 默认 从 0开始,每个元素+1
write("Colors red : %d",Red);
write("Colors Green : %d",Green);
//输出结果
Program / Model Colors red : 0
Program / Model Colors Green : 1
- 当对枚举类型初始化变量后,有两种方法给枚举变量赋值,如下脚本
- 可以通过 enum.Name() 可以获取变量当前值对应的元素名字
on key 'c'
enum Colors Red, Green, Blue ; // 默认 从 0开始,每个元素+1
enum Colors color; //定义枚举变量
color = Green;
# color = (enum Colors)1;//也可以通过 强制类型转换,将整形数据转为枚举类型赋值
write("colors is %s and value is : %d",color.Name(),color);
//输出结果
Program / Model colors is Green and value is : 1
🍅 2.12 结构体数据类型
- 结构体在CAPL中定义的方式与在C中完全相同
- -定义结构体变量时,完成初始化
on key 'c'
struct Data
int age;
long hight;
char name[50];
;
struct Data data = 12,150,"张三"; //结构体定义时,初始化
write("姓名:%s ; 年龄:%d ; 身高:%d",data.name,data.age,data.hight);
//输出结果
姓名:张三 ; 年龄:12 ; 身高:150
- 定义结构体变量时,没有初始化,后面再赋值
on key 'c'
struct Data
int age;
long hight;
char name[50];
;
struct Data data;
data.age = 15;
data.hight = 150;
strncpy(data.name,"张三",elcount(data.name));
write("姓名:%s ; 年龄:%d ; 身高:%d",data.name,data.age,data.hight);
//输出结果
姓名:张三 ; 年龄:15 ; 身高:150
🍅 2.13 message
- message 是CAPL独有的数据类型,可以用来仿真,改写,创建报文等,是CANoe 仿真测试的比较核心内容
- message ,有丰富的属性和相关方法,详情需要参考help文档了,不做深入探讨
- 一下代码将向总线上发送一帧ID = 100 的报文
on key 'c'
message 100 msg;
msg.DLC = 1;
msg.BYTE(0) = 0xff;
output(msg);
🍅 2.14 定时器
- 由于CAPL被设计为提供事件驱动的环境,计时器提供了一种简单的触发周期性的方法事件。CAPL允许设置无限多个用户定义的计时器。
- CAPL 提供两种定时器: 毫秒计时器(msTimer) 和 秒计时器(timer),必须再全局变量中定义定时器
msTimer tenth_second_clock;
Timer one_minute_clock;
-
使用一个定时器分一下三个步骤:
- 声明一个计时器变量
- 在事件过程(preStart 除外)或用户定义的函数中预先设置计时器
- 为该计时器定义一个on timer 事件
-
下面代码,是一个简单但是完整的毫秒定时器的使用方法,目的是案件‘a’触发后,开启定时器,20ms后发送 ID =100的报文
variables
msTimer myTimer; // creates a millisecond timer
message 100 msg; // creates message 100
on key ‘a’ // when the ‘a’ key is pressed
setTimer(myTimer,20); // set myTimer to 20 ms
on timer myTimer // when myTimer expires (after 20 ms)
output(msg); // output the message
- 周期定时器:下面代码周期为100ms的发送ID=0x555的报文
variables
message 0x555 msg1 = dlc = 1;
mstimer timer1; // define timer1
on start
setTimer(timer1, 100); // initialize timer to run for 100 msec
on timer timer1
msg1.byte(0) = msg1.byte(0) + 1; // increment the data
output(msg1); // output message
setTimer(timer1, 100); // reset the timer
- 如果定时器还没被触发,你可以通过setTimer() 函数,重置该定时器
- 如果定时器还没被触发,你也可以通过cancelTimer() 函数来取消该定时器
🍅 2.15 运算符
- CAPL的运算符大多数和C都一样,也进行了一些删减
- CAPL的运算符包括下面几大类
算数运算
赋值运算
关系运算
布尔运算
位运算
混合运算
2.15.1 算数运算
-
下图是CAPL支持的算数运算符,包括加减乘除,取模等,完全和C语言一样
-
下面一些算数运算符的使用
int x,y,z;
y = 8;
z = 4;
x = y + z; // Addition. Result = 12
x = y - z; // Subtraction. Result = 4
x = y * z; // Multiplication. Result = 32
x = y / z; // Division. Result = 2
x = z % y; // Modulo. Result = 4
x = y++; // Increment. Result = 9
x = z--; // Decrement. Result = 3
2.15.2 赋值运算符
- 下图是CAPL支持的赋值运算符,完全和C语言一样。
- 下面一些赋值运算符的简单使用
int y, z;
y = 8;
z = 4;
// each statement below is independent from the others
y += z; // Addition. Result: y = 12
y -= z; // Subtraction. Result: y = 4
y *= z; // Multiplication. Result: y = 32
y /= z; // Division. Result: y = 2
y %= z; // Modulo. Result: y = 0
y <<= 1; // Left-shift. Result: y = 16
y &= z; // AND. Result: y = 0 (binary arithmetic)
y |= z; // OR. Result: y = 12 (binary arithmetic)
y ^= z; // XOR. Result: y = 12 (binary arithmetic)
2.15.3 布尔运算符
- 下图是CAPL支持的布尔运算符,完全和C语言一样。
- 下面一些布尔运算符的简单使用
byte y, z;
y = 0x00;
z = 0x01;
if (!y) // test result is TRUE
if (!z) // test result is FALSE
if (y == 0 && z == 1) // test result is TRUE
if (y == 1 || z == 1) // test result is TRUE
2.15.4 比较运算符
-
下图是CAPL支持的比较运算符,完全和C语言一样。
-
下面一些比较运算符的简单使用
int y,z;
y = 8;
z = 4;
if (y == z) // test result is FALSE
if (y != z) // test result is TRUE
if (y <= z) // test result is FALSE
if (y >= z) // test result is TRUE
2.15.5 位运算符
- 下图是CAPL支持的位运算符,完全和C语言一样。
- 下面一些位运算符的简单使用
byte x, y, z;
y = 0x0AA; // y = 1010 1010
z = 0x05A; // z = 0101 1010
x = y & z; // AND result = 0000 1010
x = y | z; // OR result = 1111 1010
x = y ^ z; // XOR result = 1111 0000
x = y << 1; // shift left result = 0101 0100
x = y >> 1; // shift right result = 0101 0101
x = ~y; // 1’s complement result = 0101 0101
2.15.6 三目运算符
- 下图是CAPL支持的三目运算符,完全和C语言一样。
- 返回值:先求表达式 1 的值,如果为真,则执行表达式 2,并返回表达式 2 的结果;如果表达式 1 的值为假,则执行表达式 3,并返回表达式 3 的结果
byte x, y, z;
z = 3;
y = 5;
x = (y < z) ? z : y; // conditional result x = 5
2.15.7 其它运算符
- 下图是CAPL支持的运算符,[]可以用来数组索引取值, 点 表示结构体的成员,这在CAPL语言中很常见,不止用于结构体的成员变量,很多Object都有成员
- 比如message数据类型
message 100 msg;
msg.DLC = 1;
msg.BYTE(0) = 0xff;
output(msg);
2.15.8 不支持运算符
- 下图是CAPL支持的运算符,& 在CAPL中局部支持,可以用来地址传参,比如
void function(int & dl),
可以在函数内部改变传入的变量
2.15.9 运算符优先级
- 下图是我在网上找的C语言的运算符优先级,因为CAPL语言基于C,大部分都适用。
- 没有必要去记哈,贴出来给个参考。如果代码需要复合运算的时候,都加上括号,既方便阅读代码,也不用担心优先级的问题。
🍅 2.16 控制语句
- CAPL支持的控制语句和C语言中一样,包括 if else ,do ,while ,for 等
2.16.1 if 语句
if (expression) statement;
- if 括号内的表达式为真,或者非0,则执行if 下面的语句
- 如果没有花括号,则只执行if下面的第一行语句
int speed ;
speed = 80;
if (speed > 60)
write("line 1");//这一行语句受if语句控制
write("line 2");//这一行语句不受if语句控制
- 如果有花括号,执行if下面花括号的所有语句
int speed ;
speed = 80;
if (speed > 60)
//花括号内的语句都会执行
write("line 1");
write("line 2");
2.16.2 if else 语句
-
如果下面表达式为真或者非0,则执行语句块1,否则执行语句块2
if (expression) statement_1
else statement_2 -
if else 的典型用法
int speed ;
speed = 40;
if (speed > 60)
write("line 1");
else if(speed > 80)
write("line 2");
else
write("line 3");
2.16.3 Switch 语句
- 下面是switch 语句的伪代码表示:
switch (expression)
case value1: statement1; statement2; … break;
case value2: statement1; statement2; … break;
. . .
default: statement1; statement2; … break;
- switch (expression) 中的 expression应该是个 整形变量或者字符变量或者枚举类型变量
- case value1: 每个case分支中的value应该是个 整形或者字符常量,注意case value后面有个冒号
- default ,当所有分支都不能匹配的时候,会执行default内的代码
- 当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行。
- 不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止。
float value1, value2, result;
char operator;
...
switch ( operator )
case ‘+’: result = value1 + value2;
break;
case ‘-’: result = value1 – value2;
break;
case ‘*’: result = value1 * value2;
break;
case ‘/’: if ( value2 == 0) write (“Division by zero!”);
else result = value1 / value2;
break;
default: write (“Unknown operator.”);
break;
2.16.4 While 循环语句
- Capl 语言中 while 循环的语法:
while(condition)
statement(s);
- 在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。
- condition 可以是任意的表达式,当为任意非零值时都为 true。当条件为 true 时执行循环。 当条件为 false 时,退出循环.
int a = 10;
/* while 循环执行 */
while( a < 20 )
write("a 的值: %d\\n", a);
a++;
2.16.5 do…while 循环语句
- Capl 语言中 do…while 循环的语法:
do
statement(s);
while( condition );
- 在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。
- condition 可以是任意的表达式,当为任意非零值时都为 true。当条件为 true 时执行循环。 当条件为 false 时,退出循环.
- 不像 for 和 while 循环,它们是在循环头部测试循环条件。在 C 语言中,do…while 循环是在循环的尾部检查它的条件。
- do…while 循环与 while 循环类似,但是 do…while 循环会确保至少
执行一次循环
。 - 还要注意while 表达式最后是
分号
结尾的
int a = 10;
/* do 循环执行,在条件被测试之前至少执行一次 */
do
write("a 的值: %d\\n", a);
a = a + 1;
以上是关于带你入门的主要内容,如果未能解决你的问题,请参考以下文章