深入浅出学习CAN系列-了解CAPL编程语言
前言
????????上一篇文章介紹了如何創建CANoe工程,需要先閱讀這篇文章,才能對整個工程有所了解,包括節點、報文、信號等關鍵信息。
? ? ? ? 本文的重點是分析該工程中各個節點CAPL語言是怎么編寫的,主要目的在于理解整個工程的實現,具體關于CAPL語言的理論知識總結等以后再分享。
????????CAPL就是Communication Application Programming Laguage的縮寫,CAPL類似于C語言的語法。CAPL語法是C語言的,又有一些C++的特性,this指針,事件等,我覺得和我之前學的JavaScript語言有一些互通的地方。????????
????????如圖,我們會分別介紹三個節點的CAPL程序。
Engine.can
????????首先來看一下Engine節點engine.can的代碼。
?/*@!Encoding:936*/ includes {}variables {//The following three messages are defined for transmissionmessage EngineStatus EngineStat; //定義一個在DBC中message name為EngineStatus的報文變量EngineStatmessage LockingRq LkCtrlRq;message WindowRq WindowCtrl;//The following timer is for simulating the cyclic message transmission msTimer msTimer_EngineStatus; //定義一個ms定時器msTimer_EngineStatus}on start {setTimerCyclic(msTimer_EngineStatus,100); }on timer msTimer_EngineStatus{ //響應定時器事件msTimer_EngineStatus,將報文發送到總線EngineStat.Velocity = @sysvar::testNS::Velocity; //獲取面板中變量輸入的值EngineStat.IgnitionStatus = @sysvar::testNS::IgnitionStart;output(EngineStat); //將報文發送到總線中 }程序結構
????????先從宏觀的角度來看,這個CAPL程序的結構包含了頭文件、全局變量、事件函數,沒有自定義函數。
????????includes{ }頭文件是對其他文件及dll文件的包含說明,variables{ }是對全局變量的聲明定義,on start{ },on timer{ }是工程中用到的各類事件。
全局變量? ?
????????CAPL提供了各種網絡對應的報文類。本文以CAN message為例,報文變量定義格式:message + message ID/message name + variable
????????使用message關鍵字來聲明一個報文變量,message后是message ID或CANoe工程導入DBC后的message name,然后是在CAPL程序中要使用的報文變量名。
message EngineStatus EngineStat;????????如上,定義一個在DBC中message name為EngineStatus的報文變量EngineStat,此外還定義了報文LockingRq和報文WindowRq。
????????2. msTimer 定時器變量
????????CAPL提供兩種定時器變量: timer:基于秒(s)的定時器 、msTimer:基于毫秒(ms)的定時器。
msTimer msTimer_EngineStatus;????????如上,定義了一個ms定時器msTimer_EngineStatus。
事件函數
CAPL是一種面向過程、由事件驅動的類C語言。
事件驅動針對于順序執行,其區別如下:
順序執行:順序執行流程中,子例程或過程函數按照代碼編寫順序逐句執行。
事件驅動:CAPL程序由事件驅動,工程運行過程中發生指定的事件時才會運行相應的事件處理函數。
事件起始關鍵字 on
on后加某種事件,工程運行時條件觸發,則執行函數體內的語句。
關鍵字this
系統變量、環境變量或CAN報文事件中,可以用this關鍵字訪問其指代的數據內容。
on start {setTimerCyclic(msTimer_EngineStatus,100); }????????如上,on start{ }函數在工程開始時調用,setTimerCyclic(msTimer_EngineStatus,100)?設置定時器msTimer_EngineStatus為一個100ms為周期的循環定時器;
on timer msTimer_EngineStatus{ //響應定時器事件msTimer_EngineStatus,將報文發送到總線EngineStat.Velocity = @sysvar::testNS::Velocity; //獲取面板中變量輸入的值EngineStat.IgnitionStatus = @sysvar::testNS::IgnitionStart;output(EngineStat); //將報文發送到總線中 }? ? ? ? 如上,定義了一個響應定時器事件,函數中EngineStat.Velocity = @sysvar::testNS::Velocity;表示面板panel中的系統變量Velocity變化后,將其賦值給EngineStat報文的Velocity 信號。最后的output()函數將報文發送到總線中。
? ? ? ? 整段engine.can的代碼,實現了周期(100ms)循環執行msTimer_EngineStatus事件,將EngineStatus報文每100ms發送到總線中。如果面板panel中報文的兩個信號有變化的話,會實時更新。
Doors.can
includes {}variables {byte WindowState = 0;byte IgnitionState;message LockingState LockingStat;message WindowState WindowStat; }on message EngineStatus {//Storing Ignition Stateif(this.IgnitionStatus) IgnitionState = 1; //Ignition is onelse IgnitionState = 0; // Ignition is off//Locking based on velocityif(IgnitionState == 1 && this.Velocity > 15 && LockingStat.LockState == 0){LockingStat.LockState = 1;output(LockingStat);} }on message WindowRq{if(IgnitionState){if(this.WindowRequest == 1) //Roll up windowif(WindowState > 0) WindowState--;if(this.WindowRequest == 2) //Roll down windowif(WindowState<15) WindowState++;}WindowStat.WindowPosition = WindowState;output(WindowStat); }on message LockingRq{if(this.LockRequest) LockingStat.LockState = 0;else LockingStat.LockState = 1;output(LockingStat); }數據結構
variables {byte WindowState = 0;byte IgnitionState;message LockingState LockingStat;message WindowState WindowStat; }????????如上,定義了兩個報文變量LockingStat和WindowStat,以及用byte聲明了一個字節的變量WindowState和IgnitionState。
事件函數
CAN消息事件
?通過”on message”定義消息事件,該事件會在指定的報文消息被接收時被調用。
on message EngineStatus {//Storing Ignition Stateif(this.IgnitionStatus) IgnitionState = 1; //Ignition is onelse IgnitionState = 0; // Ignition is off//Locking based on velocityif(IgnitionState == 1 && this.Velocity > 15 && LockingStat.LockState == 0){LockingStat.LockState = 1;output(LockingStat);} }????????如上,當收到報文EngineStatus后,執行函數括號中的內容。當報文中的信號IgnitionStatus為1時,IgnitionState變量賦值為1,表示汽車已經啟動,反之變量賦值為0。
????????第二個if語句表示,當汽車已經啟動IgnitionState == 1,車速大于15this.Velocity > 15,車是解鎖狀態LockingStat.LockState,同時符合這三個條件的時候,將LockingStat.LockState置為1,即將車上鎖。隨后將LockingState報文發送到總線。
????????其余兩個消息事件的內容同理,這邊就不贅述了。
console.can
/*@!Encoding:936*/ includes {}variables {message LockingRq LkCtrlRq;message WindowRq WinRq; }on sysvar_update testNS::LockRq{if(@sysvar::testNS::LockRq) LkCtrlRq.LockRequest = 1; //request unlock doorselse LkCtrlRq.LockRequest = 0; //request Lock Doorsoutput(LkCtrlRq); //Outputs message onto the bus }on sysvar_update testNS::WindowRequest{WinRq.WindowRequest = @sysvar::testNS::WindowRequest;output(WinRq); //Outputs message onto the bus }on message WindowState{@sysvar::testNS::WindowState = this.WindowPosition; }事件函數
on message WindowState{@sysvar::testNS::WindowState = this.WindowPosition; }????????如上,當收到報文WindowState后,將信號WindowPosition的值賦值給系統變量WindowState,即在面板上可以看到該值的變化。
????????讀取或者設置系統變量的值,用 ‘@’ 或者 sysGetVariable,系統變量要通過 域操作符"::" 在前面加上他的域空間才行。
on sysvar_update testNS::WindowRequest{WinRq.WindowRequest = @sysvar::testNS::WindowRequest;output(WinRq); //Outputs message onto the bus }????????如上,當在面板panel對系統變量WindowRequest進行操作后,會執行函數括號里的內容,將系統變量的值賦值給報文的WindowRequest信號,然后將報文發送到總線。
on sysvar 和 on sysvar_update的區別
on sysvar :值變化才會觸發
on sysvar_update :只要對系統變量操作了,值不變化也會觸發
總結
以上是生活随笔為你收集整理的深入浅出学习CAN系列-了解CAPL编程语言的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Endnotex8在office2013
- 下一篇: 各个省市mysql表附带行政id(一)