- ?? 我是螞蟻小兵,專注于車載診斷領(lǐng)域,尤其擅長于對CANoe工具的使用
- ?? 尋找組織 ,答疑解惑,摸魚聊天,博客源碼,點(diǎn)擊加入??【相親相愛一家人】
- ?? 玩轉(zhuǎn)CANoe,博客目錄大全,點(diǎn)擊跳轉(zhuǎn)??
??前言
-
?? 本章內(nèi)容,面向CAPL初學(xué)者,超過兩萬字,超全超詳細(xì)。
-
?? 本節(jié)內(nèi)容大量引用,翻譯下面的Vector 官方文檔:capl_programming ,資料我放在下方公眾號網(wǎng)盤了,有需自取!
??1 CAPL 簡介
-
CAPL(發(fā)音為“kapple”),是 Communication Access Programming Language 的縮寫。CAPL是基于C語言開發(fā)的,專門用于CANalyzer和CANoe工具環(huán)境,但是CAPL簡化了C語言,移除了復(fù)雜的指針概念,和一些不常用的關(guān)鍵字等,也融入了一些C++的概念,比如函數(shù)重載等。就學(xué)習(xí)難度而言 CAPL < C< C++。
-
CANalyzer或CANoe工具本身無需CAPL程序,就足以執(zhí)行簡單的測量和分析。采用CAPL程序,大大擴(kuò)展了CAN通信的測量和分析。
如果沒有CAPL,該工具無法執(zhí)行的是涉及計(jì)時(shí)的分析。CAPL可以使分析更加高效 -
CAPL 腳本是基于事件驅(qū)動的,和常規(guī)語言不同,CAPL沒有 main()函數(shù),沒有程序入口,任何事件都有可能觸發(fā)CAPL腳本的執(zhí)行,比如,按鍵事件,定時(shí)器事件,執(zhí)行測試等;如果沒有事件發(fā)生,那么CAPL程序是“閑置的”。
-
任何語言都需要編譯之后才能運(yùn)行,我們編寫CAPL 的IDE叫做 CAPL Browser ,是CNAoe 整個(gè)開發(fā)環(huán)境的一部分組件;因?yàn)镃APL Browser的整體結(jié)構(gòu)基于事件的概念,并且是專門組織的圍繞不同的事件類,軟件開發(fā)過程比傳統(tǒng)的組織要簡單得多C程序。關(guān)于CAPL的事件結(jié)構(gòu)更詳細(xì)的解讀,參考后面章節(jié)博客內(nèi)容。
??2 CAPL 語法基礎(chǔ)
??2.1 CAPL和C語言的主要不同點(diǎn)
- 下圖可以看出,C語言支持很多概念,CAPL都舍棄掉了,或者只取其一小部分支持,讓CAPL語言更加簡便和易懂
- 比如CAPL是基礎(chǔ)事件驅(qū)動的,所以不需要main()函數(shù)入口
- 持指針操作,宏定義,頭文件都不在支持
- 下圖有點(diǎn)老,博主基于CANoe 11版本,枚舉和結(jié)構(gòu)體類型都是支持的。
- 在c語言中,使用函數(shù)之前,必須要進(jìn)行聲明,而CAPL是不需要的。
Note:
1,在CAPL中,默認(rèn)所有的局部變量都是靜態(tài)的,在C語言中,需要用關(guān)鍵字static 修飾的變量才是靜態(tài)的。這一點(diǎn)新手在寫腳本要特別注意 點(diǎn)擊,了解 CAPL腳本中關(guān)于 局部變量 容易忽略的一點(diǎn)
2,void 在CAPL中只支持函數(shù)返回值類型,表示函數(shù)沒有返回值
3,CAPL中使用了一些標(biāo)準(zhǔn)的C函數(shù)。這些函數(shù)通常是數(shù)學(xué)函數(shù)或字符串函數(shù)(例如,abs(),strncpy())已經(jīng)在CAPL內(nèi)部預(yù)定義了。
4,CAPL沒有完整的ANSI C標(biāo)準(zhǔn)庫,但它有CAPL特有的庫,稱為CAPL dll。dll編程需要有一定的編程經(jīng)驗(yàn)
5,字符串?dāng)?shù)據(jù)類型在CAPL中不支持;但是,您可以使用字符數(shù)組(例如,char temp[6]= " Hello "??。
??2.1 CAPL和C語言中等價(jià)的函數(shù)
- 對于C程序員來說,了解一些等價(jià)的函數(shù)是很有幫助的。下面是一個(gè)類似的簡明列表函數(shù),但有關(guān)CAPL函數(shù)如何使用的更多詳細(xì)信息,請參閱CAPL函數(shù)參考手冊。
??2.2 注釋
- CAPL 的注釋方式和大多數(shù)語言都一樣,都是通過 // 或者 /**/ 來實(shí)現(xiàn)的,下面四種注釋方法都是合法的。
- CAPL Brower中注釋代碼的默認(rèn)快捷鍵 選中你要注釋的代碼,先按住組合鍵 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 變量的命名規(guī)范
-
變量名、函數(shù)名和數(shù)組名可以由字母和數(shù)字和下劃線組成,但是首字母不能是數(shù)字
-
下面的命名都是合法的:
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 區(qū)分大小寫
-
在使用CAPL編寫時(shí),一定要記住,對于用戶定義的變量,小寫字母和大寫字母是不同的變量
-
下面三個(gè)變量是三個(gè)不同的變量
input_1
Input_1
INPUT_1 -
但是CAPL支持的關(guān)鍵字是不區(qū)分大小寫的,比如 INT a; 和int a;是一樣的。
??2.5 CAPL 關(guān)鍵字
- 關(guān)鍵字不能用來命名變量或函數(shù)。CAPL使用C編程中保留的關(guān)鍵字語言。但是,CAPL不支持一些常見的C關(guān)鍵字。
下面是保留關(guān)鍵字的列表,包括CAPL支持的和不支持的關(guān)鍵字 - 本圖較老,emum和struct現(xiàn)在是支持的。
??2.6 CAPL 支持的數(shù)據(jù)類型
- 下表列出了支持的部分?jǐn)?shù)據(jù)類型,不全,不過足以介紹CAPL支持的基本數(shù)據(jù)類型,以及所占的字節(jié)數(shù),還有是是有符號數(shù)等等。message 和timer等是CAPL獨(dú)有的數(shù)據(jù)類型,這里不描述
??2.7 變量聲明
- CAPL 變量有局部變量和全局變量,在CAPL 中Variables中定義的是全局變量
- 數(shù)據(jù)類型float和double都是占8個(gè)字節(jié),它們指定符合IEEE的64位浮點(diǎn)數(shù)標(biāo)準(zhǔn),它們彼此兼容。
- 變量的初始化在聲明期間是可選的,定義的時(shí)候如果沒有初始化,
整形數(shù)據(jù)則默認(rèn)是0;
char 型默認(rèn)是null ;
message 類型默認(rèn)的數(shù)據(jù)段是0;
定時(shí)器timer ,不需要初始化 - 下面的變量聲明是合法的
char letter_a = “a”;
int number_days_in_year = 365;
message wake-up xxx; // 后面再說
timer one_second; // 定時(shí)器必須全局變量 后面再說
int j, k = 2; // 如果變量不初始化,默認(rèn)j = 0
double x = 33.7;
char p;
??2.8 數(shù)據(jù)類型轉(zhuǎn)換
- CAPL支持類型轉(zhuǎn)換,隱形和顯性都可以
-下面 第一個(gè)賦值語句使用隱形轉(zhuǎn)換,即將1.6和1.7添加到結(jié)果3.3,但是sum是整形,所以自動截?cái)啵Y(jié)果就是3
-下面 第二個(gè)賦值語句使用顯性轉(zhuǎn)換,即1+1 =2 ,最后結(jié)果就是2
int sum;
sum = 1.6 + 1.7;
sum = (int) 1.6 + (int) 1.7;
??2.9 常量
- 初始化一個(gè)變量意味著給它賦一個(gè)初始值或開始值。在CAPL中,這可以在同一行中完成變量聲明。當(dāng)值在聲明期間賦值時(shí),它們被視為常量
整形
- 整形可以是十進(jìn)制和十六進(jìn)制
int value = 20;
int value2 = 0x14;
浮點(diǎn)數(shù)
- 浮點(diǎn)數(shù)可以是十進(jìn)制數(shù),或者科學(xué)計(jì)數(shù)法,以下都是合法的
float value = 0.23;
float value2 = 23E-2;
2.1
2.1e0
3.1415
0.00034
22e+3
1E-6
字符
- 字符常量 是用單引號,括起來的一個(gè)字符
char value = ‘B’;
char value2 = ‘8’;
char value3 = ‘?’;
- CAPL支持使用ASCII字符集。上面的三個(gè)字符賦值可以用十六進(jìn)制分別
char value = 0x42;
char value2 = 0x38;
char value3 = 0x3F;
字符串
- 字符串常量由一系列由雙引號括起來的一個(gè)或多個(gè)連續(xù)字符組成。
- 字符串存儲在char類型的數(shù)據(jù)元素?cái)?shù)組中。最后一個(gè)元素包含空字符\0,即用于指示字符串的結(jié)束。
- 要確保字符串?dāng)?shù)組定義時(shí)的大小總是字符串長度 + 1,因?yàn)榻Y(jié)束符\0也占用一個(gè)字符
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”;
- 如果已經(jīng)定義過了一個(gè)字符串?dāng)?shù)組,不可以直接給它賦值的,下面代碼時(shí)不允許的
char value3[31] ;
value3 = “with a tab escape sequence ”;
- 可行的一種方法,是通過CAPL自帶的字符串操作函數(shù)實(shí)現(xiàn)
char value3[31] ;
strncpy(value3, “with a tab escape sequence ”, elcount(value3));
宏定義
- 在C語言中,下面代碼是合法的,但是在CAPL中是不可以的。
#define TRUE 1
#define FALSE 0
?? 2.10 數(shù)組
-
數(shù)組時(shí)同一種數(shù)據(jù)類型的集合,元素必須小于等于指定的大小
-
下面時(shí)26個(gè)字母,但是我們必須定義27個(gè)大小,因?yàn)閿?shù)據(jù)類型時(shí)char , 結(jié)束符\0要占一個(gè)字節(jié)
char alphabet[27] = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
我們通過下表索引可以獲取數(shù)組中的數(shù)值,比如 alphabet[0] 就是 ‘A’ -
整形或者浮點(diǎn)型數(shù)組,大小可以和聲明的元素?cái)?shù)量一致,比如
int sample_data[4] = { 100, 300, 500, 600 }; -
如果,定義時(shí),數(shù)組沒有完全舒適化,其余的用默認(rèn)值0填充
int sample_data[10] = { 100, 300, 500, 600 }; -
也可以定義二維數(shù)組
int M[4][5] = {
{ 10, 5, -3, 17, 82 },
{ 9, 0, 0, 8, -7 },
{ 32, 20, 1, 0, 14 },
{ 0, 0, 8, 7, 6 }
}; -
要確定數(shù)組中元素的數(shù)量,可以使用elCount()函數(shù),如下面的例子所示:
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 }; // 默認(rèn) 從 0開始,每個(gè)元素+1
enum State { State_Off = -1, State_On = 1 }; //可以指定值
- 定義完成后,可以直接使用enum的成員變量
on key 'c'
{
enum Colors { Red, Green, Blue }; // 默認(rèn) 從 0開始,每個(gè)元素+1
write("Colors red : %d",Red);
write("Colors Green : %d",Green);
}
//輸出結(jié)果
Program / Model Colors red : 0
Program / Model Colors Green : 1
- 當(dāng)對枚舉類型初始化變量后,有兩種方法給枚舉變量賦值,如下腳本
- 可以通過 enum.Name() 可以獲取變量當(dāng)前值對應(yīng)的元素名字
on key 'c'
{
enum Colors { Red, Green, Blue }; // 默認(rèn) 從 0開始,每個(gè)元素+1
enum Colors color; //定義枚舉變量
color = Green;
# color = (enum Colors)1;//也可以通過 強(qiáng)制類型轉(zhuǎn)換,將整形數(shù)據(jù)轉(zhuǎn)為枚舉類型賦值
write("colors is %s and value is : %d",color.Name(),color);
//輸出結(jié)果
Program / Model colors is Green and value is : 1
}
?? 2.12 結(jié)構(gòu)體數(shù)據(jù)類型
- 結(jié)構(gòu)體在CAPL中定義的方式與在C中完全相同
- -定義結(jié)構(gòu)體變量時(shí),完成初始化
on key 'c'
{
struct Data
{
int age;
long hight;
char name[50];
};
struct Data data = {12,150,"張三"}; //結(jié)構(gòu)體定義時(shí),初始化
write("姓名:%s ; 年齡:%d ; 身高:%d",data.name,data.age,data.hight);
//輸出結(jié)果
姓名:張三 ; 年齡:12 ; 身高:150
}
- 定義結(jié)構(gòu)體變量時(shí),沒有初始化,后面再賦值
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);
//輸出結(jié)果
姓名:張三 ; 年齡:15 ; 身高:150
}
?? 2.13 message
- message 是CAPL獨(dú)有的數(shù)據(jù)類型,可以用來仿真,改寫,創(chuàng)建報(bào)文等,是CANoe 仿真測試的比較核心內(nèi)容
- message ,有豐富的屬性和相關(guān)方法,詳情需要參考help文檔了,不做深入探討
- 一下代碼將向總線上發(fā)送一幀ID = 100 的報(bào)文
on key 'c'
{
message 100 msg;
msg.DLC = 1;
msg.BYTE(0) = 0xff;
output(msg);
}
?? 2.14 定時(shí)器
- 由于CAPL被設(shè)計(jì)為提供事件驅(qū)動的環(huán)境,計(jì)時(shí)器提供了一種簡單的觸發(fā)周期性的方法事件。CAPL允許設(shè)置無限多個(gè)用戶定義的計(jì)時(shí)器。
- CAPL 提供兩種定時(shí)器: 毫秒計(jì)時(shí)器(msTimer) 和 秒計(jì)時(shí)器(timer),必須再全局變量中定義定時(shí)器
msTimer tenth_second_clock;
Timer one_minute_clock;
-
使用一個(gè)定時(shí)器分一下三個(gè)步驟:
- 聲明一個(gè)計(jì)時(shí)器變量
- 在事件過程(preStart 除外)或用戶定義的函數(shù)中預(yù)先設(shè)置計(jì)時(shí)器
- 為該計(jì)時(shí)器定義一個(gè)on timer 事件
-
下面代碼,是一個(gè)簡單但是完整的毫秒定時(shí)器的使用方法,目的是案件‘a(chǎn)’觸發(fā)后,開啟定時(shí)器,20ms后發(fā)送 ID =100的報(bào)文
variables
{
msTimer myTimer; // creates a millisecond timer
message 100 msg; // creates message 100
}
on key ‘a(chǎn)’ // when the ‘a(chǎn)’ 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
}
- 周期定時(shí)器:下面代碼周期為100ms的發(fā)送ID=0x555的報(bào)文
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
}
- 如果定時(shí)器還沒被觸發(fā),你可以通過setTimer() 函數(shù),重置該定時(shí)器
- 如果定時(shí)器還沒被觸發(fā),你也可以通過cancelTimer() 函數(shù)來取消該定時(shí)器
?? 2.15 運(yùn)算符
- CAPL的運(yùn)算符大多數(shù)和C都一樣,也進(jìn)行了一些刪減
- CAPL的運(yùn)算符包括下面幾大類
算數(shù)運(yùn)算
賦值運(yùn)算
關(guān)系運(yùn)算
布爾運(yùn)算
位運(yùn)算
混合運(yùn)算
2.15.1 算數(shù)運(yùn)算
-
下圖是CAPL支持的算數(shù)運(yùn)算符,包括加減乘除,取模等,完全和C語言一樣
-
下面一些算數(shù)運(yùn)算符的使用
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 賦值運(yùn)算符
- 下圖是CAPL支持的賦值運(yùn)算符,完全和C語言一樣。
- 下面一些賦值運(yùn)算符的簡單使用
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 布爾運(yùn)算符
- 下圖是CAPL支持的布爾運(yùn)算符,完全和C語言一樣。
- 下面一些布爾運(yùn)算符的簡單使用
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 比較運(yùn)算符
-
下圖是CAPL支持的比較運(yùn)算符,完全和C語言一樣。
-
下面一些比較運(yùn)算符的簡單使用
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 位運(yùn)算符
- 下圖是CAPL支持的位運(yùn)算符,完全和C語言一樣。
- 下面一些位運(yùn)算符的簡單使用
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 三目運(yùn)算符
- 下圖是CAPL支持的三目運(yùn)算符,完全和C語言一樣。
- 返回值:先求表達(dá)式 1 的值,如果為真,則執(zhí)行表達(dá)式 2,并返回表達(dá)式 2 的結(jié)果;如果表達(dá)式 1 的值為假,則執(zhí)行表達(dá)式 3,并返回表達(dá)式 3 的結(jié)果
byte x, y, z;
z = 3;
y = 5;
x = (y < z) ? z : y; // conditional result x = 5
2.15.7 其它運(yùn)算符
- 下圖是CAPL支持的運(yùn)算符,[]可以用來數(shù)組索引取值, 點(diǎn) 表示結(jié)構(gòu)體的成員,這在CAPL語言中很常見,不止用于結(jié)構(gòu)體的成員變量,很多Object都有成員
- 比如message數(shù)據(jù)類型
message 100 msg;
msg.DLC = 1;
msg.BYTE(0) = 0xff;
output(msg);
2.15.8 不支持運(yùn)算符
- 下圖是CAPL支持的運(yùn)算符,& 在CAPL中局部支持,可以用來地址傳參,比如
void function(int & dl),
可以在函數(shù)內(nèi)部改變傳入的變量
2.15.9 運(yùn)算符優(yōu)先級
- 下圖是我在網(wǎng)上找的C語言的運(yùn)算符優(yōu)先級,因?yàn)镃APL語言基于C,大部分都適用。
- 沒有必要去記哈,貼出來給個(gè)參考。如果代碼需要復(fù)合運(yùn)算的時(shí)候,都加上括號,既方便閱讀代碼,也不用擔(dān)心優(yōu)先級的問題。
?? 2.16 控制語句
- CAPL支持的控制語句和C語言中一樣,包括 if else ,do ,while ,for 等
2.16.1 if 語句
if (expression) statement;
- if 括號內(nèi)的表達(dá)式為真,或者非0,則執(zhí)行if 下面的語句
- 如果沒有花括號,則只執(zhí)行if下面的第一行語句
int speed ;
speed = 80;
if (speed > 60)
write("line 1");//這一行語句受if語句控制
write("line 2");//這一行語句不受if語句控制
- 如果有花括號,執(zhí)行if下面花括號的所有語句
int speed ;
speed = 80;
if (speed > 60)
{
//花括號內(nèi)的語句都會執(zhí)行
write("line 1");
write("line 2");
}
2.16.2 if else 語句
-
如果下面表達(dá)式為真或者非0,則執(zhí)行語句塊1,否則執(zhí)行語句塊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應(yīng)該是個(gè) 整形變量或者字符變量或者枚舉類型變量
- case value1: 每個(gè)case分支中的value應(yīng)該是個(gè) 整形或者字符常量,注意case value后面有個(gè)冒號
- default ,當(dāng)所有分支都不能匹配的時(shí)候,會執(zhí)行default內(nèi)的代碼
- 當(dāng)遇到 break 語句時(shí),switch 終止,控制流將跳轉(zhuǎn)到 switch 語句后的下一行。
- 不是每一個(gè) case 都需要包含 break。如果 case 語句不包含 break,控制流將會 繼續(xù) 后續(xù)的 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 循環(huán)語句
- Capl 語言中 while 循環(huán)的語法:
while(condition)
{
statement(s);
}
- 在這里,statement(s) 可以是一個(gè)單獨(dú)的語句,也可以是幾個(gè)語句組成的代碼塊。
- condition 可以是任意的表達(dá)式,當(dāng)為任意非零值時(shí)都為 true。當(dāng)條件為 true 時(shí)執(zhí)行循環(huán)。 當(dāng)條件為 false 時(shí),退出循環(huán).
int a = 10;
/* while 循環(huán)執(zhí)行 */
while( a < 20 )
{
write("a 的值: %d\n", a);
a++;
}
2.16.5 do…while 循環(huán)語句
- Capl 語言中 do…while 循環(huán)的語法:
do
{
statement(s);
}while( condition );
- 在這里,statement(s) 可以是一個(gè)單獨(dú)的語句,也可以是幾個(gè)語句組成的代碼塊。
- condition 可以是任意的表達(dá)式,當(dāng)為任意非零值時(shí)都為 true。當(dāng)條件為 true 時(shí)執(zhí)行循環(huán)。 當(dāng)條件為 false 時(shí),退出循環(huán).
- 不像 for 和 while 循環(huán),它們是在循環(huán)頭部測試循環(huán)條件。在 C 語言中,do…while 循環(huán)是在循環(huán)的尾部檢查它的條件。
- do…while 循環(huán)與 while 循環(huán)類似,但是 do…while 循環(huán)會確保至少
執(zhí)行一次循環(huán)
。 - 還要注意while 表達(dá)式最后是
分號
結(jié)尾的
int a = 10;
/* do 循環(huán)執(zhí)行,在條件被測試之前至少執(zhí)行一次 */
do
{
write("a 的值: %d\n", a);
a = a + 1;
}while( a < 20 );
2.16.6 for 循環(huán)語句
- Capl 語言中 for 循環(huán)的語法:
for ( init; condition; increment )
{
statement(s);
}
-
下面是 for 循環(huán)的控制流:
1,init 會首先被執(zhí)行,且只會執(zhí)行一次。您也可以不在這里寫任何語句,只要有一個(gè)分號出現(xiàn)即可。CAPL語句不允許在這個(gè)位置定義新的變量
,而C語言是可以的
2,接下來,會判斷 condition。如果為真,則執(zhí)行循環(huán)主體。如果為假,則不執(zhí)行循環(huán)主體,且控制流會跳轉(zhuǎn)到緊接著 for 循環(huán)的下一條語句。切記不要讓condition永遠(yuǎn)為真,否則會是個(gè)死循環(huán)
的
3,在執(zhí)行完 for 循環(huán)主體后,控制流會跳回上面的 increment 語句。該語句允許您更新循環(huán)控制變量。該語句可以留空,只要在條件后有一個(gè)分號出現(xiàn)即可。
4,條件再次被判斷。如果為真,則執(zhí)行循環(huán),這個(gè)過程會不斷重復(fù)(循環(huán)主體,然后增加步值,再然后重新判斷條件)。在條件變?yōu)榧贂r(shí),for 循環(huán)終止。 -
下面三個(gè)代碼都是可以的
int a ;
/* for 循環(huán)執(zhí)行 */
for( a = 10; a < 20; a = a + 1 )
{
write("a 的值: %d\n", a);
}
int a ;
a =10;
/* for 循環(huán)執(zhí)行 */
for( ; a < 20; a = a + 1 ) //第一個(gè)表達(dá)式為空
{
write("a 的值: %d\n", a);
}
int a ;
a =10;
/* for 循環(huán)執(zhí)行 */
for( ; a < 20; )//第1,3個(gè)表達(dá)式為空
{
write("a 的值: %d\n", a);
a = a + 1;
}
2.16.7 break 語句
-
Capl 語言中 break 語句有以下兩種用法:
當(dāng) break 語句出現(xiàn)在一個(gè)循環(huán)內(nèi)時(shí),循環(huán)會立即終止,且程序流將繼續(xù)執(zhí)行緊接著循環(huán)的下一條語句。
它可用于終止 switch 語句中的一個(gè) case。 -
如果您使用的是嵌套循環(huán)(即一個(gè)循環(huán)內(nèi)嵌套另一個(gè)循環(huán)),break 語句會停止執(zhí)行最內(nèi)層的循環(huán),然后開始執(zhí)行該塊之后的下一行代碼。
-
下圖是break語句在循環(huán)語句中的使用,和退出循環(huán)的過程
int a = 10;
/* while 循環(huán)執(zhí)行 */
while( a < 20 )
{
write("a 的值: %d\n", a);
a++;
if( a > 15)
{
/* 使用 break 語句終止循環(huán) */
break;
}
}
2.16.8 continue 語句
-
continue 語句有點(diǎn)像 break 語句。但它不是強(qiáng)制終止,continue 會跳過當(dāng)前循環(huán)中的代碼,強(qiáng)迫開始下一次循環(huán)。
-
對于 for 循環(huán),continue 語句執(zhí)行后自增語句仍然會執(zhí)行。對于 while 和 do…while 循環(huán),continue 語句重新執(zhí)行條件判斷語句
-
-下圖是continue 語句在循環(huán)語句中的使用
int a = 10;
/* do 循環(huán)執(zhí)行 */
do
{
if( a == 15)
{
/* 跳過迭代 */
a = a + 1;
continue;
}
write("a 的值: %d\n", a);
a++;
}while( a < 20 );
//輸出結(jié)果:
a 的值: 10
a 的值: 11
a 的值: 12
a 的值: 13
a 的值: 14
a 的值: 16
a 的值: 17
a 的值: 18
a 的值: 19
2.16.9 return 語句
- CAPL腳本中,不帶參數(shù)的return也可以退出循環(huán)語句
on key 'c'
{
int a = 10;
/* while 循環(huán)執(zhí)行 */
while( a < 20 )
{
write("a 的值: %d\n", a);
a++;
if( a > 15)
{
/* 使用 break 語句終止循環(huán) */
return;
}
}
}
- 但是更多的使用return,是用來在函數(shù)中,返回一個(gè)值或者值的表達(dá)式
- 注意:CAPL中所有的事件處理都不返回值
long Power(int x, int y)
{
int i;
long result;
result = 1;
for (i = 1; i <= y; i++)
result *= x;
return result;
}
?? 2.17 函數(shù)
1, CAPL語言,選用了C語言庫的少部分函數(shù),但是CANoe有它自己的大量的函數(shù)庫,這些函數(shù)都是專用于CANalyzer或CANoe編程環(huán)境中有用的各種專用操作。
2,CAPL的函數(shù)大致分為3類:
- 自定義的函數(shù);不用任何聲明,在CAPL文件任意位置都可以
- CAPL內(nèi)置的函數(shù);不用像C語言那樣的要引用 #include <stdio.h>等等各種庫,已經(jīng)被內(nèi)置在CAPL中,隨用隨調(diào)
- DLL: 考慮到CAPL內(nèi)置庫不夠用,CAPL對動態(tài)庫有很好的支持
3 ,CAPL為其內(nèi)置函數(shù)使用一致且易于閱讀的命名約定:
- 所有標(biāo)準(zhǔn)C函數(shù)都是小寫的(例如,sin(), cos(), strlen(), strncat())
- 非標(biāo)準(zhǔn)C函數(shù),且只有1個(gè)單詞的函數(shù)都是用小寫(例如,trigger(), outport(), inport())
- 非標(biāo)準(zhǔn)C函數(shù),但是超過1個(gè)單詞的,除第一個(gè)單詞,其余的首字母都大寫(例如,swapInt(), timeDiff(), putValueToControl())
4, 雖然函數(shù)名是不區(qū)分大小的,但是為了保持CAPL統(tǒng)一的編碼規(guī)則和可讀性,建議你依據(jù)上面的規(guī)則
2.17.1 函數(shù)重載
- 這里CAPL引入了C++的函數(shù)重載的思想,只要保證參數(shù)不同,我們可以定義相同的函數(shù)名
on key 'c'
{
printme(5.7);
printme(3, "Feet");
}
void printme (double num)
{
write("Floating point %f", num);
}
void printme (int num, char units[])
{
write("%d %s", num, units);
}
2.17.2 函數(shù)傳參
- 因?yàn)闆]有C語言指針的概念,相對C語言函數(shù)傳參就相對簡單很對,以
數(shù)值類型傳參
為例 - 傳值:將函數(shù)外的參數(shù)再內(nèi)存中拷貝一份,再函數(shù)內(nèi)的更改,不會對函數(shù)外的參數(shù)有影響。
on key 'a'
{
int a = 10 ,b =20 ;
write("a=%d ; b=%d",a,b);
swip_1(a,b);
write("a=%d ; b=%d",a,b);
}
void swip_1(int a, int b)
{
int temp;
temp = a;
a = b;
b = temp;
write("inter>>>>a=%d ; b=%d",a,b);
}
輸出結(jié)果:
a=10 ; b=20
inter>>>>a=20 ; b=10
a=10 ; b=20
- 引用傳參:將變量的引用傳入函數(shù),效果和指針相同,在函數(shù)內(nèi)更改,也會對函數(shù)外的參數(shù)進(jìn)行更改
on key 'b'
{
int a = 10 ,b =20 ;
write("a=%d ; b=%d",a,b);
swip_2(a,b);
write("a=%d ; b=%d",a,b);
}
void swip_2(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
write("inter>>>>a=%d ; b=%d",a,b);
}
輸出結(jié)果:
a=10 ; b=20
inter>>>>a=20 ; b=10
a=20 ; b=10
- 數(shù)組/結(jié)構(gòu)體傳參 : 數(shù)組/結(jié)構(gòu)體等連續(xù)內(nèi)存的變量傳參都是
地址傳參
,函數(shù)內(nèi)部的操作都會對函數(shù)外產(chǎn)生影響。
void test_2(char para2[])
{
snprintf(para2,elCount(para2),"hello Vector!");
}
On key 'c'
{
char input[100] = "hello world!";
write("***********%s",input);
test_2(input);
write("***********%s",input);
}
輸出結(jié)果:
***********hello world!
***********hello Vector!
2.17.3 函數(shù)返回值
原則上來說,CAPL 的函數(shù)只支持 數(shù)值類型 的返回值
有同學(xué)問,數(shù)組和結(jié)構(gòu)體類型可以作為返回值嗎?答案是不可以的,如果你想把函數(shù)中的數(shù)組傳出去,請給它傳參傳入一個(gè)數(shù)組,上面也說了函數(shù)內(nèi)對數(shù)組的更改是會影響要函數(shù)外的,這樣就把函數(shù) “return”
出去了
long test_1(long para1,long para2)
{
return para1 + para2 ;
}
On key 'a'
{
write("***********%d",test_1(3,5));
}
?? 2.18 test case
testcase NewTestCase()
{
// 測試方法的代碼塊
}
testcase 是CAPL語法獨(dú)有的一種語法模塊,有點(diǎn)像函數(shù),可以傳遞各種參數(shù),也是需要有程序調(diào)用它才會執(zhí)行
常見的調(diào)用testcase 的方法有兩種 ,一種是XML TestModule
,另一種是CAPL TestModule
從零開始學(xué)習(xí)CANoe(七)—— XML 測試節(jié)點(diǎn)
從零開始學(xué)習(xí)CANoe(六)—— CAPL 測試節(jié)點(diǎn)
- 下面是XML TestModule 方式,由xml文件調(diào)用testcase ,xml編程進(jìn)一步的學(xué)習(xí)可以參考:Capl編程xml標(biāo)簽語法
test.xml 部分代碼,測試啟動時(shí),會依次調(diào)用CAPL中的 testcase
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<testmodule title="CANoe" version="1.12">
<capltestcase name="test_1" />
<capltestcase name="test_1" >
<caplparam type="string" name="case_id">TC_10449595</caplparam>
<caplparam type="int" name="case_id">0x245</caplparam>
</capltestcase>
</testmodule>
test.can 中的 testcase,負(fù)責(zé)測試方法的具體實(shí)現(xiàn)。
testcase test_1()
{
write("test_1 running");
}
testcase test_2(char case_id[],int message_id)
{
write("test_2 running ,case_id : %s",case_id);
}
- CAPL TestModule 類型中的 testcase 是通過 MainTest 來調(diào)用的。
?? 2.19 CAPL 文件類型
2.19.1 根據(jù)文件后綴分為.can 和 .cin
類似于C語言的.c和.h文件 ,一般情況我們在.can文件寫 test case,在 .cin 文件寫函數(shù)和定義變量,然后在.can的includes 模塊中把.cin文件引用進(jìn)來。
特別說明:
其實(shí) .can 和.cin文件 的內(nèi)部結(jié)構(gòu)基本一致,都可以定義變量,事件,函數(shù)等,功能基本一樣
和C語言不同的是 在.can和.cin文件中,使用函數(shù),不需要提前聲明,任何地方都可以定義,任何地方都可以使用,注意我說的任何
比如:在.cin 文件中定義的函數(shù)和變量,在.can文件中可以直接使用,這好理解,因?yàn)槭?can文件 include了 .cin文件 ;但是 在.can 文件中定義的函數(shù)和變量,在cin文件中也是可以直接使用的。
2.19.2 創(chuàng)建不同的節(jié)點(diǎn)類型,就會有不同類型的.can/.cin文件
- 如下圖,雖然都是.can文件,但是 一個(gè)節(jié)點(diǎn)類型是
Test node
,一個(gè)節(jié)點(diǎn)類型是Simulation node
,節(jié)點(diǎn)類型不同
文件的類型不同,在創(chuàng)建節(jié)點(diǎn)類型的時(shí)候就決定了,雖然都是.can文件 ,但是支持的CAPL語法也會有所差別。
Test node:側(cè)重于測試測量,CAPL內(nèi)置了很多的測試函數(shù),可以在Test node類型的.can文件中使用,但是不可以在simulation node 類型的can文件中使用,函數(shù)中包含testxxxx的都是如此 ,比如常見的testwaitfortimeout()是最常見的延時(shí)等待函數(shù),但是它不能在 simulation node 類型的can文件中使用。
?? 2.20 CAPL 文件的編碼方式
.can/cin文件的編碼方式,這在很多編程語言中都有,在CAPL中開頭部分定義
/@!Encoding:936/ : 支持中文字符串,比如write(“調(diào)用順序 —— 1”)
/*@!Encoding:ASCII/ :不支持中文,老外寫代碼用的都是這個(gè)
其它的暫時(shí)沒用到,就不說了,有興趣自己gg吧
?? 2.21 CAPL 的事件結(jié)構(gòu)
這里再次強(qiáng)調(diào)下,CAPL腳本是基于事件驅(qū)動的,也就是說CAPL腳本中每一行代碼都是某個(gè)對應(yīng)的事件發(fā)生了才去執(zhí)行的。
- testcase,是由其它功能模塊調(diào)用而執(zhí)行的,如上邊所說xml test module
- Functions :函數(shù)也肯定是被調(diào)用才被執(zhí)行的
- Test Function ,這個(gè)本文我沒說,也是被xml/.net 文件調(diào)用而執(zhí)行的,和testcse同一類的
- includes : 非事件,引用.cin和dll文件的功能塊
- Variables: 非事件,定義全局變量,注意是相對本文件的全局變量,非CANoe環(huán)境的全局變量,在CANoe中使用全局變量有系統(tǒng)變量和環(huán)境變量
2.21.1 sytem ,系統(tǒng)事件
on timer 和 on key 就不再贅述了,前面也已經(jīng)寫過了,圈起來的是幾個(gè)測量事件,啟動和停止CANoe 軟件的時(shí)候會分別調(diào)用
CAPL 腳本中 定時(shí)器 ,按鍵觸發(fā)事件的使用
在這里插入代碼片
- 執(zhí)行順序如下:
- on preStart過程僅用于初始化變量、在Write Window中顯示消息以及從文件中讀取數(shù)據(jù)
- on preStop函數(shù)可用于執(zhí)行一些在測量停止實(shí)際生效之前必須執(zhí)行的最終操作。
on preStart
{
write("調(diào)用順序 —— 1");
}
on Start
{
write("調(diào)用順序 —— 2");
}
on preStop
{
write("調(diào)用順序 —— 3");
}
on stopMeasurement
{
write("調(diào)用順序 —— 4");
}
注意:
- on start 和 on stopMeasurement 事件不能在 test node 類型的.can文件中使用
- 可以使用 on preStart ,但是不能用來對變量賦值等操作
- 如果測量測試已經(jīng)完成,那么 on preStop 中的代碼也不會被執(zhí)行。
- 所以 系統(tǒng)的測數(shù)量事件相關(guān)代碼最好集中在simulated node .can文件中完成
2.21.2 值(信號/變量)變化事件
比如信號值,系統(tǒng)變量,環(huán)境變量 ,這些元素值發(fā)生變化,會觸發(fā)這些事件
CAPL 腳本中對信號,系統(tǒng)變量,環(huán)境變量的 事件響應(yīng)
2.21.3 報(bào)文接收事件
總線上收到指定的報(bào)文后,會觸發(fā) on message 事件,同時(shí)message 是一個(gè)object 對象,它由很多屬性,可以通過 this .xxx獲取和設(shè)置
CAPL腳本 對CAN 報(bào)文的事件響應(yīng)
On message CAN1.0x4c
{
write("***0x%x",this.id);
}
2.21.4 事件中的this 關(guān)鍵字
1)在接收CAN對象或環(huán)境變量的事件過程中,對象的數(shù)據(jù)結(jié)構(gòu)由關(guān)鍵字this指定。例如,您可以通過以下方式訪問剛剛接收到的消息100的第一個(gè)數(shù)據(jù)字節(jié)
on message 100 {
byte byte_0;
byte_0 = this.byte(0);
...
}
2):類似地,您可以通過以下方法讀取剛剛更改過的整數(shù)環(huán)境變量Switch的新值
on envVar Switch {
int val;
val = getvalue(this);
...
}
3):類似地,鍵盤按鍵事件
On key 'a'
{
write("pressed %c",this);
}
?? 2.22 CAPL Browser 的設(shè)置
2.22.1 配色方案:
2.22.2 必須的工具欄:
在使用CAPL 寫腳本時(shí),我認(rèn)為這三個(gè)工具欄應(yīng)該要打開的,可以便捷你的開發(fā)速度
- Output :開發(fā)的時(shí)候,編譯可以實(shí)時(shí)發(fā)現(xiàn)腳本的錯(cuò)誤信息
- Symbols: 在CANoe中加載的DBC,CDD文件的元素,定義的系統(tǒng)變量等都可以直接這里找的到,隨用隨查看
- CALP Functions: C語言在使用庫函數(shù)時(shí),需要在文件開頭include相應(yīng)的庫文件,但是CAPL不需要那么麻煩,它內(nèi)置了很多自己專用的函數(shù),也吸收了一些C/C++的函數(shù),但是不需要include任何文件,可以在CAPL中直接使用。有時(shí)候記不全函數(shù)的名稱,可以直接搜索查看。
??總結(jié)
文章來源:http://www.zghlxwxcb.cn/news/detail-788900.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-788900.html
- ??要有最樸素的生活,最遙遠(yuǎn)的夢想,即使明天天寒地凍,路遙馬亡!
- ??如果這篇博客對你有幫助,請 “點(diǎn)贊” “評論”“收藏”一鍵三連 哦!碼字不易,大家的支持就是我堅(jiān)持下去的動力。
到了這里,關(guān)于兩萬字的CAPL語法基礎(chǔ),一篇文章帶你入門的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!