CANoe 入門 Step by step系列(三)簡單例子的剖析


    最好的學習方式是什么?模仿。有人會問,那不是山寨么?但是我認為,那是模仿的初級階段,當把別人最好的設計已經融化到自己的血液里,變成自己的東西,而靈活運用的時候,才是真正高級階段。正所謂畫虎畫皮難畫骨。但初級階段仍然是必須經歷的過程,他會使你在達到高級階段的過程中少走很多彎路,下面我們來邁出這一步。先研究一下別人的簡單例子。

    最好的例子莫過於Vector本身的Demo了,這個在安裝完CANoe之后就會被自動安裝。先看最簡單的一個,名字叫Easy,但並不簡單哦,比我們之前介紹的所有的東西都整合再一起了,很簡單,但很全面。但是假如你說,這個我自己也可以完全自己寫出來(並不是僅僅是看懂哦),那么我可以肯定的說,在工作中,你完全可以勝任一般的任務要求哦~,剩下的只是工作量的問題了。但我相信到現在為止,你們很多人,都無法寫出這樣的程序,所以我建議你們把這個程序好好的研究明白,這點很重要。廢話不多說,上圖,下面是打開運行后的界面。

tmpD0

通過面板可以控制,及顯示很多動畫效果,做的非常的漂亮。在其余的窗體也將主要的數據以圖表等表現方式呈現出來。

我們先看一下DBC的內容吧

Signals:

EngineSpeed  車速信息

FlashLight      雙跳燈

HeadLight      大燈

OnOff            引擎狀態

 

Messages:

EngineState  引擎狀態:包含的信號有OnOff,EngineSpeed

LightState    燈光狀態:包含的信號有FlashLight,HeadLight

 

Network nodes:

Display        顯示節點,接收所有消息

Engine        引擎節點,發送EngineState 消息

Light          燈光節點,發送LightState 消息

 

Environment variables:   環境變量,一般與界面的組件相關聯,這樣就實現了圖形化界面的控制與顯示,下面就是關聯的界面組件

EnvEngineSpeedDspMeter  tmp60

EnvEngineSpeedDspText   tmp61

EnvEngineSpeedEntry       tmp5D

EnvEngineStateDsp          tmp5E

EnvEngineStateSwitch       tmp56

EnvHazardLightsSwitch     tmp57

EnvHeadLightSwitch         tmp58

EnvLightDsp                    tmp62

 

注意一下信號的信息:

tmp156tmp157

Definition頁面的,Init.Val的輸入框使能了,之前是灰色的狀態,為什么呢?點擊一下藍色的帶下划線的連接,彈出窗台如下:

tmp158

意思是說這個值的設置,必須要定義的屬性才能有效,之前一直沒有提到信號的屬性,這次還是第一次遇到哦。個人理解信號屬性是表明信號的特點的一系列參數,當然消息和節點也都有對應的屬性。為了更加詳細的了解這個屬性,我們求助於幫助。

tmp15E

哦,明白了,原來是用來初始化數據的哦。其實在Definition表示的是物理值,都要轉換成Raw值保存到GenSigStartValue屬性中。在屬性的創建我們之前也沒有提到過,這里講一下,請在CANdb++ Editor菜單中,View->Attribute Definitions

tmp163

右鍵,New,填寫好信息即可。屬性背后跟行為是密切相關的,甚至跟底層dll,其他的一些屬性請參考Help文檔,當然重要的屬性我們也會跟大家在后面提到。

dbc還有一些細節,就是接受的消息的定義,之間也沒介紹過,例如Display節點只接收消息,那么你就應該在節點的屬性上進行配置,方法是右擊節點然后點Edit Node,在Mapped Rx Sig.中就可以定義接收的信號了,Add…

tmp16C

其實不定義接收消息也是可以的,但會在File->Consistency check 的檢查中中顯示出無接收節點等的報警。例如前面第一講例子的dbc的檢查如下:

tmp16E

再看一下CAPL程序。

engine.can 程序如下:


variables
{
}

on envvar EnvEngineStateSwitch         //當撥動開關的時候,會更改發動機發出的信號
{
  $EngineState::OnOff = @this;           //注意信號和環境變量直接賦值時的符號,信號用$,環境變量用@
  if(@this)
    $EngineState::EngineSpeed = @EnvEngineSpeedEntry;
  else
    $EngineState::EngineSpeed = 0;
}

on envvar EnvEngineSpeedEntry         //當移動車速滑條時,會更改發動機發出的信號
{
  if(@EnvEngineStateSwitch)
  {
    $EngineState::EngineSpeed = @this;
  }
}

on start                                         //程序開始運行的時候,將調用所有的環境變量的事件
{
  CallAllOnEnvVar();    // call all envvar procedures of this model and
                        // thus consider the START VALUES of all environment
                        // variables for: 
                        //  - initialization of all message variables
                        //  - starting of any timers
                        //  - sending messages (output) with start values
}

light.can 的程序如下:

variables
{
  msTimer tFlashLightFrequency;                 //定義閃燈定時器
  const int gFlashLightFrequency = 500;      //定義閃燈頻率,初始化為500ms
  int gHazardLightsStatus = 0;                   //定義危險燈信號

  int gDebugCounterTX = 0;                      //用於調試,記錄TX報文個數
  int gDebugCounterTXRQ = 0;                  //用於調試,記錄TXRQ報文個數
  int gDebugCounterRX = 0;                      //用於調試,記錄RX報文個數
}

on envvar EnvHeadLightSwitch                   //大燈開關狀態更改時,更新燈光消息的信號
{
  // assign EV value to the message signal
  $LightState::HeadLight = @this;
}

on start
{
  CallAllOnEnvVar();    // call all envvar procedures of this model and
                        // thus consider the START VALUES of all environment
                        // variables for: 
                        //  - initialization of all message variables
                        //  - starting of any timers
                        //  - sending messages (output) with start values

  setWriteDbgLevel(0); // set DbgLevel = 1 to get more information in Write-Window
}

on message LightState    //調試用,打印相關信息
{
  if (this.dir == TX)
  {
    gDebugCounterTX++;
    if(gDebugCounterTX == 10)
    {
      writeDbgLevel(1,"LightState TX received by node %NODE_NAME%");
      gDebugCounterTX = 0;
    }    
  }
  if(this.dir == TXREQUEST)
  {
    gDebugCounterTXRQ++;
    if(gDebugCounterTXRQ == 10)
    {
      writeDbgLevel(1,"LightState TXREQUEST received by node %NODE_NAME%");
      gDebugCounterTXRQ = 0;
    }
  }
  if (this.dir == RX)
  {
    gDebugCounterRX++;
    if(gDebugCounterRX == 10)
    {
      writeDbgLevel(1,"Error: LightState RX received by node %NODE_NAME%");
      gDebugCounterRX = 0;
    }
  }
}

on envVar EnvHazardLightsSwitch      //危險警示燈開關變化時,更新燈光消息的閃燈信號
{
  if (@this)
  {
    gHazardLightsStatus = 1;
    setTimer(tFlashLightFrequency, gFlashLightFrequency);
  }
  else
  {
    cancelTimer(tFlashLightFrequency);
    gHazardLightsStatus = 0;
  }

  $LightState::FlashLight = gHazardLightsStatus;
}

on timer tFlashLightFrequency             //危險報警燈間隔閃爍的控制
{
  gHazardLightsStatus = (gHazardLightsStatus == 1 ? 0 : 1);
  $LightState::FlashLight = gHazardLightsStatus;
  setTimer(this, gFlashLightFrequency);
}

on key '0'                                      //按鍵事件,定義打印調試信息的等級
{
  setwriteDbgLevel(0);
}

on key '1'                                      //按鍵事件,定義打印調試信息的等級
{
  setwriteDbgLevel(1);                   
}

以上程序,有C語言基礎的同學應該都可以看得懂,這里不用詳細介紹了。

看完程序大家可能有個疑問,沒有調用任何發送CAN消息的函數(只是更改其中的信號),但報文卻真的發出去了,這是為什么呢?

這是因為周期發送消息的工作,已經在消息的屬性中定義了,這樣消息會自動周期的發送。如下:

tmp29

這個在消息的屬性查看中的界面,當然也可以在上面我們介紹的View->Attribute Definitions,進行修改和查看,但區別是,這個只是針對個別消息的,View->Attribute Definitions,是針對所有的情況。還有消息屬性中,對此進行歸類,以上歸類到Interaction Layer這個是CAN通訊的交互層。上面的各個屬性的具體含義,請參考幫助文檔,都有詳細的說明。

下面說一下界面。

tmp4B

選中一個界面組件,在狀態欄中可顯示他的類型,關聯的對象等信息。右邊為屬性窗口,定義選中組件的屬性

tmp4D

這個組件類型為:Switch/Indicator

屬性欄中:

Image 表示該組件使用的圖片,因為要表示幾種狀態,所以做成這樣,尺寸105x34 pix

tmp4F

State Count 表示狀態的個數

其他的屬性不一一介紹了,自己試一下基本可以知道,實在不行求助幫助文檔,這里不一 一介紹了。

到現在整個工程的剖析基本上結束了,但說過的這些不足以覆蓋所有的細節,但基本脈絡已經很清晰了,剩下的可以自己研究,都不難理解。個人建議,在實際工作中創建自己的工程,當遇到問題是,參考例子中的實現方式,這樣更加幫助理解。進步也最快。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM