最好的學(xué)習(xí)方式是什么?模仿。有人會(huì)問(wèn),那不是山寨么?但是我認(rèn)為,那是模仿的初級(jí)階段,當(dāng)把別人最好的設(shè)計(jì)已經(jīng)融化到自己的血液里,變成自己的東西,而靈活運(yùn)用的時(shí)候,才是真正高級(jí)階段。正所謂畫(huà)虎畫(huà)皮難畫(huà)骨。但初級(jí)階段仍然是必須經(jīng)歷的過(guò)程,他會(huì)使你在達(dá)到高級(jí)階段的過(guò)程中少走很多彎路,下面我們來(lái)邁出這一步。先研究一下別人的簡(jiǎn)單例子。
最好的例子莫過(guò)于Vector本身的Demo了,這個(gè)在安裝完CANoe之后就會(huì)被自動(dòng)安裝。先看最簡(jiǎn)單的一個(gè),名字叫Easy,但并不簡(jiǎn)單哦,比我們之前介紹的所有的東西都整合再一起了,很簡(jiǎn)單,但很全面。但是假如你說(shuō),這個(gè)我自己也可以完全自己寫(xiě)出來(lái)(并不是僅僅是看懂哦),那么我可以肯定的說(shuō),在工作中,你完全可以勝任一般的任務(wù)要求哦~,剩下的只是工作量的問(wèn)題了。但我相信到現(xiàn)在為止,你們很多人,都無(wú)法寫(xiě)出這樣的程序,所以我建議你們把這個(gè)程序好好的研究明白,這點(diǎn)很重要。廢話(huà)不多說(shuō),上圖,下面是打開(kāi)運(yùn)行后的界面。
通過(guò)面板可以控制,及顯示很多動(dòng)畫(huà)效果,做的非常的漂亮。在其余的窗體也將主要的數(shù)據(jù)以圖表等表現(xiàn)方式呈現(xiàn)出來(lái)。
我們先看一下DBC的內(nèi)容吧
Signals:
EngineSpeed 車(chē)速信息
FlashLight 雙跳燈
HeadLight 大燈
OnOff 引擎狀態(tài)
Messages:
EngineState 引擎狀態(tài):包含的信號(hào)有OnOff,EngineSpeed
LightState 燈光狀態(tài):包含的信號(hào)有FlashLight,HeadLight
Network nodes:
Display 顯示節(jié)點(diǎn),接收所有消息
Engine 引擎節(jié)點(diǎn),發(fā)送EngineState 消息
Light 燈光節(jié)點(diǎn),發(fā)送LightState 消息
Environment variables: 環(huán)境變量,一般與界面的組件相關(guān)聯(lián),這樣就實(shí)現(xiàn)了圖形化界面的控制與顯示,下面就是關(guān)聯(lián)的界面組件
注意一下信號(hào)的信息:
Definition頁(yè)面的,Init.Val的輸入框使能了,之前是灰色的狀態(tài),為什么呢?點(diǎn)擊一下藍(lán)色的帶下劃線(xiàn)的連接,彈出窗臺(tái)如下:
意思是說(shuō)這個(gè)值的設(shè)置,必須要定義的屬性才能有效,之前一直沒(méi)有提到信號(hào)的屬性,這次還是第一次遇到哦。個(gè)人理解信號(hào)屬性是表明信號(hào)的特點(diǎn)的一系列參數(shù),當(dāng)然消息和節(jié)點(diǎn)也都有對(duì)應(yīng)的屬性。為了更加詳細(xì)的了解這個(gè)屬性,我們求助于幫助。
哦,明白了,原來(lái)是用來(lái)初始化數(shù)據(jù)的哦。其實(shí)在Definition表示的是物理值,都要轉(zhuǎn)換成Raw值保存到GenSigStartValue屬性中。在屬性的創(chuàng)建我們之前也沒(méi)有提到過(guò),這里講一下,請(qǐng)?jiān)贑ANdb++ Editor菜單中,View->Attribute Definitions
右鍵,New,填寫(xiě)好信息即可。屬性背后跟行為是密切相關(guān)的,甚至跟底層dll,其他的一些屬性請(qǐng)參考Help文檔,當(dāng)然重要的屬性我們也會(huì)跟大家在后面提到。
dbc還有一些細(xì)節(jié),就是接受的消息的定義,之間也沒(méi)介紹過(guò),例如Display節(jié)點(diǎn)只接收消息,那么你就應(yīng)該在節(jié)點(diǎn)的屬性上進(jìn)行配置,方法是右擊節(jié)點(diǎn)然后點(diǎn)Edit Node,在Mapped Rx Sig.中就可以定義接收的信號(hào)了,Add…
其實(shí)不定義接收消息也是可以的,但會(huì)在File->Consistency check 的檢查中中顯示出無(wú)接收節(jié)點(diǎn)等的報(bào)警。例如前面第一講例子的dbc的檢查如下:
再看一下CAPL程序。
engine.can 程序如下:
variables
{
}
on envvar EnvEngineStateSwitch //當(dāng)撥動(dòng)開(kāi)關(guān)的時(shí)候,會(huì)更改發(fā)動(dòng)機(jī)發(fā)出的信號(hào)
{
$EngineState::OnOff = @this; //注意信號(hào)和環(huán)境變量直接賦值時(shí)的符號(hào),信號(hào)用$,環(huán)境變量用@
if(@this)
$EngineState::EngineSpeed = @EnvEngineSpeedEntry;
else
$EngineState::EngineSpeed = 0;
}
on envvar EnvEngineSpeedEntry //當(dāng)移動(dòng)車(chē)速滑條時(shí),會(huì)更改發(fā)動(dòng)機(jī)發(fā)出的信號(hào)
{
if(@EnvEngineStateSwitch)
{
$EngineState::EngineSpeed = @this;
}
}
on start //程序開(kāi)始運(yùn)行的時(shí)候,將調(diào)用所有的環(huán)境變量的事件
{
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; //定義閃燈定時(shí)器
const int gFlashLightFrequency = 500; //定義閃燈頻率,初始化為500ms
int gHazardLightsStatus = 0; //定義危險(xiǎn)燈信號(hào)
int gDebugCounterTX = 0; //用于調(diào)試,記錄TX報(bào)文個(gè)數(shù)
int gDebugCounterTXRQ = 0; //用于調(diào)試,記錄TXRQ報(bào)文個(gè)數(shù)
int gDebugCounterRX = 0; //用于調(diào)試,記錄RX報(bào)文個(gè)數(shù)
}
on envvar EnvHeadLightSwitch //大燈開(kāi)關(guān)狀態(tài)更改時(shí),更新燈光消息的信號(hào)
{
// 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 //調(diào)試用,打印相關(guān)信息
{
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 //危險(xiǎn)警示燈開(kāi)關(guān)變化時(shí),更新燈光消息的閃燈信號(hào)
{
if (@this)
{
gHazardLightsStatus = 1;
setTimer(tFlashLightFrequency, gFlashLightFrequency);
}
else
{
cancelTimer(tFlashLightFrequency);
gHazardLightsStatus = 0;
}
$LightState::FlashLight = gHazardLightsStatus;
}
on timer tFlashLightFrequency //危險(xiǎn)報(bào)警燈間隔閃爍的控制
{
gHazardLightsStatus = (gHazardLightsStatus == 1 ? 0 : 1);
$LightState::FlashLight = gHazardLightsStatus;
setTimer(this, gFlashLightFrequency);
}
on key '0' //按鍵事件,定義打印調(diào)試信息的等級(jí)
{
setwriteDbgLevel(0);
}
on key '1' //按鍵事件,定義打印調(diào)試信息的等級(jí)
{
setwriteDbgLevel(1);
}
以上程序,有C語(yǔ)言基礎(chǔ)的同學(xué)應(yīng)該都可以看得懂,這里不用詳細(xì)介紹了。
看完程序大家可能有個(gè)疑問(wèn),沒(méi)有調(diào)用任何發(fā)送CAN消息的函數(shù)(只是更改其中的信號(hào)),但報(bào)文卻真的發(fā)出去了,這是為什么呢?
這是因?yàn)橹芷诎l(fā)送消息的工作,已經(jīng)在消息的屬性中定義了,這樣消息會(huì)自動(dòng)周期的發(fā)送。如下:
這個(gè)在消息的屬性查看中的界面,當(dāng)然也可以在上面我們介紹的View->Attribute Definitions,進(jìn)行修改和查看,但區(qū)別是,這個(gè)只是針對(duì)個(gè)別消息的,View->Attribute Definitions,是針對(duì)所有的情況。還有消息屬性中,對(duì)此進(jìn)行歸類(lèi),以上歸類(lèi)到Interaction Layer這個(gè)是CAN通訊的交互層。上面的各個(gè)屬性的具體含義,請(qǐng)參考幫助文檔,都有詳細(xì)的說(shuō)明。
下面說(shuō)一下界面。
選中一個(gè)界面組件,在狀態(tài)欄中可顯示他的類(lèi)型,關(guān)聯(lián)的對(duì)象等信息。右邊為屬性窗口,定義選中組件的屬性
這個(gè)組件類(lèi)型為:Switch/Indicator
屬性欄中:
Image 表示該組件使用的圖片,因?yàn)橐硎編追N狀態(tài),所以做成這樣,尺寸105x34 pix
State Count 表示狀態(tài)的個(gè)數(shù)
其他的屬性不一一介紹了,自己試一下基本可以知道,實(shí)在不行求助幫助文檔,這里不一 一介紹了。
到現(xiàn)在整個(gè)工程的剖析基本上結(jié)束了,但說(shuō)過(guò)的這些不足以覆蓋所有的細(xì)節(jié),但基本脈絡(luò)已經(jīng)很清晰了,剩下的可以自己研究,都不難理解。個(gè)人建議,在實(shí)際工作中創(chuàng)建自己的工程,當(dāng)遇到問(wèn)題是,參考例子中的實(shí)現(xiàn)方式,這樣更加幫助理解。進(jìn)步也最快。
聯(lián)系客服