STM32的CAN過濾器-bxCAN的過濾器的4種工作模式以及使用方法總結

1. 前言

bxCAN是STM32系列最穩(wěn)定的IP核之一蛛株,無論有哪個新型號出來扔字,這個IP核基本未變,可見這個IP核的設計是相當成熟的格嘁。本文所講述的內容屬于這個IP核的一部分笛求,掌握了本文所講內容,就可以很方便地適用于所有STM32系列中包含bxCAN外設的型號糕簿。有關bxCAN的過濾器部分的內容在參考手冊中往往看得“不甚明白“涣易,本文就過濾器的4種工作模式進行詳細講解并使用具體的代碼進行演示,這些代碼都進行過實測驗證通過的冶伞,希望能給讀者對于bxCAN過濾器有一個清晰的理解新症。

2. 準備工作

2.1.???為什么要過濾器?

在這里响禽,我們可以將CAN總線看成一個廣播消息通道徒爹,上面?zhèn)鬏斨鞣N類型的消息瓷翻,好比報紙如叼,有體育新聞卵牍,財經新聞闯团,政治新聞扒寄,還有軍事新聞身弊,每個人都有自己的喜好丸边,不一定對所有新聞都感興趣儿普,因此贮竟,在看報紙的時候丽焊,一般人都是只看自己感興趣的那類新聞较剃,而過濾掉其他不感興趣的內容。那么我們一般是怎么過濾掉那些不感興趣的內容的呢技健?下面有兩種方法來實現這個目的:

第一種方法:

???????? 每次看報紙時写穴,你都看下每篇文章的標題,如果感興趣則繼續(xù)看下去雌贱,如果不感興趣啊送,則忽略掉。

第二種方法:

???????? 你告訴郵遞員欣孤,你只對財經新聞感興趣馋没,請只將財經類報紙送過來,其他的就不要送過來了降传,就這樣披泪,你看到的內容必定是你感興趣的財經類新聞。

上面那種方法好呢搬瑰?很明顯款票,第二種方法是最好的,因為你不用自己每次判斷哪些新聞內容是你感興趣的泽论,可以免受“垃圾”新聞干擾艾少,從而可以節(jié)省時間忙其他事。bxCAN的過濾器就是采用上述第二種方法翼悴,你只需要設置好你感興趣的那些CAN報文ID缚够,那么MCU就只能收到這些CAN報文,是從硬件上過濾掉鹦赎,完全不需要軟件參與進來谍椅,從而節(jié)省了大大節(jié)省了MCU的時間,可以更加專注于其他事務古话,這個就是bxCAN過濾器的意義所在雏吭。

2.2.???兩種過濾模式(列表模式與掩碼模式)

假設我們是bxCAN這個IP的設計者,現在由我們來設計過濾器陪踩,那么我們該如何設計呢杖们?

首先我們是不是很快就會想到只要準備好一張表,把我們需要關注的所有CAN報文ID寫上去肩狂,開始過濾的時候只要對比這張表摘完,如果接收到的報文ID與表上的相符,則通過傻谁,如果表上沒有孝治,則不通過,這個就是簡單的過濾方案。恭喜你谈飒!bxCAN過濾器的列表模式采用的就是這種方案岂座。


但是,這種列表方案有點缺陷步绸,即如果我們只關注一個報文ID掺逼,則需要往列表中寫入這個ID吃媒,如果需要關注兩個瓤介,則需要寫入兩個報文ID,如果需要關注100個赘那,則需要寫入100個刑桑,如果需要1萬個,那么需要寫入1萬個募舟,可問題是祠斧,有這個大的列表供我們使用嗎?大家都知道拱礁,MCU上的資源是有限的琢锋,不可能提供1萬個或更多,甚至100個都嫌多呢灶。非常明顯吴超,這種列表的方式受到列表容量大小的限制,實際上鸯乃,bxCAN的一個過濾器若工作在列表模式下,scale為32時鲸阻,每個過濾器的列表只能寫入兩個報文ID,若scale為16時缨睡,每個過濾器的列表最多可寫入4個CAN ID鸟悴,由此可見,MCU的資源是非常非常有限的奖年,并不能任我們隨心所欲细诸。因此,我們需要考慮另外一種替代方案陋守,這種方案應該不受到數量限制揍堰。


下面假設我們是古時候一座城鎮(zhèn)的守衛(wèi),城主要求只有1156年出生的人才可以進城嗅义,我們又該如何執(zhí)行呢屏歹?假設古時候的人也有類似今天的身份證(...->_<-…),大家都知道,身份份證號碼中有4位是表示出生年月之碗,如下圖:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 1 18位身份證號碼的各位定義

如上圖蝙眶,身份證中第7~10這4位數表示的是出生年份,那么,我們可以這么執(zhí)行:

檢查想要進城的所有人的身份證號碼的第7~10位數字幽纷,如果這個數字依次為1156則可以進入式塌,否則則不可以,至于身份證號碼的其他位則完全不關心友浸。假如過幾天城主放寬進城條件為只要是1150年~1160前的人都可以進城峰尝,那么,我們就可以只關注身份證號碼的第7~9這3位數是否為115就可以了收恢,對不對武学?這樣一來,我們就可以非常完美地執(zhí)行城主的要求了伦意。

再變下火窒,假設現在使用機器來當守衛(wèi),不再是人來執(zhí)行這個“篩選”工作驮肉。機器是死的熏矿,沒有人那么靈活,那么機器又該如何執(zhí)行呢离钝?

對于機器來說票编,每一步都得細化到機器可以理解的程度,于是我們可以作如下細化:

第一步:獲取想進城的人的身份證號碼

第二步:只看獲取到身份證的第7~9位卵渴,其他位忽略

第三步:將忽略后的結果與1156進行比較

第四步:比較結果相同則通過慧域,不同則不能通過

這種方式,我們稱之為掩碼模式奖恰。

2.3.???驗證碼與屏蔽碼

仔細查看上面4個步驟吊趾,這不就是C代碼中的if語句嗎?如下:



if( x & y ==z) //x表示待檢查身份證號碼瑟啃,y表示只關注第7~9位的屏蔽碼论泛,Z則為1156,這里叫做驗證碼

{

//可以通過

}

else

{

//不可以通過

}



對于機器來說蛹屿,我們要為它準備好兩張紙片屁奏,一片寫上屏蔽碼,另一片紙片寫上驗證碼错负,屏蔽碼上相應位為1時坟瓢,表示此位需要與驗證碼對應位進行比較,反之犹撒,則表示不需要折联。機器在執(zhí)行任務的時候先將獲取的身份證號碼與屏蔽碼進行“與”操作,再將結果與驗證碼的進行比較识颊,根據判斷是否相同來決定是否通過诚镰。整個判別流程如下所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 2 掩碼模式的計算過程

從上圖可以很容易地理解屏蔽碼與驗證碼的含義,這樣一來,能通過的結果數量就完全取決于屏蔽碼清笨,設得寬月杉,則可以通過的多(所有位為0,則不過任何過濾操作抠艾,則誰都可以通過)苛萎,設得窄,則通過的少(所有位設為1检号,則只有一個能通過)腌歉。那么知道這個有什么用呢?因為bxCAN的過濾器的掩碼模式就是采用這種方式谨敛,在bxCAN中究履,分別采用了兩個寄存器(CAN_FiR1,CAN_FiR2)來存儲屏蔽碼與驗證碼滤否,從而實現掩碼模式的工作流程的脸狸。這樣,我們就知道了bxCAN過濾器的掩碼模式的大概工作原理。

但是藐俺,我們得注意到炊甲,采用掩碼模式的方式并不能精確的對每一個ID進行過濾,打個比方欲芹,還是采用之前的守衛(wèi)的例子卿啡,假如城主要求只有1150~1158年出生的人能通過,那么菱父,若我們還是才用掩碼模式颈娜,那么掩碼就設為第7~9位為”1”,對應的浙宜,驗證碼的7~9位分別為”115”官辽,這樣就可以了。但是粟瞬,仔細一想同仆,出生于1159的人還是可以通過,是不是裙品?但總體來說俗批,雖然沒有做到精確過濾,但我們還是能做到大體過濾的市怎,而這個就是掩碼模式的缺點了岁忘。在實際應用時,取決于需求区匠,有時我們會同時使用到列表模式和掩碼模式干像,這都是可能的。

2.4.???列表模式與掩碼模式的對比

綜合之前所述,下面我們來對比一下列表模式與掩碼模式這兩種模式的優(yōu)缺點蝠筑。

2.5.???標準CAN ID與擴展CAN ID

1986 年德國電氣商BOSCH公司開發(fā)出面向汽車的CAN 通信協(xié)議狞膘,剛開始的時候,CAN ID定義為11位什乙,我們稱之為標準格式挽封,ISO11898-1標準中CAN的基本格式如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 3 標準CAN報文格式定義

如上圖所示,標準CAN ID存放在上圖ID18~ID28中臣镣,共11位辅愿。隨著工業(yè)發(fā)展,后來發(fā)現11位的CAN ID已經不夠用忆某,于是就增加了18位点待,擴展CAN ID到29位,如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 4 擴展CAN報文格式定義

從上圖對比擴展CAN報文與標準CAN報文弃舒,發(fā)現在仲裁域部分癞埠,擴展CAN報文的CAN ID包含了base Identifier與extension Identifier,即基本ID與擴展ID聋呢,而標準CAN報文的CAN ID部分只包含基本ID苗踪,擴展ID(ID0~ID17)被放在基本ID的右方,也就是說,屬于低位。知道這些有什么用呢削锰?至少我們可以得到這兩條信息:

?標準ID一般小于或等于<=0x7FF(11位)通铲,只包含基本ID。

對于擴展CAN的低18位為擴展ID器贩,高11位為基本ID颅夺。

例如標準CAN ID 0x7E1,二進制展開為0b 0[111 1110 0001] ,只有中括號內的11位才有效蛹稍,其全部是基本ID吧黄。

再例如擴展CAN ID 0x1835f107,二進制展開為0b 000[1 1000 0011 10][01 11110001 0000 0111],只有紅色中括號和綠色中括號內的位才有效稳摄,總共29位稚字,左邊紅色中括號中的11位為基本ID,右邊綠色中括號內的18位為擴展ID厦酬,請記住這個信息胆描!知道這個之后,我們可以很方便地將一個CANID拆分成基本ID和擴展ID仗阅,這個也將在后續(xù)的內容中多次用到昌讲,再次留意一下,擴展ID是位于基本ID的右方减噪,在擴展CAN ID的構成中短绸,擴展ID位于低18位车吹,而基本ID位于高11位,于是要獲取一個擴展CANID的基本ID醋闭,就只需要將這個CANID右移18位(這種算法后續(xù)將多次用到,請務必記住!)窄驹。

3. bxCAN的過濾器的解決方案

終于進入到正題了!前面已經介紹了過濾器的列表模式與掩碼模式证逻,以及掩碼模式下的屏蔽碼與驗證碼的含義乐埠,還介紹了標準CAN ID與擴展CAN ID的組成部分。現在我們終于要站在bxCAN的角度來分析其過濾方案囚企。

首先過濾模式分列表模式和掩碼模式,因此,對于沒有過濾器,我們需要這么一個位來標記,用戶可以通過設置這個位來標記他到底是想要這個過濾器工作在列表模式下還是掩碼模式,于是,這個表示過濾模式的位就定義在CAN_FM1R寄存器中的FBMx位上丈咐,如下圖:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖5 CAN過濾器模式寄存器CAN_FM1R定義

這里以STM32F407為例,bxCAN共有28個過濾器龙宏,于是上圖的每一個位對應地表示這28個過濾器的工作模式棵逊,供用戶設置∫铮”0”表示掩碼模式辆影,”1”表示列表模式。

另外花吟,我們知道了標準CAN ID位11位秸歧,而擴展CAN ID有29位厨姚,對于標準的CAN ID來說衅澈,我們有一個16位的寄存器來處理他足夠了,相應地谬墙,擴展CAN ID今布,我們就必須使用32位的寄存器來處理它,而在實際應用中拭抬,根據需求部默,我們可能自始至終都只需要處理11位的CAN ID。對于資源嚴重緊張的MCU環(huán)境來說造虎,本著不浪費的原則傅蹂,這里最好能有另外一個標志用告訴過濾器是否需要處理32位的CAN ID。于是算凿,bxCAN處于這種考慮份蝴,也設置了這么一個寄存器CAN_FS1R來表示CAN ID的位寬,如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖6 CAN過濾器位寬寄存器CAN_FS1R定義

如上圖氓轰,每一個位對應著bxCAN中28個過濾器的位寬婚夫,這個需要用戶來設置。

于是根據模式與位寬的設置署鸡,我們共可以得出4中不同的組合:32位寬的列表模式案糙,16位寬的列表模式限嫌,32位寬掩碼模式,16位寬的掩碼模式时捌。如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 7 CAN過濾器的4中工作模式

在bxCAN中怒医,每個過濾器都存在這么兩個寄存器CAN_FxR1和CAN_FxR2,這兩個寄存器都是32位的奢讨,他的定義并不是固定的裆熙,針對不同的工作模式組合他的定義是不一樣的,如列表模式-32位寬模式下禽笑,這兩個寄存器的各位定義都是一樣的入录,都用來存儲某個具體的期望通過的CAN ID,這樣就可以存入2個期望通過的CAN ID(標準CAN ID和擴展CAN ID均可)佳镜;若在掩碼模式-32位寬模式下時僚稿,則CAN_FxR1用做32位寬的驗證碼,而CAN_FxR2則用作32位寬的屏蔽碼蟀伸。在16位寬時蚀同,CAN_FxR1和CAN_FxR2都要各自拆分成兩個16位寬的寄存器來使用,在列表模式-16位寬模式下啊掏,CAN_FxR1和CAN_FxR2定義一樣蠢络,且各自拆成兩個,則總共可以寫入4個標準CAN ID迟蜜,若在16位寬的掩碼模式下刹孔,則可以當做2對驗證碼+屏蔽碼組合來用,但它只能對標準CAN ID進行過濾娜睛。這個就是bxCAN過濾器的解決方案髓霞,它采用了這4種工作模式。

接下來將分別介紹過濾器的4中工作模式以及所對應的代碼示例畦戒。

4.2.???32位寬的列表模式


? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖11 32位寬下的CAN_FxR1與CAN_FxR2各位定義

如上圖所示方库,在32位寬的列表模式下,CAN_FxR1與CAN_FxR2都用來存儲希望通過的CAN ID障斋,由于是32位寬的纵潦,因此既可以存儲標準CAN ID,也可以存儲擴展CAN ID垃环。注意看上圖最底下的各位定義邀层,可以看出,從右到左晴裹,首先被济,最低位是沒有用的,然后是RTR涧团,表示是否為遠程幀只磷,接著IDE经磅,擴展幀標志,然后才是EXID[0:17]這18位擴展ID钮追,最后才是STID[0:10]這11位標準ID预厌,也就是前面所說的基本ID。在進行配置的時候元媚,即將希望通過的CAN ID寫入的時候轧叽,要注意各個位對號入座,即基本ID放到對應的STD[0:10]刊棕,擴展ID對應放到EXID[0:17],若是擴展幀炭晒,則需要將IDE設為“1”,標準幀則為“0”甥角,數據幀設RTR為“0”网严,遠程幀設RTR為“1”。示例代碼如下:


static void CANFilterConfig_Scale32_IdList(void)

{

? CAN_FilterConfTypeDef? sFilterConfig;

? uint32_t StdId =0x321; //這里寫入兩個CAN ID嗤无,一個位標準CAN ID

? uint32_t ExtId =0x1800f001; //一個位擴展CAN ID


? sFilterConfig.FilterNumber = 0; //使用過濾器0

? sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //設為列表模式

? sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //配置為32位寬

? sFilterConfig.FilterIdHigh = StdId<<5; //基本ID放入到STID中

? sFilterConfig.FilterIdLow = 0|CAN_ID_STD; //設置IDE位為0

? sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;

? sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT; //設置IDE位為1

? sFilterConfig.FilterFIFOAssignment = 0; //接收到的報文放入到FIFO0中

? sFilterConfig.FilterActivation = ENABLE;

? sFilterConfig.BankNumber = 14;


? if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

? {

? ? Error_Handler();

? }

}



這里需要說明一下震束,由于我們使用的是cube庫,在cube庫中,CAN_FxR1與CAN_FxR2寄存器分別被拆成兩段,CAN_FxR1寄存器的高16位對應著上面代碼中的FilterIdHigh末荐,低16位對應著FilterIdLow,而CAN_FxR2寄存器的高16位對應著FilterMaskIdHigh嘉栓,低16位對應著FilterMaskIdLow,這個CAN_FilterConfTypeDef的的4個成員FilterIdHigh驰凛,FilterIdLow胸懈,FilterMaskIdHigh,FilterMaskIdLow恰响,不應該單純看其名字,被其名字誤導涌献,而應該就單純地將這4個成員看成4個uint_16類型的變量x,y,m,n而已胚宦,后續(xù)其他示例也是同樣理解,不再重復解釋燕垃。這4個16位的變量其具體含義取決于當前過濾器工作與何種模式枢劝,比如當前32位寬的列表模式下,FilterIdHigh與FilterIdLow一起用來存放一個CAN ID卜壕,FilterMaskIdHigh與FilterMaskIdLow用來存放另一個CAN ID您旁,不再表示其字面所示的mask含義,這點我們需要特別注意轴捎。

在上述代碼示例中鹤盒,我們分別將標準CAN ID和擴展CAN ID放入到CAN_FxR1與CAN_FxR2寄存器中蚕脏。對于標準CAN ID,對比圖11侦锯,由于標準CAN ID只擁有標準ID驼鞭,所以,只需要將標準ID放入到高16位的STID[0:10]中尺碰,高16位最右邊被EXID[13:17]占著挣棕,因此,需要將StdId左移5位才能剛好放入到CAN_FxR1的高16位中亲桥,于是有了:

sFilterConfig.FilterIdHigh = StdId<<5;

另一個擴展CAN ID ExtId類型洛心,將其基本ID放入到STID中,擴展ID放入到EXID中题篷,最后設置IDE位為1皂甘。就這樣配置好了。

4.3.???16位寬的列表模式

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖12 16位寬的列表模式

如上圖所示悼凑,在16位寬的列表模式下偿枕,FilterIdHigh,FilterIdLow户辫,FilterMaskIdHigh渐夸,FilterMaskIdLow這4個16位變量都是用來存儲一個標準CAN ID,這樣渔欢,就可以存放4個標準CAN ID了墓塌,需要注意地是,此種模式下奥额,是不能處理擴展CANID苫幢,凡是需要過濾擴展CAN ID的,都是需要用到32位寬的模式垫挨。于是有以下代碼示例:



static void CANFilterConfig_Scale16_IdList(void)

{

? CAN_FilterConfTypeDef? sFilterConfig;

? uint32_t StdId1 =0x123; //這里采用4個標準CAN ID作為例子

? uint32_t StdId2 =0x124;

? uint32_t StdId3 =0x125;

? uint32_t StdId4 =0x126;


? sFilterConfig.FilterNumber = 1; //使用過濾器1

? sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //設為列表模式

? sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //位寬設置為16位

? sFilterConfig.FilterIdHigh = StdId1<<5; //4個標準CAN ID分別放入到4個存儲中

? sFilterConfig.FilterIdLow = StdId2<<5;

? sFilterConfig.FilterMaskIdHigh = StdId3<<5;

? sFilterConfig.FilterMaskIdLow = StdId4<<5;

? sFilterConfig.FilterFIFOAssignment = 0; //接收到的報文放入到FIFO0中

? sFilterConfig.FilterActivation = ENABLE;

? sFilterConfig.BankNumber = 14;


? if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

? {

? ? Error_Handler();

? }

}



可見韩肝,列表模式還是非常好理解的。

4.4.???32位寬掩碼模式

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖13 32位寬掩碼模式

如上圖所示九榔,32位寬模式下哀峻,FilterIdHigh與FilterIdLow合在一起表示CAN_FxR1寄存器,用來存放驗證碼哲泊,而FilterMaskIdHigh與FilterMaskIdLow合在一起表示CAN_FxR2寄存器剩蟀,用來存放屏蔽碼,關于驗證碼與屏蔽碼的概念在之前的2.3節(jié)已經明確說明了切威,不清楚的可以回過去看看2.3節(jié)的內容育特。在32位寬的掩碼模式下,既可以過濾標準CAN ID先朦,也可以過濾擴展CAN ID缰冤,甚至兩者混合這來也是可以的犬缨,下面我們就這3中情況分別給出示例。

4.4.1. 只針對標準CAN ID

如下代碼示例:


static void CANFilterConfig_Scale32_IdMask_StandardIdOnly(void)

{

? CAN_FilterConfTypeDef? sFilterConfig;

? uint16_t StdIdArray[10] ={0x7e0,0x7e1,0x7e2,0x7e3,0x7e4,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x7e5,0x7e6,0x7e7,0x7e8,0x7e9}; //定義一組標準CAN ID

? uint16_t? ? ? mask,num,tmp,i;


? sFilterConfig.FilterNumber = 2; //使用過濾器2

? sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置為掩碼模式

? sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //設置為32位寬

? sFilterConfig.FilterIdHigh =(StdIdArray[0]<<5); //驗證碼可以設置為StdIdArray[]數組中任意一個锋谐,這里使用StdIdArray[0]作為驗證碼

? sFilterConfig.FilterIdLow =0;


? mask =0x7ff; //下面開始計算屏蔽碼

? num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);

? for(i =0; i<num; i++) //屏蔽碼位StdIdArray[]數組中所有成員的同或結果

? {

? ? tmp =StdIdArray[i] ^ (~StdIdArray[0]); //所有數組成員與第0個成員進行同或操作

? ? mask &=tmp;

? }

? sFilterConfig.FilterMaskIdHigh =(mask<<5);

? sFilterConfig.FilterMaskIdLow =0|0x02; //只接收數據幀


? sFilterConfig.FilterFIFOAssignment = 0; //設置通過的數據幀進入到FIFO0中

? sFilterConfig.FilterActivation = ENABLE;

? sFilterConfig.BankNumber = 14;


? if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

? {

? ? Error_Handler();

? }

}


如上代碼所示遍尺,與之前的標準CAN ID相比,擴展CAN ID的驗證碼與屏蔽碼放入到相對應的寄存器時所移動的位數與標準CAN ID時有所差別涮拗,其他的都一樣乾戏。

接下來是標準CAN ID與擴展CAN ID混合著來。

4.4.3. 標準CAN ID與擴展CAN ID混合過濾

如下代碼所示:


static void CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix(void)

{

? CAN_FilterConfTypeDef? sFilterConfig;

? //定義一組標準CAN ID

uint32_t StdIdArray[10] ={0x711,0x712,0x713,0x714,0x715,

? ? ? ? ? ? ? ? ? ? ? ? ? 0x716,0x717,0x718,0x719,0x71a};

? //定義另外一組擴展CAN ID

uint32_t ExtIdArray[10] ={0x1900fAB1,0x1900fAB2,0x1900fAB3,0x1900fAB4,0x1900fAB5,

? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x1900fAB6,0x1900fAB7,0x1900fAB8,0x1900fAB9,0x1900fABA};

? uint32_t? ? ? mask,num,tmp,i,standard_mask,extend_mask,mix_mask;


? sFilterConfig.FilterNumber = 4; //使用過濾器4

? sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置為掩碼模式

? sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //設為32位寬

? sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff; //使用第一個擴展CAN? ID作為驗證碼

? sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff);


? standard_mask =0x7ff; //下面是計算屏蔽碼

? num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);

? for(i =0; i<num; i++) //首先計算出所有標準CAN ID的屏蔽碼

? {

? ? tmp =StdIdArray[i] ^ (~StdIdArray[0]);

? ? standard_mask &=tmp;

? }


? extend_mask =0x1fffffff;

? num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);

? for(i =0; i<num; i++) //接著計算出所有擴展CAN ID的屏蔽碼

? {

? ? tmp =ExtIdArray[i] ^ (~ExtIdArray[0]);

? ? extend_mask &=tmp;

? }

? mix_mask =(StdIdArray[0]<<18)^ (~ExtIdArray[0]); //再計算標準CAN ID與擴展CAN ID混合的屏蔽碼

? mask =(standard_mask<<18)& extend_mask &mix_mask; //最后計算最終的屏蔽碼

? mask <<=3;? ? //對齊寄存器

? sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;

? sFilterConfig.FilterMaskIdLow = (mask&0xffff);

? sFilterConfig.FilterFIFOAssignment = 0;

? sFilterConfig.FilterActivation = ENABLE;

? sFilterConfig.BankNumber = 14;


? if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

? {

? ? Error_Handler();

? }

}


如上代碼所示三热,在混合的情況下鼓择,只需稍微修改下屏蔽碼的計算方式就可以了,其他的基本沒有什么變化就漾。

4.5.???16位寬掩碼模式

如下圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖14 16位寬的掩碼模式

如上圖所示呐能,在16位寬的掩碼模式下,CAN_FxR1的低16位是作為驗證碼抑堡,對應的16位屏蔽碼為CAN_FxR1的高16位摆出,同樣的,CAN_FxR2的低16位是作為驗證碼首妖,對應與CAN_FxR2的高16位為屏蔽碼偎漫。于是,其示例代碼如下:


static void CANFilterConfig_Scale16_IdMask(void)

{

? CAN_FilterConfTypeDef? sFilterConfig;

? uint16_t StdIdArray1[10] ={0x7D1,0x7D2,0x7D3,0x7D4,0x7D5, //定義第一組標準CAN ID

? ? ? ? ? ? ? ? ? ? ? ? ? 0x7D6,0x7D7,0x7D8,0x7D9,0x7DA};

? uint16_t StdIdArray2[10] ={0x751,0x752,0x753,0x754,0x755, //定義第二組標準CAN ID

? ? ? ? ? ? ? ? ? ? ? ? ? 0x756,0x757,0x758,0x759,0x75A};

? uint16_t? ? ? mask,tmp,i,num;


? sFilterConfig.FilterNumber = 5; //使用過濾器5

? sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置為掩碼模式

? sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //設為16位寬


? //配置第一個過濾對

? sFilterConfig.FilterIdLow =StdIdArray1[0]<<5; //設置第一個驗證碼

? mask =0x7ff;

? num =sizeof(StdIdArray1)/sizeof(StdIdArray1[0]);

? for(i =0; i<num; i++) //計算第一個屏蔽碼

? {

? ? tmp =StdIdArray1[i] ^ (~StdIdArray1[0]);

? ? mask &=tmp;

? }

? sFilterConfig.FilterMaskIdLow =(mask<<5)|0x10;? ? //只接收數據幀


? //配置第二個過濾對

? sFilterConfig.FilterIdHigh = StdIdArray2[0]<<5; //設置第二個驗證碼

? mask =0x7ff;

? num =sizeof(StdIdArray2)/sizeof(StdIdArray2[0]);

? for(i =0; i<num; i++) //計算第二個屏蔽碼

? {

? ? tmp =StdIdArray2[i] ^ (~StdIdArray2[0]);

? ? mask &=tmp;

? }

? sFilterConfig.FilterMaskIdHigh = (mask<<5)|0x10;? //只接收數據幀


? sFilterConfig.FilterFIFOAssignment = 0; //通過的CAN 消息放入到FIFO0中

? sFilterConfig.FilterActivation = ENABLE;

? sFilterConfig.BankNumber = 14;


if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

? {

? ? Error_Handler();

? }

}

如上代碼所示有缆,在這種模式下象踊,其特殊之處就是可以配置兩套驗證碼,屏蔽碼組合棚壁,可以分別相對獨立地對標準CAN ID進行過濾杯矩。

5. 總結

在實際的應用中,我們需要根據需求的實際情況來決定使用何種過濾配置袖外,在配置之前史隆,我們需要先將那些需要通過的CANID進行整理,若數量少在刺,則使用列表模式逆害,精準,若只有標準CAN ID蚣驼,則可以考慮使用16位寬模式,若需求中的CAN ID過多相艇,則可以考慮使用多個過濾器颖杏,部分使用列表模式,部分使用掩碼模式坛芽,CAN ID值相近的可以歸納成一組留储,使用掩碼模式進行過濾翼抠。但使用掩碼模式的同時,我們也需要意識到获讳,也有可能部分不期望的CAN ID也會通過過濾器阴颖,掩碼放得越寬,帶進其他CAN ID的幾率就越大丐膝,這點我們需要格外注意量愧,視情況進行應用判斷和處理。另外帅矗,對于相近的CAN ID偎肃,我們可以提前計算好屏蔽碼,直接在代碼中填入浑此,而不是在代碼中臨時計算累颂,這樣可以提高軟件效率,大家視情況而定凛俱。


原文鏈接:https://blog.csdn.net/flydream0/article/details/52317532



?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末紊馏,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子蒲犬,更是在濱河造成了極大的恐慌朱监,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暖哨,死亡現場離奇詭異赌朋,居然都是意外死亡,警方通過查閱死者的電腦和手機篇裁,發(fā)現死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門沛慢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人达布,你說我怎么就攤上這事团甲。” “怎么了黍聂?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵躺苦,是天一觀的道長。 經常有香客問我产还,道長匹厘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任脐区,我火速辦了婚禮愈诚,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己炕柔,他們只是感情好酌泰,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著匕累,像睡著了一般陵刹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上欢嘿,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天衰琐,我揣著相機與錄音,去河邊找鬼际插。 笑死碘耳,一個胖子當著我的面吹牛,可吹牛的內容都是我干的框弛。 我是一名探鬼主播辛辨,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瑟枫!你這毒婦竟也來了斗搞?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤慷妙,失蹤者是張志新(化名)和其女友劉穎僻焚,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體膝擂,經...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡虑啤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了架馋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狞山。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖叉寂,靈堂內的尸體忽然破棺而出萍启,到底是詐尸還是另有隱情,我是刑警寧澤屏鳍,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布勘纯,位于F島的核電站,受9級特大地震影響钓瞭,放射性物質發(fā)生泄漏驳遵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一山涡、第九天 我趴在偏房一處隱蔽的房頂上張望超埋。 院中可真熱鬧搏讶,春花似錦佳鳖、人聲如沸霍殴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽来庭。三九已至,卻和暖如春穿挨,著一層夾襖步出監(jiān)牢的瞬間月弛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工科盛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帽衙,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓贞绵,卻偏偏與公主長得像厉萝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子榨崩,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容