CAPL提供了非常多样的库函数供我们进行使用,其中有的函数是我们较为熟悉的,如settimer,output等,这些我们已经知道函数的用法和功能了,但是,在实际使用CANoe中,我们更多的时候关心的是总线上的数据以及这些数据的处理,所以,我们有必要知道一些其他的常用函数。
一、使用CAPL函数帮助手册
CAPL的帮助手册中有着众多函数的用法及其示例,我们先来看下如何使用CAPL的帮助手册(函数库)
打开CAPL函数库帮助手册
在CAPL浏览器中找到Layout菜单栏,点击红框中的CAPL Function,随后CAPL浏览器的右侧就会出现CAPL函数帮助界面
点击CAPL Function切换到函数帮助手册视图,可以看到上面有几大函数的分类
任意点击一个分类展开这个分类下的函数
我们可以看到,通用分组下有着我们先前已经使用过的几个最常用的函数
canceltimer、settimer、output和write。在前文中我们已经对这几个函数进行了使用,比如
output(meaageframe);
但是我们并没有深究,并不知道这些函数到底应该怎么使用,只是我在文章中对他的使用进行了说明,现在,我们以CAPL帮助手册的视角来学习一下这个函数该怎么使用。
这里,我已settimer函数为例子,鼠标点击settimer函数,右下角就会出现类似红框的界面(CANoe版本不同,界面会稍微有一点差别,总体上是一样的),随后我们点击右边的问号图标,打开这个函数的说明。
在Function Syntax中我们可以看到这个函数具有三种重载形式(不懂重载什么意思的,可以简单的认为就是这个函数的几种不同的用法)
分别是
这个函数可以接受两个参数也可以接受三个参数
下面有CANoe官网给的简单示例,告知这个函数的简单用法。
从参数列表中,可以看到这个函数的几个参数
mstimer t:一个mstimer定时器
timer t:一个秒级别定时器
duration:定时器持续的时间,即定时器超时时间
durationsec:定时器超时时间的秒
durationnanosec:定时器超时时间的纳秒
这三种 用法我们都有涉及,接着以一小段代码进行下简单示例
variables
{
message 0x123 testmsg;
msTimer TaskmsTimer;//ms定时器
timer TaskTimer;//s定时器
timer TaskTimer2;//s定时器2
}
on key'A'
{
setTimer(TaskmsTimer,500);//设置定时器500ms超时
}
on key'B'
{
setTimer(TaskTimer,1);//设置定时器1S超时
}
on key'C'
{
setTimer(TaskTimer2,1,500*1000*1000);//500纳秒*1000*1000 即500ms 1s+500ms,即1.5s执行一次
}
on key'D'
{
cancelTimer(TaskmsTimer);//关闭定时器
cancelTimer(TaskTimer);
cancelTimer(TaskTimer2);
}
on timer TaskmsTimer
{
setTimer(TaskmsTimer,500);
output(testmsg);
}
on timer TaskTimer
{
setTimer(TaskTimer,1);
output(testmsg);
}
on timer TaskTimer2
{
setTimer(TaskTimer2,1,500*1000*1000);//500纳秒*1000*1000 即500ms 1s+500ms,即1.5s执行一次
output(testmsg);
}
运行工程,先按下大写字母A,我们通过trace窗口看看0x123的周期
周期为500ms,符合我们在A事件中写的逻辑代码。使用D关闭定时器之后,我们再按下B看下现象
报文周期为1S,也是我们想要的效果。再次使用D关闭定时器之后,我们按下C看看
报文周期为1.5s,符合我们填写的参数。
至此,我们已经通过CAPL函数库学会了settimer函数的使用,是否也掌握了CAPL函数库的使用呢?
CAPL函数库中有着非常非常多的功能函数,这里就不再继续教大家怎么去看了,各位可以自行查阅CAPL函数帮助手册
如图,从左侧点击需要查看的大类展开,随后再次展开里面的小项即可对CAPL中的所有帮助内容进行查看了。
或者,可以在帮助手册中进行关键字的搜索。
根据关键词快速搜索到相关的函数。
二、CAN总线类函数
CAPL中提供了非常多的用于CAN总线的函数
这里只对常用的几个进行介绍
canGetDataLength(返回指定CAN报文的长度)
函数原型:long canGetDataLength(message msg);
用法示例
on message *
{
byte len;
len = canGetDataLength(this);//this指针,指代事件本身,在这里指代这个收到的CAN报文。
write("收到的CAN报文长度为:%d",len);
}
在这里,我使用CAN IG模块向总线上发送一条CAN报文
在CAN总线上,点击红色连接线,右键鼠标,选择新建一个CAN IG模块。
左键双击新建的CAN IG节点,进入CAN IG界面。
在CAN IG界面右键选择添加一个CAN帧
给新建的CAN帧一个id 我这里是0x321,可以看到我的dlc为8
随后,启动工程。点击图中的红色箭头手动发送一次0x321
在write窗口可以看到,代码中打印出了总线上收到的CAN帧0x321的长度为8,正确的。
我们再次在CAN IG中修改这个dlc为5看一下
再次按下按钮手动发送一帧0x321
write中又打印了刚刚收到的CAN帧的长度为5。
以上就是这个函数的用法。
getMessageID(返回CAN报文的ID)
函数原型:
dword getMessageID(char messageName[]); // form 1
dword getMessageID(char messageName[], char dbName[]); // form 2
用法示例:
on message *
{
word id;
id = getMessageID("Test");
write("收到的CAN报文id为:%d",id);
}
注意,此函数的参数的message需要在dbc中有定义。
我在dbc中定义了一个名为Test的CAN帧,ID为0x123。
随后,在CAN IG中添加这个报文并发送试一下
选择从dbc中添加报文。
添加完成后,启动工程发送试一下
解析到了报文ID、
三、LIN总线类函数
linStopScheduler 用于停止CANoe自动运行LIN的调度表,常用于需要暂停发送LIN报文的场景,比如需要停发LIN报文一段时间后测试ecu是否休眠,常用此函数。
函数原型:void linStopScheduler();
linStartScheduler 用于开始CANoe自动运行LIN的调度表
函数原型:void linStartScheduler();
linChangeSchedtable 用于切换运行的调度表
函数原型:
long linChangeSchedTable(dword tableIndex);
long linChangeSchedTable(dword tableIndex, dword slotIndex);
long linChangeSchedTable(dword tableIndex, dword slotIndex, dword onSlotIndex);
常用于在APP调度表和诊断调度表中互相切换。
linGotoSleep LIN总线休眠函数
函数原型:long linGotoSleep();
本质上调用该函数后,会由CANoe自动向总线上发送一个LIN的通用休眠帧。
linWakeup LIN总线唤醒函数,调用该函数本质上是向LIN总线上发送一个250~5000us的低电平。
long linWakeup(); // form 1
linWakeup(dword ttobrk, dword wakeupSignalCount, dword widthInMicSec); // from 2
linGetDlc 获取指定LIN帧的长度
函数原型:long linGetDlc(long frameID);
linGetChecksum 获取指定LIN帧或者错误帧的校验和
函数原型
byte linGetChecksum(linFrame linFrame); form 1
byte linGetChecksum(linCSError linCsError); // form 2
四、数学运算类函数
_max 返回数据中的最大值
函数原型:
long _max(long x, long y); // form 1
dword _max(dword x, dword y); // form 2
int64 _max(int64 x, int64 y); // form 3
qword _max(qword x, qword y); // form 4
float _max(float x, float y); // form 5
用法示例
on key' '
{
byte max;
write("max=%d",_max(36,85));
}
_min 返回数据中的最小值
函数原型:
long _min(long x, long y); // form 1
dword _min(dword x, dword y); // form 2
int64 _min(int64 x, int64 y); // form 3
qword _min(qword x, qword y); // form 4
float _min(float x, float y); // form 5
示例:
on key' '
{
float min;
write("min=%f",_min(36.6,_min(58.2,12.3)));
}
可以看到,返回了最小值为12.3
_pow 返回x的y次幂
函数原型:double _pow(double x, double y);
用法示例
on key' '
{
float res;
write("res=%f",_pow(3,4));
}
random 产生指定范围的随机数
函数原型:dword random(dword num);
用法示例
on key' '
{
dword num;
num = random(100);//产生0到100之间的额随机数
write("本次产生的随机数为%d",num);
}
其他的数学运算函数,大家就自己去使用吧
五、字符串处理类函数
strlen 返回字符串的真实长度
函数原型 long strlen(char s[]);
on key' '
{
char str[16] = "你好世界";
write("字符串str的长度为%d",strlen(str));
}
我的CAPL中编码方式为utf8,而在utf8编码中,一个中文占3个字节,这里总共四个中文字符,所以总长占12字节,返回值正确。
strnact 字符串黏贴函数,用于将一个字符串粘贴至另一个字符串的末尾。
函数原型:void strncat(char dest[], char src[], long len);
on key' '
{
char str[16] = "你好世界";
char isp[32] = "hello word";
strncat(isp,str,elcount(isp));
write("字符串isp的内容为%s",isp);
}
可以看到,isp已经变成了hello word你好世界,str被黏贴到了isp后面。
strncpy 字符串拷贝函数,用于把一个字符串复制到另一个字符串中。
函数原型:void strncpy(char dest[], char src[], long max);
on key' '
{
char str[16] = "你好世界";
char isp[32] = "hello word";
strncpy(isp,str,elcount(isp));
write("字符串isp的内容为%s",isp);
}
可以看到,经过strncpy操作后,isp的内容由"hello word"变为了"你好世界",str的数据被拷贝到了isp中。
strncmp 判断字符串是否相等
函数原型:
long strncmp(char s1[], char s2[], long len); // form 1
long strncmp(char s1[], char s2[], long s2offset, long len); // form 2
on key' '
{
char str[16] = "你好世界";
char isp[32] = "你好世界";
byte result;
result = strncmp(isp,str,elcount(isp));
if(result == 0)
write("字符串str与isp相等");
}
这里定的了str和isp,数据是一样的,仅长度不同,在数据上他们是相等的,所以返回了0,即这两个字符串相等。
ltoa 将数字以字符串形式显示,即将数字转换为字符串。
函数原型:
void ltoa(long val, char s[], long base);
on key' '
{
word num = 365;
char str[4];
ltoa(num,str,10);
write("str=%s",str);
}
可以看到,我已经把num转换成了字符串,使用的%s输出。
atol 将字符串转换为数字,与ltoa相反。
函数原型:long atol(char s[]);
on key' '
{
char str[5] = "4567";
word num;
num = atol(str);
write("num=%d",num);
}
可以看到,调用这个函数我们把字符串“4567”转换成了数字4567
_atoi64 将字符数组转换为64位整数
函数原型:int64 _atoi64(char s[]);
on key' '
{
char numstr[10] = "123456789";
int64 num;
num = _atoi64(numstr);
write("num = %ld",num);
}
可以看到,这里把字符数组(字符串“123456789”)转换成了一个64位整数。
六、其他常用函数
stop 结束正在运行的CANoe工程。
函数原型:void stop();
getSignal 获取指定的信号的物理值。
函数原型:float getSignal(Signal aSignal); // form 1
此函数调用的结果等同于直接使用$来取信号。
setSignal 设置指定的信号的物理值
函数原型:void setSignal(Signal aSignal, double aValue); // form 1
此函数调用的结果等同于直接使用$取信号给信号赋值。
putvalue 给环境变量赋值(高版本中已经废弃环境变量,此函数也随之被废弃)
用法为:putvalue(EnvVar,Num);其中envvar是环境变量的变量名,num是要赋予的值。
getvalue 获取环境变量的值(高版本中已经废弃)
函数原型:float getvalue(Envvar);
系统变量赋值函数
使用对应的函数可以为对应的类型的系统变量进行赋值。
比如,为一个double类型的系统变量赋值
使用 sysSetVariableFloat
函数原型:
long sysSetVariableFloat(char namespace[], char variable[], float value); // form 1
long sysSetVariableFloat(SysVarName, float value); // form 2
注意:使用此类函数,在使用系统变量作为参数时,需要先指定命名空间,否则代码会报错。