轉載自 http://blog./posts/canoe-tutorial-part-2.html
在這份教程的第一部分,我們提到?jīng)]有CAN數(shù)據(jù)庫,CANoe還不能工作。在第二部分,我們來看看CAN數(shù)據(jù)庫是怎樣的。通過CANoe的Tools菜單,或者從開始菜單打開Vector的CAN數(shù)據(jù)庫編輯器——CANdb++ Editor。
簡介
CAN總線上有4種報文:數(shù)據(jù)幀、遠程幀、錯誤幀、超載幀。其中只有數(shù)據(jù)幀真正承載數(shù)據(jù)。CAN數(shù)據(jù)庫儲存這些的數(shù)據(jù)幀的所有屬性,這樣當我們發(fā)現(xiàn)了某條報文在總線上出現(xiàn)時,利用數(shù)據(jù)庫中的數(shù)據(jù),就能查詢出相關的數(shù)據(jù)。比如這條報文的收發(fā)者,以及其表示的意義。
在Vector格式的數(shù)據(jù)庫中,數(shù)據(jù)被組織成了6種不同的對象(Object):
- 信號(Signal)
- 報文(Message)
- 網(wǎng)絡節(jié)點(Network node),或者簡稱節(jié)點
- 環(huán)境變量(Environment variable)
- 設備(ECU)
- CAN網(wǎng)絡(Network)
對象是有級別的,高級的對象由若干低級對象附加額外的屬性構成。如下圖:
信號和報文信號的關系稍后會解釋。報文信號到報文的箭頭表示(若干)信號組成報文;報文到節(jié)點的箭頭表示報文擁有發(fā)送節(jié)點;報文信號到節(jié)點的箭頭表示擁有接收節(jié)點;節(jié)點和環(huán)境變量到ECU的箭頭表示它們組成了ECU;同樣,ECU組成了網(wǎng)絡。這和CAN總線的交互結構是一樣的。
在CANoe自帶的CANdb++版本中,一個數(shù)據(jù)庫最高級的對象是Network,且只能有一個,其名字與文件名相同。在更高級的Vector CANdb++ Admin版本中,最高級為一個叫Vehicles的對象,可以包含若干Network。
對象說明
信號
信號(Singal)代表了信息的最小單位,也就是一個“值”。例如發(fā)動機轉速,開關的位置等。其主要的屬性有:name
,
length
, Byte order
, Value type
。具體含義可以參考CANdb++的Help中,Signal and Message Signal一節(jié)。注意Byte order屬性,我們稱之為“格式”,它可以設置為Motorola
或者Intel
,稍后會詳細介紹。
報文信號
報文信號(Mapped signal)其實就是信號,區(qū)別在于當一個信號成為報文的組成部分時,它就會變成報文信號。因為它算是存在于報文中的,因此多了兩個屬性:
- Startbit: 起始位,也就是信號在報文中的位置。
- Receivers: 這個Signal會被哪個節(jié)點接收,這也是上圖信號到節(jié)點的箭頭的意義。
一個信號可以包含在多個報文中,之后會變成多個不同的報文信號,CANdb++ Editor中也叫映射的信號(Mapped Signal)。這是為了Singal可以重用,數(shù)據(jù)庫中其它對象都不能這樣重用。
報文
報文(Message)代表一條CAN報文,它就是在CAN總線上實際發(fā)送的內(nèi)容。報文包含若干信號,有name
, ID
,
DLC
, Transmitters
等屬性,具體參考Help文檔。需要說明的是,理論上只有一個節(jié)點會是報文的發(fā)送者,不過CANdb++ Editor中可以設置多個。
另外,Message的屬性頁中的Layout,可以直觀的設置Message包含的Message Signal的位置(也就是其Startbit屬性),它編輯的并不是Message的屬性。
網(wǎng)絡節(jié)點
網(wǎng)絡節(jié)點(Node),它幾乎代表了一個設備(ECU)。之所以說幾乎,首先是因為ECU還包含了環(huán)境變量,其次是因為有一種特殊的ECU模型,它叫做網(wǎng)關(Gateway)。網(wǎng)關包含兩個或更多節(jié)點,我們等會兒再來說明它。
所以通常,節(jié)點 + 環(huán)境變量 = ECU,節(jié)點的主要屬性就只有name
而已。
環(huán)境變量
環(huán)境變量(Environment varisble),用來儲存ECU中的數(shù)據(jù),比如開關位置、傳感器信號等。節(jié)點讀寫這些變量,同時,環(huán)境變量還能夠被其它東西讀寫,比如虛擬的傳感器。環(huán)境變量的存在是為了更好的模擬ECU這個模型。節(jié)點利用環(huán)境變量和環(huán)境交換信息。
ECU
上面已經(jīng)差不多說明了,ECU其實就是節(jié)點和環(huán)境變量的組合,代表真實世界的儀器設備。在CANdb++ Editor中,ECU的可設置的屬性只有其包含哪些環(huán)境變量。ECU對象名字無法編輯的,它等于節(jié)點的名字。
網(wǎng)絡
Network表示真實世界中的一條CAN總線,它包含若干ECU。
網(wǎng)關
網(wǎng)關(Gateway),是一種特殊的ECU,它包含多個節(jié)點,以及環(huán)境變量。各個節(jié)點屬于不同的網(wǎng)絡,通過共用的環(huán)境變量交換數(shù)據(jù)。這樣,各個網(wǎng)絡就可以通過網(wǎng)關交換信息。這也是“網(wǎng)關”名字的由來。需要注意的是,CANdb++ Editor非Admin版本中,dbc文件只能含有唯一一個Network,因此網(wǎng)關這種模型是建立不出來的(汗
關于信號的起始位
稍微了解點CAN之后,CAN數(shù)據(jù)庫非常容易理解,它其實就是CAN總線的模型。不過信號的“起始位”屬性,還是得仔細說明。借助報文的Layout,理解起來會稍容易一些。
我們已經(jīng)知道,報文包含若干信號。信號的格式(Byte order)可以是兩種之一:Motorola或者Intel。他們是指Motorola和Intel處理器中使用的數(shù)據(jù)的儲存格式,也就是兩種字節(jié)序,Motorola是大端字節(jié)序,Intel是小端字節(jié)序。具體來說,十進制數(shù)128,寫成二進制數(shù)1000 0000
,就是大端字節(jié)序,而寫成0000 0001
就是小端字節(jié)序。
Byte order for Motorola processors (Big Endian): MSB ... ... LSB Byte order for Intel processors (Little Endian): LSB ... ... MSB
CANdb++ Editor中,都表示成(注意大小寫):
msb ... ... lsb
不過我認為這樣理解起來更加混亂,因此我們還是按照MSB和LSB來看。
這兩種字節(jié)序的信號在報文中的排列規(guī)則也不同。為了解釋這些規(guī)則,我們假如報文的DLC為8,也就是報文中含有8字節(jié)的數(shù)據(jù),共8 * 8 = 64 bit
。把每一位都列在一張表中。
如果位編號從右至左(R2L),那么:
7 6 5 4 3 2 1 0 -------------------------------- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
如果位編號從左至右(L2R),那么:
0 1 2 3 4 5 6 7 -------------------------------- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
這兩種編號方式中,字節(jié)的編號是一樣的,位的編號不同。CAN報文是串行發(fā)送的,CAN節(jié)點在發(fā)送報文時,不論如何編號,總是從表的左上第一位開始發(fā)送。從左至右,從上至下。
x x x x x x x x -------------------------------- 1st 2nd 3rd 4th 5th 6th 7th 8th | 0 ... ... ... ... ... ... ... ... | 1 ... ... ... ... ... ... ... ... | 2 ... ... ... ... ... ... ... ... | 3 ... ... ... ... ... ... ... ... | 4 ... ... ... ... ... ... ... ... | 5 ... ... ... ... ... ... ... ... | 6 ... ... ... ... ... ... ... last| 7
上面說到不同字節(jié)序(格式)的信號在報文中的排列規(guī)則也不同:Intel格式的信號的每位,從MSB到LSB,按照從右至左,從上至下的順序排列(向右上角塞):
x x x x x x x x -------------------------------- >.. ... ... ... ... ... ... MSB | 0 LSB ... ... ..> | 1 | 2 | 3 | 4 | 5 | 6 | 7
在CANdb++中看時,記得把MSB和LSB分別換成lsb和msb(注意順序)。
而Motorola格式的信號,從MSB到LSB,按照每位從左至右,從上至下排列(向左上角塞):
x x x x x x x x -------------------------------- MSB ... ... ... ... ... ... ..< | 0 <.. ... ... LSB | 1 | 2 | 3 | 4 | 5 | 6 | 7
在CANdb++中看時,記得把MSB和LSB分別換成msb和lsb。
<
或者>
表示信號的銜接點。通常一個Message中只應該含有同一種格式的信號。否則:
x x x x x x x x -------------------------------- >l e t n I ... ... MSB | 0 LSB ... ... ..> | 1 MSB ... M o t o r o< | 2 <l a ... LSB | 3 | 4 | 5 | 6 | 7
于是Intel向左上擠,占據(jù)了12個位。Motorola向右上擠就只能從byte2開始排列了,中間的4位不得不空出來。
至此應該沒有太多問題,不過接下來才是混亂的:Intel格式的信號有2種表示方法Intel Standard
和Intel Sequential
:
Intel Standard表示法:
7 6 5 4 3 2 1 0 -------------------------------- | 0 >.. ... ... MSB | 1 LSB ... ... ... ... ... ... ..> | 2 | 3
這種表示法使用從右至左的位編號方式。例子中我們假設前12位(bit0~11)已經(jīng)被其它信號占滿了。這個信號起始位為MSB,即:12。說出Intel Standard、起始位12、長度12位,就能在Message中確定Singal的位置了。
Intel Sequential表示法:
0 1 2 3 4 5 6 7 -------------------------------- | 0 >.. ... ... MSB | 1 LSB ... ... ... ... ... ... ..> | 2 | 3
這種表示法使用從左至右的位編號方式。前12位(bit7~0, 15~12)已經(jīng)被占,這個信號起始位為MSB,即:11。
Motorola式的信號有4種表示方法,分別是:Motorola Forward LSB
, Motorola Forward MSB
,
Motorola Sequential
, Motorola Backward
。
Motorola Forward LSB:
7 6 5 4 3 2 1 0 -------------------------------- | 0 MSB ... ... ..< | 1 <.. ... ... ... ... ... ... LSB | 2 | 3
從右至左編號方式,起始位為LSB,即:16。
Motorola Forward MSB:
7 6 5 4 3 2 1 0 -------------------------------- | 0 MSB ... ... ..< | 1 <.. ... ... ... ... ... ... LSB | 2 | 3
從右至左編號方式,起始位為MSB,即:11。
Motorola Sequential:
0 1 2 3 4 5 6 7 -------------------------------- | 0 MSB ... ... ..< | 1 <.. ... ... ... ... ... ... LSB | 2 | 3
從左至右編號方式,起始位為MSB,即:12。
也許你覺得最后一種方法應該是從左至右編號,起始位為LSB,但是世間萬物總是那么不如意。
Motorola Backward:
7 6 5 4 3 2 1 0 -------------------------------- | 3 MSB ... ... ..< | 2 <.. ... ... ... ... ... ... LSB | 1 | 0
非常費解的編號方式,它的字節(jié)編號是從下到上,位編號從右到左,起始位置為LSB,即8。
針對兩種格式信號使用的表示法可以在CANdb++ Editor菜單欄的Option > Settings > Display
中設置。但不論設置如何,數(shù)據(jù)庫進行儲存時,Intel格式使用Intel Sequential表示法儲存,Motorola格式使用Motorola Sequential表示法儲存,避免在設置不同的編輯器中打開時出現(xiàn)誤解。
在這份教程里,我們都使用Motorola格式的信號,并且使用Motorola Forward MSB式的表示方法。它應該和很多人(比如我)的第一感覺相同。
第一份CAN數(shù)據(jù)庫
現(xiàn)在讓我們著手建立一份簡單的CAN數(shù)據(jù)庫。它有1個信號,1條報文,2個節(jié)點分別作為收發(fā)節(jié)點,1個環(huán)境變量用來演示其使用。當然,不用說,有1個網(wǎng)絡。
CANdb++ Editor中,使用File > Create Database...
來新建一個叫candb.dbc
的數(shù)據(jù)庫,程序會詢問你使用的模板。不同模板的區(qū)別在于每個對象的屬性多少。越復雜的模板屬性越多,這里我們使用最簡單的EmptyTemplate.dbc
在CANdb++ Editor默認打開的Overall View窗口的左側,我們可以看到各個對象的分類。如果不是的話,找菜單欄View > Overall View
。
建立節(jié)點
在Newwork noedes上右鍵新建,
Name: ECM
同樣再新建一個:
Name: METER
建立報文
在Message上右鍵,新建:
Name: EngineState Type: CAN Standard ID: 0x1 DLC: 1
Transmitters中,點擊Add...
,選擇ECM。
建立信號
在Singal上點擊右鍵,New...
,之后輸入:
Name: Speed Length[bit]: 8 Byte Order: Motorola Value Type: Unsigned Unit: m/s Factor: 0.1 Offset: 0 Minimum: 0 Maximum: 25.5
Messages頁中點擊Add...
,選擇EngineState。
編輯報文信號
展開左側Messages下的EngineState,右鍵點擊Speed,選擇Edit Mapped Singal
。
Startbit[bit]: 7
Receivers頁中點擊Add...
,選擇METER。
建立環(huán)境變量
在左側Environment variables上右鍵新建
Name: env_speed Value Type: Float Access: Read Unit: m/s Initial Value: 0 Minimum: 0 Maximum: 25.5
Control units頁中添加ECM。
再次確認一下,使用View > Communication Matrix
非常好,我們的數(shù)據(jù)庫如此精煉。數(shù)據(jù)庫的教程至此,保存在<project>\database
文件夾中吧。
額外的說明
Vector的CANdb數(shù)據(jù)庫其實是一個編碼為ANSI的文本文件,可以使用任何文本編輯器打開。其結構可以參考Vector的DBC File Format Documentation,在官網(wǎng)似乎搜不到這份文件,就只有提供民間版本了。
這在你有了某種結構的數(shù)據(jù)庫文件(比如表格文件格式),想要轉換成Vector的dbc文件的,可以寫程序轉換,而不是手動輸入。