1. 程式人生 > >CAN通訊工作原理個人心得

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位位寬列表模式