18.1 CAN協(xié)議
18.1.1 協(xié)議概述
CAN是Controller Area Network的縮寫,最初是專門用于汽車網(wǎng)絡(luò)的通信協(xié)議,與485協(xié)議相似,CAN也是一種2線制,采用兩根線的電壓差進行數(shù)據(jù)傳輸?shù)膮f(xié)議,隨著CAN協(xié)議的高性能與可靠性被認同,現(xiàn)在被廣泛運用在工業(yè)自動化,船舶等當(dāng)面,目前最熱門的國六標(biāo)準(zhǔn),J1939通信協(xié)議就是以CAN協(xié)議為基礎(chǔ)設(shè)計的。
CAN協(xié)議最遠通信距離可達10km,與485相似,CAN也有兩種電平,分別為顯性電平與隱性電平,當(dāng)CAN_H與CAN_L電壓一致的時候為隱性電平,反之為顯性電平。實際上隱性電平代表邏輯電平1,顯性電平代表邏輯電平0,CAN在通信的時候,也需要在每個設(shè)備輸出端并聯(lián)1個120Ω的終端匹配電阻,用于進行阻抗匹配。
18.1.2 通信組成
CAN協(xié)議通過5種類型的幀進行數(shù)據(jù)通信:數(shù)據(jù)幀,遙控幀,錯誤幀,過載幀和間隔幀,其中數(shù)據(jù)幀與遙控幀具有標(biāo)準(zhǔn)格式與擴展格式兩種,標(biāo)準(zhǔn)格式有11個位的標(biāo)識符,擴展格式則有29個位的標(biāo)識符,五種幀的功能如下所示。
(1)數(shù)據(jù)幀:用于實際數(shù)據(jù)傳輸
(2)遙控幀:用于接收端向具有相同ID的發(fā)送端請求數(shù)據(jù)
(3)錯誤幀:用于檢測報錯時通知其他設(shè)備
(4)過載幀:用于接收端通報尚未準(zhǔn)備好接收準(zhǔn)備
(5)間隔幀:用于將數(shù)據(jù)幀與遙控幀和前面的幀分割
完整的數(shù)據(jù)幀構(gòu)成如下圖所示。
數(shù)據(jù)幀一般由7段組成:
(1)幀起始:即數(shù)據(jù)幀開始的段,標(biāo)準(zhǔn)幀和擴展幀都是由1個位的顯性電平表示幀起始
(2)仲裁段:表示該幀優(yōu)先級,標(biāo)準(zhǔn)幀和擴展幀格式在這一段結(jié)構(gòu)如下圖所示。
其中RTR位用于標(biāo)識是否是遠程幀(0代表數(shù)據(jù)幀;1代表遠程幀),IDE位為標(biāo)識符選擇位(0表示使用標(biāo)準(zhǔn)標(biāo)識符;1表示使用擴展標(biāo)識符),SRR位為代替遠程請求位,為隱性位,代替了標(biāo)準(zhǔn)幀中的RTR位。
(3)控制段:表示數(shù)據(jù)的字節(jié)數(shù)即保留位,由6個位構(gòu)成,表示數(shù)據(jù)段的字節(jié)數(shù)。標(biāo)準(zhǔn)幀和擴展幀的控制段結(jié)構(gòu)如下圖所示。
r0和r1為保留位,必須全部以顯性電平發(fā)送,但是接收端可以接收顯性、隱性及任意組合的電平。DLC段為數(shù)據(jù)長度表示段,高位在前,DLC段有效值為08,但是接收方接收到915的時候并不認為是錯誤。
(4)數(shù)據(jù)段:數(shù)據(jù)段內(nèi)容,一段可以發(fā)送0~8個字節(jié)的數(shù)據(jù),從最高位MSB開始輸出
(5)CRC校驗:CRC校驗數(shù)據(jù)完整性
(6)應(yīng)答段:表示正常接收
(7)幀結(jié)束:表示該幀結(jié)束
18.1.3 通信參數(shù)
由發(fā)送單元在非同步的情況下發(fā)送的每秒鐘的位數(shù)稱為位速率。一個位可分為4段。
(1)同步段(SS)
(2)傳播時間段(PTS)
(3)相位緩沖段1(PBS1)
(4)相位緩沖段2(PBS2)
這些段又由可稱為Tq的最小時間單位構(gòu)成。1位分為4個段,每個段又由若干個Tq構(gòu)成,這稱為位時序。1位由多少個Tq構(gòu)成、每個段又由多少個Tq構(gòu)成等,可以任意設(shè)定位時序。通過設(shè)定位時序,多個單元可同時采樣,也可任意設(shè)定采樣點。各段的作用和Tq數(shù)如下表所示。
18.1.4 總線仲裁
在總線空閑態(tài),最先開始發(fā)送消息的單元獲得發(fā)送權(quán)。當(dāng)多個單元同時開始發(fā)送時,各發(fā)送單元從仲裁段的第一位開始進行仲裁。連續(xù)輸出顯性電平最多的單元可繼續(xù)發(fā)送。實現(xiàn)過程如下圖所示。
單元1和單元2同時開始向總線發(fā)送數(shù)據(jù),開始部分他們的數(shù)據(jù)格式是一樣的,故無法區(qū)分優(yōu)先級,直到T時刻,單元1輸出隱性電平,而單元2輸出顯性電平,此時單元1仲裁失利,立刻轉(zhuǎn)入接收狀態(tài)工作,不再與單元2競爭,而單元2則順利獲得總線使用權(quán),繼續(xù)發(fā)送自己的數(shù)據(jù)。這就實現(xiàn)了仲裁,讓連續(xù)發(fā)送顯性電平多的單元獲得總線使用權(quán)
18.1.5 STM32 CAN模組簡介
STM32F1系列自帶的是基本擴展CAN,支持CAN協(xié)議的2.0A和2.0B,支持報文發(fā)送的優(yōu)先級要求可軟件配置,最大通信速率1Mbps,3個發(fā)送郵箱和3級深度的2個接收緩存器FIFO,28個可變的濾波器組,STM32的CAN模組結(jié)構(gòu)如下圖所示。
從上面結(jié)構(gòu)可以看出,兩個CAN都分別具備自己的發(fā)送與接收郵箱,但是28個濾波器卻是公用的,通過FMR寄存器可以設(shè)置濾波器的分配方式,STM32的每個濾波器組的位寬都可以獨立配置,根據(jù)位寬的不同,每個濾波器組可以提供
(1)1個32位過濾器:包含STDID[10:0],EXTID[17:0],18位擴展ID,IDE和RTR位
(2)1個16位過濾器:包含STDID[10:0],IDE,RTR和EXTID[17:15]
此外過濾器可以配置為屏蔽位模式與標(biāo)識符列表模式。
(1)在屏蔽位模式下,標(biāo)識符寄存器和屏蔽寄存器一起,指定報文標(biāo)識符的任何一位,應(yīng)該按照“必須匹配”或“不用關(guān)心”處理
(2)標(biāo)識符列表模式下,屏蔽寄存器也被當(dāng)作標(biāo)識符寄存器用。因此,不是采用一個標(biāo)識符加一個屏蔽位的方式,而是使用2個標(biāo)識符寄存器。接收報文標(biāo)識符的每一位都必須跟過濾器標(biāo)識符相同。
18.1.6 CAN的發(fā)送流程
第1步:程序選擇1個空置的郵箱(TME=1),設(shè)置標(biāo)識符(ID),數(shù)據(jù)長度和發(fā)送數(shù)據(jù)
第2步:設(shè)置CAN_TIxR的TXRQ位為1,請求發(fā)送
第3步:郵箱掛號(等待成為最高優(yōu)先級)?
第4步:預(yù)定發(fā)送(等待總線空閑)
第5步:發(fā)送
第6步:郵箱空置
整個發(fā)送流程如下圖所示。
18.1.7 CAN的接收流程
CAN接收到的有效報文,被存儲在3級郵箱深度的FIFO中。FIFO完全由硬件來管理,從而節(jié)省了CPU的處理負荷,簡化了軟件并保證了數(shù)據(jù)的一致性。應(yīng)用程序只能通過讀取FIFO輸出郵箱,來讀取FIFO中最先收到的報文。這里的有效報文是指那些正確被接收的(直到EOF都沒有錯誤)且通過了標(biāo)識符過濾的報文。前面我們知道CAN的接收有2個FIFO,我們每個濾波器組都可以設(shè)置其關(guān)聯(lián)的FIFO,通過CAN_FFA1R的設(shè)置,可以將濾波器組關(guān)聯(lián)到FIFO0/FIFO1。CAN接收流程為:
FIFO空->收到有效報文->掛號1(存入FIFO的一個郵箱,這個由硬件控制,我們不需要理會)->收到有效報文->掛號2->收到有效報文->掛號3->收到有效報文->溢出
這個流程里面,我們沒有考慮從FIFO讀出報文的情況,實際情況是:我們必須在FIFO溢出之前,讀出至少1個報文,否則下個報文到來,將導(dǎo)致FIFO溢出,從而出現(xiàn)報文丟失。每讀出1個報文,相應(yīng)的掛號就減1,直到FIFO空,完整的接收流程圖如下圖所示。
FIFO接收到的報文數(shù),我們可以通過查詢CAN_RFxR的FMP寄存器來得到,只要FMP不為0,我們就可以從FIFO讀出收到的報文。
18.1.8 通信速率計算
根據(jù)通信參數(shù)小節(jié)我們可以知道1個位是由4個段組成,分別為同步段(SS),傳播時間段(PTS),相位緩沖段1(PBS1),相位緩沖段2(PBS2),STM32內(nèi)部將傳播時間段與相位緩沖段1合并為時間段1,這樣1個位就是有3個段組成,即同步段SS,時間段1和時間段2(即相位緩沖段),由于波特率的定義是1秒內(nèi)發(fā)送二進制位的個數(shù),所以,CAN波特率的計算公式為
18.1.9 STM32F1系列CAN測試模式
(1)靜默模式
通過對CAN_BTR寄存器的SILM位置1,來選擇靜默模式。在靜默模式下,CAN可以正常地接收數(shù)據(jù)幀和遠程幀,但只能發(fā)出隱性位,而不能真正發(fā)送報文。如果bxCAN需要發(fā)出顯性位(確認位、過載標(biāo)志、主動錯誤標(biāo)志),那么這樣的顯性位在內(nèi)部被接回來從而可以被CAN內(nèi)核檢測到,同時CAN總線不會受到影響而仍然維持在隱性位狀態(tài)。因此,靜默模式通常用于分析CAN總線的活動,而不會對總線造成影響-顯性位(確認位、錯誤幀)不會真正發(fā)送到總線上,靜默模式等效圖如下圖所示。
(2)環(huán)回模式
通過對CAN_BTR寄存器的LBKM位置1,來選擇環(huán)回模式。在環(huán)回模式下,CAN把發(fā)送的報文當(dāng)作接收的報文并保存(如果可以通過接收過濾)在接收郵箱里,環(huán)回模式等效圖如下圖所示。
(3)環(huán)回靜默模式
該模式可用于“熱自測試”,即可以像環(huán)回模式那樣測試CAN,但卻不會影響CANTX和CANRX所連接的整個CAN系統(tǒng)。在環(huán)回靜默模式下,CANRX引腳與CAN總線斷開,同時CANTX引腳被驅(qū)動到隱性位狀態(tài),環(huán)回靜默模式等效圖如下圖所示。
18.2 相關(guān)寄存器
18.2.1 CAN主控制器:CAN_MCR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | DBF | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
RESET | - | TTCM | ABOM | AWUM | NART | RFLM | TXFP | SLEEP | INRQ |
Bit 16:DBF:調(diào)試凍結(jié)
0:在調(diào)試時,CAN照常工作
1:在調(diào)試時,凍結(jié)CAN的接收/發(fā)送。仍然可以正常地讀寫和控制接收FIFO
Bit 15:bxCAN軟件復(fù)位
0:本外設(shè)正常工作
1:對bxCAN進行強行復(fù)位,復(fù)位后bxCAN進入睡眠模式。此后硬件自動對該位清0
Bit 7:時間觸發(fā)通信模式
0:禁止時間觸發(fā)通信模式
1:允許時間觸發(fā)通信模式
Bit 6:自動離線管理
0:離線狀態(tài)的退出過程是,軟件對INRQ位進行置1隨后清0后,一旦硬件檢測到128次11位連續(xù)的隱性位,則退出離線狀態(tài)
1:一旦硬件檢測到128次11位連續(xù)的隱性位,則自動退出離線狀態(tài)
Bit 5:自動喚醒模式
0:睡眠模式通過清除CAN_MCR寄存器的SLEEP位,由軟件喚醒
1:睡眠模式通過檢測CAN報文,由硬件自動喚醒。喚醒的同時,硬件自動對SLEEP和SLAK位清0
Bit 4:禁止報文自動重傳
0:按照CAN標(biāo)準(zhǔn),CAN硬件在發(fā)送報文失敗時會一直自動重傳直到發(fā)送成功
1:CAN報文只被發(fā)送1次,不管發(fā)送的結(jié)果如何
Bit 3:接收FIFO鎖定模式
0:在接收溢出時FIFO未被鎖定,當(dāng)接收FIFO的報文未被讀出,下一個收到的報文會覆蓋原有的報文
1:在接收溢出時FIFO被鎖定,當(dāng)接收FIFO的報文未被讀出,下一個收到的報文會被丟棄
Bit 2:發(fā)送FIFO優(yōu)先級
0:優(yōu)先級由報文的標(biāo)識符來決定
1:優(yōu)先級由發(fā)送請求的順序來決定
Bit 1:睡眠模式請求(在復(fù)位后該位被置1)
1:可以請求CAN進入睡眠模式,一旦當(dāng)前的CAN活動結(jié)束,CAN就進入睡眠
0:使CAN退出睡眠模式
Bit 0:初始化請求
0:當(dāng)CAN在接收引腳檢測到連續(xù)的11個隱性位后,CAN就達到同步,并為接收和發(fā)送數(shù)據(jù)作好準(zhǔn)備了。為此,硬件相應(yīng)地對INAK位清0
1:一旦當(dāng)前的CAN活動結(jié)束,CAN就進入初始化模式。相應(yīng)地,硬件對INAK位置1
18.2.2 CAN主狀態(tài)寄存器:CAN_MSR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | RX | SAMP | RXM | TXM | - | SLAKI | WKUI | ERRI | SLAK | INAK |
Bit 11:CAN接收電平,該位反映CAN接收引腳的實際電平
Bit 10:上次采樣值,CAN接收引腳的上次采樣值(對應(yīng)于當(dāng)前接收位的值)
Bit 9:接收模式,該位為1表示CAN當(dāng)前為接收器
Bit 8:發(fā)送模式,該位為1表示CAN當(dāng)前為發(fā)送器
Bit 4:睡眠確認中斷,當(dāng)SLKIE=1,一旦CAN進入睡眠模式硬件就對該位置1,緊接著相應(yīng)的中斷被觸發(fā)軟件可對該位清0,當(dāng)SLAK位被清0時硬件也對該位清0
Bit 3:喚醒中斷掛號,當(dāng)CAN處于睡眠狀態(tài),一旦檢測到幀起始位,硬件就置該位為1
Bit 2:出錯中斷掛號,當(dāng)檢測到錯誤時,CAN_ESR寄存器的某位被置1,如果CAN_IER寄存器的相應(yīng)中斷使能位也被置1時,則硬件對該位置1
Bit 1:睡眠模式確認
0:CAN退出睡眠模式
1:CAN模塊正處于睡眠模式
Bit 0:初始化確認
0:CAN退出初始化模式時
1:CAN模塊正處于初始化模式
18.2.3 CAN位時序寄存器:CAN_BTR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
SILM | LBKM | - | SJW[1:0] | - | TS2[2:0] | TS1[3:0] | |||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | BRP[9:0] |
Bit 31:靜默模式(用于調(diào)試)
0:正常狀態(tài)
1:靜默模式
Bit 30:環(huán)回模式(用于調(diào)試)
0:禁止環(huán)回模式
1:允許環(huán)回模式
Bit 25~Bit 24:重新同步跳躍寬度,該位域定義了CAN硬件在每位中可以延長或縮短多少個時間單元的上限,t RJW =t CAN ×(SJW[1:0]+1)
Bit 22~Bit 20:時間段2,該位域定義了時間段2占用了多少個時間單元,t BS2 =t CAN ×(TS2[2:0]+1)
Bit 19~Bit 16:時間段1,該位域定義了時間段1占用了多少個時間單元,t BS1 =t CAN ×(TS1[3:0]+1)
Bit 9Bit 0:波特率分頻器,該位域定義了時間單元tq的時間長度,t PCLK~q =(BRP[9:0]+1)×t
18.2.4 CAN發(fā)送狀態(tài)寄存器:CAN_TSR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LOW2 | LOW1 | LOW0 | TME2 | TME1 | TME0 | CODE[1:0] | ABRQ2 | - | TERR2 | ALST2 | TXOK2 | RQCP2 | |||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ABRQ1 | - | TERR1 | ALST1 | TXOK1 | RQCP1 | ABRQ0 | - | TERR0 | ALST0 | TXOK0 | RQCP0 |
Bit 31,Bit30,Bit 29:郵箱x最低優(yōu)先級標(biāo)志
當(dāng)多個郵箱在等待發(fā)送報文,且郵箱x的優(yōu)先級最低時,硬件對該位置1
Bit 28,Bit 27,Bit 26:發(fā)送郵箱x空
Bit 25~Bit 24:郵箱號
當(dāng)有至少1個發(fā)送郵箱為空時,表示下一個空的發(fā)送郵箱號。
當(dāng)所有的發(fā)送郵箱都為空時,表示優(yōu)先級最低的那個發(fā)送郵箱號
Bit 23,Bit 15,Bit 7:郵箱x終止發(fā)送
Bit 19,Bit 11,Bit 3:郵箱x發(fā)送失敗
Bit 18,Bit 10,Bit 2:郵箱x仲裁丟失
Bit 17,Bit 9,Bit 1:郵箱x發(fā)送成功
Bit 16,Bit 8,Bit 0:郵箱x請求完成
18.2.5 CAN接收FIFOx寄存器:CAN_RFxR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | ROFM | FOVR | FULL | - | FMP[1:0] |
Bit 5:釋放接收FIFO,輸出郵箱軟件通過對該位置1來釋放接收FIFO的輸出郵箱。如果接收FIFO為空,那么對該位置1沒有任何效果,即只有當(dāng)FIFO中有報文時對該位置1才有意義。如果FIFO中有2個以上的報文,由于FIFO的特點,軟件需要釋放輸出郵箱才能訪問第2個報文,當(dāng)輸出郵箱被釋放時,硬件對該位清0
Bit 4:FIFO溢出,當(dāng)FIFO0已滿,又收到新的報文且報文符合過濾條件,硬件對該位置1,該位由軟件清0
Bit 3:FIFO滿,當(dāng)FIFO0中有3個報文時,硬件對該位置1,該位由軟件清0
Bit 1~Bit 0:FIFO報文數(shù)目,表示當(dāng)前接收FIFO0中存放的報文數(shù)目
每當(dāng)1個新的報文被存入接收FIFO0,硬件就對FMP0加1
每當(dāng)軟件對RFOM位寫1來釋放輸出郵箱,F(xiàn)MP就被減1,直到其為0
18.2.6 CAN過濾器主控寄存器:CAN_FMR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | FINIT |
Bit 0:過濾器初始化模式
0:過濾器組工作在正常模式
1:過濾器組工作在初始化模式
18.2.7 CAN過濾器模式寄存器:CAN_FM1R
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | FBM[27:16] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
FBM[15:0] |
Bit 29~Bit 0:過濾器模式
0:過濾器組x的2個32位寄存器工作在標(biāo)識符屏蔽位模式
1:過濾器組x的2個32位寄存器工作在標(biāo)識符列表模式
18.2.8 CAN過濾器位寬寄存器:CAN_FS1R
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | FSC[27:16] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
FSC[15:0] |
Bit 29~Bit 0:過濾器位寬設(shè)置
0:過濾器位寬為2個16位
1:過濾器位寬為單個32位
18.2.9 CAN過濾器FIFO關(guān)聯(lián)寄存器:CAN_FFA1R
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
FFA[27:16] | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
FFA[15:0] |
Bit 29~Bit 0:過濾器關(guān)聯(lián)設(shè)置
0:過濾器被關(guān)聯(lián)到FIFO0
1:過濾器被關(guān)聯(lián)到FIFO1
18.2.10 CAN過濾器激活寄存器:CAN_FA1R
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
FACT[27:16] | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
FACT[15:0] |
Bit 29~Bit 0:過濾器激活
0:過濾器被禁用
1:過濾器被激活
18.2.11 發(fā)送郵箱標(biāo)識符寄存器:CAN_TIxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
STID[10:0]/EXID[28:18] | EXID[17:13] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
EXID[12:0] | IDE | RTR | TXRQ |
Bit 31~Bit 21:標(biāo)準(zhǔn)標(biāo)識符或擴展標(biāo)識符,依據(jù)IDE位的內(nèi)容,這些位或是標(biāo)準(zhǔn)標(biāo)識符,或是擴展身份標(biāo)識的高字節(jié)
Bit 20~Bit 3:擴展標(biāo)識符,擴展身份標(biāo)識的低字節(jié)
Bit 2:標(biāo)識符選擇
0:使用標(biāo)準(zhǔn)標(biāo)識符
1:使用擴展標(biāo)識符
Bit 1:遠程發(fā)送請求
0:數(shù)據(jù)幀
1:遠程幀
Bit 0:發(fā)送數(shù)據(jù)請求,由軟件對其置1,來請求發(fā)送郵箱的數(shù)據(jù)。當(dāng)數(shù)據(jù)發(fā)送完成,郵箱為空時,硬件對其清0
18.2.12 發(fā)送郵箱數(shù)據(jù)長度和時間戳寄存器:CAN_TDTxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
TIME[15:0] | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | TGT | - | DLC[3:0] |
Bit 31~Bit 16:報文時間戳,該域包含了,在發(fā)送該報文SOF的時刻,16位定時器的值
Bit 8:發(fā)送時間戳(只有在CAN處于時間觸發(fā)通信模式才有效)
0:不發(fā)送時間戳TIME[15:0]
1:發(fā)送時間戳TIME[15:0]
注:在長度為8的報文中,時間戳TIME[15:0]是最后2個發(fā)送的字節(jié):TIME[7:0]作為第7個字節(jié),TIME[15:8]為第8個字節(jié),替換了寫入CAN_TDHxR[31:16]的數(shù)據(jù)。為了把時間戳的2個字節(jié)發(fā)送出去,DLC必須編程為8。
Bit 3~Bit 0:發(fā)送數(shù)據(jù)長度,指定數(shù)據(jù)報文的數(shù)據(jù)長度或者遠程幀請求的數(shù)據(jù)長度
18.2.13 發(fā)送郵箱低字節(jié)數(shù)據(jù)寄存器:CAN_TDLxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DATA3[7:0] | DATA2[7:0] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
DATA1[7:0] | DATA0[7:0] |
Bit 31~Bit 24:數(shù)據(jù)字節(jié)3
Bit 23~Bit 16:數(shù)據(jù)字節(jié)2
Bit 15~Bit 8:數(shù)據(jù)字節(jié)1
Bit 7~Bit 0:數(shù)據(jù)字節(jié)0
18.2.14 發(fā)送郵箱高字節(jié)數(shù)據(jù)寄存器:CAN_TDHxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DATA7[7:0] | DATA6[7:0] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
DATA5[7:0] | DATA4[7:0] |
Bit 31~Bit 24:數(shù)據(jù)字節(jié)7
Bit 23~Bit 16:數(shù)據(jù)字節(jié)6
Bit 15~Bit 8:數(shù)據(jù)字節(jié)5
Bit 7~Bit 0:數(shù)據(jù)字節(jié)4
18.2.15 接收郵箱標(biāo)識符寄存器:CAN_RIxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
STID[10:0]/EXID[28:18] | EXID[17:13] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
EXID[12:0] | IDE | RTR | - |
Bit 31~Bit 21:標(biāo)準(zhǔn)標(biāo)識符或擴展標(biāo)識符,依據(jù)IDE位的內(nèi)容,這些位或是標(biāo)準(zhǔn)標(biāo)識符,或是擴展身份標(biāo)識的高字節(jié)
Bit 20~Bit 3:擴展標(biāo)識符,擴展身份標(biāo)識的低字節(jié)
Bit 2:標(biāo)識符選擇
0:使用標(biāo)準(zhǔn)標(biāo)識符
1:使用擴展標(biāo)識符
Bit 1:遠程發(fā)送請求
0:數(shù)據(jù)幀
1:遠程幀
18.2.16 接收郵箱數(shù)據(jù)長度和時間戳寄存器:CAN_RDTxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
TIME[15:0] | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
FMI[7:0] | - | DLC[3:0] |
Bit 31~Bit 16:報文時間戳,該域包含了,在接收該報文SOF的時刻,16位定時器的值
Bit 15~Bit 8:過濾器匹配序號
Bit 3~Bit 0:接收數(shù)據(jù)長度
18.2.17 接收郵箱低字節(jié)數(shù)據(jù)寄存器:CAN_RDLxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DATA3[7:0] | DATA2[7:0] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
DATA1[7:0] | DATA0[7:0] |
Bit 31~Bit 24:數(shù)據(jù)字節(jié)3
Bit 23~Bit 16:數(shù)據(jù)字節(jié)2
Bit 15~Bit 8:數(shù)據(jù)字節(jié)1
Bit 7~Bit 0:數(shù)據(jù)字節(jié)0
18.2.18 接收郵箱高字節(jié)數(shù)據(jù)寄存器:CAN_RDHxR
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DATA7[7:0] | DATA6[7:0] | ||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
DATA5[7:0] | DATA4[7:0] |
Bit 31~Bit 24:數(shù)據(jù)字節(jié)7
Bit 23~Bit 16:數(shù)據(jù)字節(jié)6
Bit 15~Bit 8:數(shù)據(jù)字節(jié)5
Bit 7~Bit 0:數(shù)據(jù)字節(jié)4
18.3 實驗例程
實驗內(nèi)容:利用CAN的回環(huán)模式進行數(shù)據(jù)收發(fā)測試,通信速率500Kbps。
(1)創(chuàng)建can.h文件,并輸入以下代碼。
/*********************************************************************************************************
CAN 通 信 驅(qū) 動 文 件
*********************************************************************************************************/
#ifndef _CAN_H_
#define _CAN_H_
#include "sys.h"
/*********************************************************************************************************
函 數(shù) 列 表
*********************************************************************************************************/
u8 CAN_Init( u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode ) ; //CAN初始化
u8 CAN_Tx_Msg( u32 id, u8 ide, u8 rtr, u8 len, u8 *dat ) ; //CAN發(fā)送數(shù)據(jù)
void CAN_Rx_Msg( u8 fifox, u32 *id, u8 *ide, u8 *rtr, u8 *len, u8 *dat ) ; //CAN接收數(shù)據(jù)
#endif
(2)創(chuàng)建can.c文件,并輸入以下代碼。
/*********************************************************************************************************
CAN 通 信 驅(qū) 動 程 序
*********************************************************************************************************/
#include "can.h"
/*******************************************************
Name :CAN_Mode_Init
Function :CAN初始化
Paramater :
tsjw:重新同步跳躍時間單元.范圍:1~3
tbs2:時間段2的時間單元.范圍:1~8
tbs1:時間段1的時間單元.范圍:1~16
brp:波特率分頻器.范圍:1~1024
mode:工作模式
0:普通模式
1:回環(huán)模式
Return :
0:成功
其他:失敗
*******************************************************/
u8 CAN_Init( u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode )
{
u16 i=0;
if( ( tsjw==0 )||( tbs2==0 )||( tbs1==0 )||( brp==0 ) )
return 1 ;
//先減去1.再用于設(shè)置
tsjw -= 1 ;
tbs2 -= 1 ;
tbs1 -= 1 ;
brp -= 1 ;
RCC->APB2ENR |= 1<<2 ; //使能PA時鐘
GPIOA->CRH &= 0xFFF00FFF ;
GPIOA->CRH |= 0x000B8000 ;
GPIOA->ODR |= 3<<11 ;
RCC->APB1ENR |= 1<<25 ; //使能CAN時鐘
CAN1->MCR = 0x0000 ; //退出睡眠模式
CAN1->MCR |= 1<<0 ; //請求CAN進入初始化模式
while( ( CAN1->MSR&0x01 )==0 )
{
i ++ ;
if( i>100 )
return 2 ; //進入初始化模式失敗
}
CAN1->MCR |= 0<<7 ; //非時間觸發(fā)通信模式
CAN1->MCR |= 0<<6 ; //軟件自動離線管理
CAN1->MCR |= 0<<5 ; //睡眠模式通過軟件喚醒
CAN1->MCR |= 1<<4 ; //禁止報文自動傳送
CAN1->MCR |= 0<<3 ; //報文不鎖定,新的覆蓋舊的
CAN1->MCR |= 0<<2 ; //優(yōu)先級由報文標(biāo)識符決定
CAN1->BTR = 0x00000000 ; //清除原來的設(shè)置
CAN1->BTR |= mode<<30 ; //模式設(shè)置
CAN1->BTR |= tsjw<<24 ; //重新同步跳躍寬度(Tsjw)為tsjw+1個時間單位
CAN1->BTR |= tbs2<<20 ; //Tbs2=tbs2+1個時間單位
CAN1->BTR |= tbs1<<16 ; //Tbs1=tbs1+1個時間單位
CAN1->BTR |= brp<<0 ; //分頻系數(shù)(Fdiv)為brp+1
CAN1->MCR &= ~( 1<<0 ) ; //請求CAN退出初始化模式
while( ( CAN1->MSR&0x01 )!=0 )
{
i ++ ;
if( i>0xFFF0 )
return 3 ; //退出初始化模式失敗
}
//過濾器初始化
CAN1->FMR |= 1<<0 ; //過濾器組工作在初始化模式
CAN1->FA1R &= ~( 1<<0 ) ; //過濾器0不激活
CAN1->FS1R |= 1<<0 ; //過濾器位寬為32位
CAN1->FM1R |= 0<<0 ; //過濾器0工作在標(biāo)識符屏蔽位模式
CAN1->FFA1R |= 0<<0 ; //過濾器0關(guān)聯(lián)到FIFO0
CAN1->sFilterRegister[ 0 ].FR1 = 0x00000000 ; //32位ID
CAN1->sFilterRegister[ 0 ].FR2 = 0x00000000 ; //32位MASK
CAN1->FA1R |= 1<<0 ; //激活過濾器0
CAN1->FMR &= 0<<0 ; //過濾器組進入正常模式
return 0 ;
}
/*******************************************************
Name :CAN_Tx_Msg
Function :CAN發(fā)送數(shù)據(jù)
Paramater :
id:標(biāo)準(zhǔn)ID(11位)/擴展ID(11位+18位)
ide:ID類型
0:標(biāo)準(zhǔn)幀
1:擴展幀
rtr:數(shù)據(jù)類型
0:數(shù)據(jù)幀
1:遠程幀
len:要發(fā)送的數(shù)據(jù)長度
*dat:數(shù)據(jù)指針
Return :
0~3:郵箱編號
0xFF:無有效郵箱
*******************************************************/
u8 CAN_Tx_Msg( u32 id, u8 ide, u8 rtr, u8 len, u8 *dat )
{
u16 i;
u8 mbox, sta=0 ;
//郵箱0為空
if( CAN1->TSR&( 1<<26 ) )
mbox = 0 ;
//郵箱1為空
else if( CAN1->TSR&( 1<<27 ) )
mbox = 1 ;
//郵箱2為空
else if( CAN1->TSR&( 1<<28 ) )
mbox = 2 ;
//無空郵箱,無法發(fā)送
else
return 0xFF ;
CAN1->sTxMailBox[ mbox ].TIR = 0 ; //清除之前的設(shè)置
//標(biāo)準(zhǔn)幀
if( ide==0 )
{
id &= 0x7FF ; //取低11位stdid
id <<= 21 ;
}
//擴展幀
else
{
id &= 0x1FFFFFFF ; //取低32位extid
id <<= 3 ;
}
CAN1->sTxMailBox[ mbox ].TIR |= id ;
CAN1->sTxMailBox[ mbox ].TIR |= ide<<2 ;
CAN1->sTxMailBox[ mbox ].TIR |= rtr<<1 ;
len &= 0x0F ; //得到低四位
CAN1->sTxMailBox[ mbox ].TDTR &= 0xFFFFFFF0 ;
CAN1->sTxMailBox[ mbox ].TDTR |= len ; //設(shè)置DLC
//待發(fā)送數(shù)據(jù)存入郵箱
CAN1->sTxMailBox[ mbox ].TDHR = ( ( (u32)dat[7]<<24 )|( (u32)dat[6]<<16 )|( (u32)dat[5]<<8 )|( (u32)dat[4] ) ) ;
CAN1->sTxMailBox[ mbox ].TDLR = ( ( (u32)dat[3]<<24 )|( (u32)dat[2]<<16 )|( (u32)dat[1]<<8 )|( (u32)dat[0] ) ) ;
CAN1->sTxMailBox[ mbox ].TIR |= 1<<0 ; //請求發(fā)送郵箱數(shù)據(jù)
//獲取發(fā)送狀態(tài)
while( ( sta!=0x07 )&&( i<0xFFF ) )
{
i ++ ;
switch( mbox )
{
//郵箱0
case 0:
sta |= CAN1->TSR&( 1<<0 ) ; //RQCP0
sta |= CAN1->TSR&( 1<<1 ) ; //TXOK0
sta |= CAN1->TSR&( 1<<26 )>>24 ; //TME0
break;
//郵箱1
case 1:
sta |= CAN1->TSR&( 1<<8 )>>8 ; //RQCP1
sta |= CAN1->TSR&( 1<<9 )>>8 ; //TXOK1
sta |= CAN1->TSR&( 1<<27 )>>25 ; //TME1
break;
//郵箱2
case 2:
sta |= CAN1->TSR&( 1<<16 )>>16 ; //RQCP2
sta |= CAN1->TSR&( 1<<17 )>>16 ; //TXOK2
sta |= CAN1->TSR&( 1<<28 )>>26 ; //TME2
break;
//郵箱號不對
default:
sta = 0x05 ;
break ;
}
}
if( i==0xFFF )
mbox = 0xFF ;
return mbox ;
}
/*******************************************************
Name :CAN_Rx_Msg
Function :CAN接收數(shù)據(jù)
Paramater :
fifox:郵箱號
id:標(biāo)準(zhǔn)ID(11位)/擴展ID(11位+18位)
ide:ID類型
0:標(biāo)準(zhǔn)幀
1:擴展幀
rtr:數(shù)據(jù)類型
0:數(shù)據(jù)幀
1:遠程幀
len:要發(fā)送的數(shù)據(jù)長度
*dat:數(shù)據(jù)指針
Return :None
*******************************************************/
void CAN_Rx_Msg( u8 fifox, u32 *id, u8 *ide, u8 *rtr, u8 *len, u8 *dat )
{
if( ( fifox==0 )&&( ( CAN1->RF0R&0x03 )==0 ) )
len = 0 ;
else if( ( fifox==1 )&&( ( CAN1->RF1R&0x03 )==0 ) )
len = 0 ;
else
{
//接收數(shù)據(jù)
*ide = CAN1->sFIFOMailBox[ fifox ].RIR&0x04 ; //得到標(biāo)識符選擇位的值
if( *ide==0 )
*id = CAN1->sFIFOMailBox[ fifox ].RIR>>21 ; //標(biāo)準(zhǔn)標(biāo)識符
else
*id = CAN1->sFIFOMailBox[ fifox ].RIR>>3 ; //擴展標(biāo)識符
*rtr = CAN1->sFIFOMailBox[ fifox ].RIR&0x02 ; //得到遠程發(fā)送請求值
*len = CAN1->sFIFOMailBox[ fifox ].RDTR&0x0F ; //得到DLC
dat[ 0 ] = CAN1->sFIFOMailBox[ fifox ].RDLR&0xFF ;
dat[ 1 ] = ( CAN1->sFIFOMailBox[ fifox ].RDLR>>8 )&0xFF ;
dat[ 2 ] = ( CAN1->sFIFOMailBox[ fifox ].RDLR>>16 )&0xFF ;
dat[ 3 ] = ( CAN1->sFIFOMailBox[ fifox ].RDLR>>24 )&0xFF ;
dat[ 4 ] = CAN1->sFIFOMailBox[ fifox ].RDHR&0xFF ;
dat[ 5 ] = ( CAN1->sFIFOMailBox[ fifox ].RDHR>>8 )&0xFF ;
dat[ 6 ] = ( CAN1->sFIFOMailBox[ fifox ].RDHR>>16 )&0xFF ;
dat[ 7 ] = ( CAN1->sFIFOMailBox[ fifox ].RDHR>>24 )&0xFF ;
if( fifox==0 )
CAN1->RF0R |= 0x20 ; //釋放FIFO0郵箱
else if( fifox==1 )
CAN1->RF1R |= 0x20 ; //釋放FIFO1郵箱
}
}
(3)創(chuàng)建1.c文件,并輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "can.h"
int main()
{
u32 id;
u8 ide, rtr, len, canbuf[ 8 ] ;
STM32_Clock_Init( 9 ) ; //STM32時鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
CAN_Init( 1, 8, 9, 4, 1 ) ; //CAN初始化
CAN_Tx_Msg( 0x12, 0, 0, 8, "CAN Test" ) ; //發(fā)送8個字節(jié)
while( 1 )
{
CAN_Rx_Msg( 0, &id, &ide, &rtr, &len, canbuf ) ; //讀取數(shù)據(jù)
}
}
-
通信協(xié)議
+關(guān)注
關(guān)注
28文章
883瀏覽量
40308 -
CAN
+關(guān)注
關(guān)注
57文章
2754瀏覽量
463702 -
工業(yè)自動化
+關(guān)注
關(guān)注
17文章
2387瀏覽量
67240
發(fā)布評論請先 登錄
相關(guān)推薦
評論