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

  

 

  6)屏蔽位模式的理解

    假如過濾器組0工作在,位寬為32位標識符屏蔽模式:  

    設置         CAN_F0R1=0xFFFF 0000;           

                    CAN_F0R2=0xFF00 FF00
                      其中存放到 CAN_F0R1 的值是期望收到的ID,即我們希望收到的映像(STID+EXTID+IDE+RTR),最好是:FFFF 0000

                      而 CAN_F0R2中的0xFF00 FF00就是我們需要關心的ID,表示收到的映像。其位[31:24]和[15:8]這16個位,必須和CAN_F0R1中對應的一模一樣,而另外的16個位則不

                     必關心,可以一樣也可以不一樣,都認為是正確的ID,即收到的映像必須是0xFFXX00XX,才算是正確的(X表示不關心)。也就是說屏蔽位CAN_F0R2中的數值:

                     1:必須匹配,到來的標識符位必須和過濾器對應的標識符寄存器位相一致

                     0:不關心,可以一樣,也可以不一樣,都認為是正確的ID

               因此:

                     為了過濾出一組標識符,應該設置過濾器組工作在屏蔽模式

                     為了過濾出一個標識符,應該設置過濾器組工作在標識符列表模式

 


免責聲明!

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



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