CAN通訊工作原理個人心得
CAN匯流排結構示意圖:
說明: 1:CAN收發器(示意圖中的單元)根據兩匯流排CAN_H和CAN_L的電位差來判斷匯流排電平;
2:實際中CAN_H與CAN_L由雙絞線組成;
3:資料傳遞終端的電阻器,是為了避免資料傳輸反射回來,使資料遭到破壞;
4:電阻阻值為120Ω;
5:CAN通訊實際上為單元之間的資料傳輸
CAN通訊單元的組成:
每個通訊單元軟體部分由資料幀、遙控幀、錯誤幀、過載幀、幀間隔組成;但不是上述5種幀都包含,具體看軟體怎樣編寫
1 資料幀的傳送
1) 資料幀的組成(遙控幀與資料幀的組成類似,只是不包含資料幀的資料段)
2)STM32軟體編寫傳送資料幀及解釋(遙控幀與資料幀的組成類似,只是不包含資料幀的資料段)
u8 CAN_Send_Msg(u8* msg,u8 len)
{
u8 mbox;
u16 i=0;
CanTxMsg TxMessage; //結構體的具體元素可查詢STM32資料庫手冊
TxMessage.StdId=0x12; //報文的11位標準識別符號,範圍0x000~0x7FF (設定資料幀的仲裁段的標準表示符)
//TxMessage.ExtId=0x12; //報文的29位擴充套件識別符號,範圍0x00000000~0x1FFFFFFF,由於IDE選擇為0,此元素可以不設定 (設定資料幀的仲裁段的擴充套件識別符號)
TxMessage.IDE=0; // IDE 0:選擇使用標準識別符號 1:選擇使用擴充套件識別符號 (設定資料幀的仲裁段的選擇)
TxMessage.RTR=0; // RTR 0:選擇傳送資料幀 1:選擇傳送遙控幀 (設定資料幀的控制段)
TxMessage.DLC=len; //DLC的大小為傳送資料的長度,len最大為8,因為一個報文包含0~8個位元組資料 (設定資料幀的控制段)
for(i=0;i<len;i++)
TxMessage.Data[i]=msg[i]; // 給資料幀的資料賦值
mbox= CAN_Transmit(CAN1, &TxMessage);
i=0;
while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)) //檢測資料的傳送狀態。如果失敗,等到i加到0xFFF退出迴圈,並返回"1";成功則返回"0".
i++;
if(i>=0XFFF)
return 1;
return 0;
}
2 過濾器
在CAN協議裡,報文的識別符號不代表節點的地址,而是跟報文的內容相關的。因此,傳送者以廣播的形式把報文傳送給所有接受者。節點在接收報文時,根據識別符號的值,決定軟體
是否需要該報文;如果需要,就拷貝到SRAM裡;如果不需要,報文就被丟棄且無需軟體的干預。
比如示意圖中: 單元1要傳送報文,它會將報文傳送給單元2、單元3、單元4、單元5,而單元2、單元3、單元4、單元5會根據識別符號的值,決定是否接收改報文。
為了知道哪些報文需要接收,哪些需要放棄,所以在此過程中,引入過濾器。通過過濾器來接收需要的報文。
1 幾個重要概念
1) 過濾器組
STM32總共提供14個過濾器組來處理CAN接收過濾問題,每個過濾器組包含兩個32位暫存器,即CAN_FiR0和CAN_FiR1組成(i=0~13),在設定為遮蔽位模式下,其中一個作為標
識符暫存器,另一個作為遮蔽碼暫存器。過濾器組中的每個過濾器,編號(叫做過濾器號)從0開始,到某個最大數值(這時最大值並非13,而是取決於14個過濾器組的模式和位寬的設
置,當全部配置為位寬為16,且為識別符號列表模式時,最大編號為14*4-1=55)。
F0R1 | F0R2 | F1R1 | F1R2 | F2R1 | F2R2 | F3R1 | F3R2 | F4R1 | F4R2 | F5R1 | F5R2 | F6R1 | F6R2 | F7R1 | F7R2 | F8R1 | F8R2 | F9R1 | F9R2 | F10R1 | F10R2 | F11R1 | F11R2 | F12R1 | F12R2 | F13R1 | F13R2 |
2 過濾器過濾模式
過濾器過濾模式有遮蔽位模式和過濾器列表模式
1)遮蔽位模式
為了過濾出一組識別符號,應該設定過濾器組工作在遮蔽位模式;
在遮蔽位模式下,識別符號暫存器和遮蔽暫存器一起,指定報文識別符號的任何一位,應該按照“必須匹配”或“不用關心”處理。
2)過濾器列表模式
為了過濾出一個識別符號,應該設定過濾器組工作在識別符號列表模式;
在識別符號列表模式下,遮蔽暫存器也被當作識別符號暫存器用。因此,不是採用一個識別符號加一個遮蔽位的方式,而是使用2個識別符號暫存器。接收報文識別符號的每一位都必須跟過濾
器識別符號相同。
3)過濾器的位寬
每個過濾器組的位寬都可以獨立配置,以滿足應用程式的不同需求。根據位寬的不同,每個過濾器組可提供:
• 1個32位過濾器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
• 2個16位過濾器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
4)過濾器組的位寬模式和位寬設定
看手冊
5)過濾器匹配序號及優先規則
看手冊
2 CAN ID的分析
1) CAN ID分析
標準識別符號:ID28~ID18
擴充套件識別符號: ID28~D18 加上 ID17~D0
eg1:有標準識別符號為:
0x6D1 (b 110 1101 0001) 佔用ID的ID28~ID18,共11位
eg2:有擴充套件識別符號為:
0x1EFEDFEA (b 1 1110 1111 1110 1101 1111 1110 1010) 其中紅色部分為基本識別符號 粉色部分為擴充套件識別符號
2)位寬為32位的遮蔽模式分析
如上圖所示:此種模式下,過濾器包含一個32位的識別符號暫存器和一個32位的遮蔽暫存器,灰色部分顯示的是與CAN ID各位定位的對映關係。由圖可以看出映像關係恰好等於擴充套件
CAN ID左移3位再加上IDE、RTR及一個顯性電平得到。
所以如何將CAN ID所表示的各部分如何針對過濾器暫存器各部分對號入座,其主要是掌握其核心思想即可:1:在各種過濾器模式下,CAN ID與暫存器相應位置一定要匹配;2:在
遮蔽方式下,遮蔽暫存器某位為1表示接收到的CAN ID對應的位必須對驗證碼暫存器對應的位相同。
eg:下面以程式碼例子,假設我們要接收多個ID:0x6D1 , 1EFEDFEA, 前面為標準識別符號,後面為擴充套件識別符號,要同時能接收這兩個識別符號的情況來配置過濾器
u16 Std_ID =0x6D1;
u32 Ext_ID =0x1EFEDFEA;
u32 mask =0;
CAN_FilterInitTypeDef CAN_FilterInitStructure; //定義一個結構體變數
CAN_FilterInitStructure.CAN_FilterNumber=0; //設定過濾器組0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //設定過濾器組0為遮蔽模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //設定過濾器組0位寬為32位
/**************************************************************************************************************************************
識別符號暫存器的設定,Ext_ID<<3對齊,再>>16取高16位
***************************************************************************************************************************************/
CAN_FilterInitStructure.CAN_FilterIdHigh=((Ext_ID<<3) >>16) & 0xffff; //設定識別符號暫存器高位元組。
CAN_FilterInitStructure.CAN_FilterIdLow=(u16)(Ext_ID<<3) | CAN_ID_EXT; //設定識別符號暫存器低位元組
/***********************************************************************************************************************************
這裡也可以這樣設定,設定識別符號暫存器高位元組.這裡為什麼是左移5位呢?從上圖可以看出,CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],標準CAN ID本身是不包
含擴充套件ID資料,因此為了要將標準CAN ID放入此暫存器,標準CAN ID首先應左移5位後才能對齊。設定識別符號暫存器低位元組,這裡也可以設定為CAN_ID_STD
CAN_FilterInitStructure.CAN_FilterIdHigh=Std_ID<<5;
CAN_FilterInitStructure.CAN_FilterIdLow=0 | CAN_ID_EXT;
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*************************************************************************************************************************
遮蔽暫存器的設定這裡的思路是先將標準CAN ID和擴充套件CAN ID對應的ID值先異或後取反,為什麼?異或是為了找出兩個CAN ID有哪些位是相同的,是相同的位則說明需
要關心,需要關心的位對應的遮蔽碼位應該設定為1,因此需要取反一下。最後再整體左移3位。
****************************************************************************************************************************/
mask =(Std_ID<<18); //這裡為什麼左移18位?因為在標準CAN ID佔ID18~ID28,為了與CAN_FilterIdHigh對齊,應左移2位,接著為了與擴充套件
CAN對應,還應該再左移16位,因此,總共應左移2+16=18位。也可以用另一個方式來理解:直接看Mapping的內容,發現STDID相對EXID[0]偏移了18位,因此左移18位.
mask ^=Ext_ID; //將對齊後的標準CAN與擴充套件CAN異或後取反
mask =~mask;
mask <<=3; //再整體左移3位
mask |=0x02; //只接收資料幀,不接收遠端幀
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //設定遮蔽暫存器高位元組
CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff; //設定遮蔽暫存器低位元組
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此過濾器組關聯到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //啟用此過濾器組
CAN_FilterInit(&CAN_FilterInitStructure); //設定過濾器
3)位寬為32位的識別符號列表模式
U16 std_id =0x6D1;
U32 ext_id =0x1EFEDFEA;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber=0; //設定過濾器組0,範圍為0~13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; //設定過濾器組0為識別符號列表模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //設定過濾器組0位寬為32位
//設定遮蔽暫存器,這裡當識別符號暫存器用
CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ; //為什麼左移5位?與上面相同道理,這裡不再重複解釋
CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //設定識別符號暫存器低位元組,CAN_FilterIdLow的ID位可以隨意設定,在此模式下不會有效。
//設定識別符號暫存器
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //設定遮蔽暫存器高位元組
CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT; //設定遮蔽暫存器低位元組
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此過濾器組關聯到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //啟用此過濾器組
CAN_FilterInit(&CAN_FilterInitStructure); //設定過濾器
4)16位位寬遮蔽模式
5)16位位寬列表模式