目錄
1:CAN簡介
CAN是Controller Area Network,是一種串行的通信協議,有兩標準:ISO11898、ISO11519-2,其中ISO11898是針對通信速率爲125Kbps~1Mbps的高速通信標準,而ISO11519-2是針對通信速率爲123Kbps以下的低速通信標準
CAN有很多優點,比如多主控制,速度快,距離遠,具有錯誤檢測,恢復,連接節點多等功能。所以CAN協議特別適合工業過程監控設備的互聯
講下ISO11898標準,物理層特徵如下
CAN控制器根據CAN_L和CAN_H上的點位差來判斷總線電平,總線電平分爲顯性電平和隱形電平,二者必居其一,發送方通過使總線電平發生變化,將消息發送給接收方。
- 顯性電平對應邏輯:0 CAN_H和CAN_L之差爲2V左右
- 隱形電平對應邏輯:1 CAN_H和CAN_L之差爲0V
要注意的是,顯性電平比隱形電平強,顯性電平具有優先權,只要有一個單元輸出顯性電平,總線上即爲顯性電平,而隱形電平則具有包容的意味,只要所有單元都輸出隱形電平,總線上才爲隱形電平,
另外,在CAN總線的起止端都有一個120Ω的終端電阻,來做阻抗匹配,以減少回波反射
2:CAN通信幀種類介紹
CAN通信是以以下5鍾類型的幀進行的
數據幀、遙控幀、錯誤幀、過載幀、間隔幀
其中數據幀和遙控幀有標準格式和擴張格式兩種,標準格式有11個位標識符(ID),擴展格式有29個位ID
介紹哈數據幀
- 幀起始:表示數據幀開始的段
- 仲裁段:表示該幀優先級的段
- 控制端:表示數據的字節數及保留位的段
- 數據段:數據的內容,一幀可發送0~8·個字節的數據
- CRC段:檢查幀的傳輸錯誤的段
- ACK段:表示確認正常接受的段
- 幀結束:表示數據幀結束的段
3:CAN位時序
位時序:在CAN 通信中,一個位分爲4段,這每個段又由Time Quantum(簡稱Tq)的最小時間單位構成,這個就是位時序
有如下四個段:
- 同步段(SS)
- 傳播時間段(PTS)
- 相位緩衝段1(PBS1)
- 相位緩衝段2(PBS2)
位時間=1/波特率,因此,知道位時間,我們就可以知道波特率
1 位由多少個Tq 構成、每個段又由多少個Tq 構成等,可以任意設定位時序。通過設定位時序,多個單元可同時採樣,也可任意設定採樣點。
位時序各段的作用和Tq數如下
一個位的構成:
4:STM32_CAN
eg:STM32F407ZGT6
前面只是對CAN通信做一個基本的描述,在STM32上,自帶了基本擴展CAN外設,稱bxCAN,
- CAN1:主bxCAN,用於管理bxCAN與512字節SRAM存儲器之間的通信。
- CAN2:從bxCAN,無法直接訪問SRAM存儲器,但兩個bxCAN單元共享512字節SRAM存儲器
- 波特率最高達1Mbps
- 支持時間觸發通信
- 具有3個發送郵箱
- 具有3級深度的2個接受FIFO
- 可變的篩選器組(也稱過濾器組,最多28個)
bxCAN有三種主要的工作模式:初始化、正常、睡眠,還有測試模式和調試模式,具體看數據手冊
5:bx_CAN控制器框圖
篩選器組,可以設置你需要的數據,不需要的就不接受,就是爲降低CPU處理CAN通信的開銷
STM32 CAN控制器每個篩選器組由2個32位寄存器組成,根據位寬不同,每個篩選器組可提供1個32位的篩選器或2個16位的篩選器
篩選器可配置爲:屏蔽位模式、標識符列表模式
通過CAN_FM1R(篩選器模式寄存器)和CAN_FS1R(篩選器尺度寄存器)可配置篩選器的位寬和模式
- 爲了過濾出一組標識符,應該設置篩選器組工作在屏蔽位模式
- 爲了過濾出一個標識符,應該設置過濾器工作在標識符列表模式
- 應用程序不用的篩選器組,應該保持在禁用狀態(通過CAN_FA1R設置)。
- 通過CAN_FFA1R的設置,可以將篩選器組關聯到FIFO0/FIFO1
- 篩選器組中的每個篩選器,都被編號爲(即:篩選器編號)從0開始,到某個最大數值-取決於篩選器組的模式和位寬的設置。
6:STM32_CAN發送,接受流程
報文FIFO具有鎖定功能(由CAN_MCR,RFLM位控制),鎖定後,新數據將丟失,不鎖定則新數據將替代老數據
7:STM32CAN通信位時序
8:STM32CAN代碼實現
1:初始化
//CAN單元設置 CAN_InitStructure.CAN_TTCM=DISABLE; //非時間觸發通信模式 CAN_InitStructure.CAN_ABOM=DISABLE; //軟件自動離線管理 CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通過軟件喚醒(清除CAN->MCR的SLEEP位) CAN_InitStructure.CAN_NART=ENABLE; //禁止報文自動傳送 CAN_InitStructure.CAN_RFLM=DISABLE; //報文不鎖定,新的覆蓋舊的 CAN_InitStructure.CAN_TXFP=DISABLE; //優先級由報文標識符決定 CAN_InitStructure.CAN_Mode= mode; //模式設置 CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳躍寬度(Tsjw)爲tsjw+1個時間單位 CAN_SJW_1tq~CAN_SJW_4tq CAN_InitStructure.CAN_BS1=tbs1; //Tbs1範圍CAN_BS1_1tq ~CAN_BS1_16tq CAN_InitStructure.CAN_BS2=tbs2; //Tbs2範圍CAN_BS2_1tq ~ CAN_BS2_8tq CAN_InitStructure.CAN_Prescaler=brp; //分頻係數(Fdiv)爲brp+1 CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1 //配置過濾器 CAN_FilterInitStructure.CAN_FilterNumber=0; //過濾器0 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32位ID CAN_FilterInitStructure.CAN_FilterIdLow=0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000; //32位MASK CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//過濾器0關聯到FIFO0 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活過濾器0 CAN_FilterInit(&CAN_FilterInitStructure); //濾波器初始化
相應引腳配置位複用推輓輸出加上拉模式
- CAN_TTCM:操作CAN_MCR主控制寄存器的位7
- CAN_ABOM:操作CAN_MCR主控制寄存器的位6
- CAN_AWU:M操作CAN_MCR主控制寄存器的位5
- CAN_NART:操作CAN_MCR主控制寄存器的位4
- CAN_RFLM:操作CAN_MCR主控制寄存器的位3
- CAN_TXFP:操作CAN_MCR主控制寄存器的位2
- CAN_Mode:操作CAN_BTR位時序寄存器的位31,30
- CAN_SJW:操作CAN_BTR位時序寄存器的位25,24
- CAN_BS1:操作CAN_BTR位時序寄存器的位19~16
- CAN_BS2:操作CAN_BTR位時序寄存器的位22~20
- CAN_Prescaler:操作CAN_BTR位時序寄存器的位9~0
配置過濾器
- CAN_FilterNumber:操作CAN_FA1R篩選器激活寄存器的位27:0
- CAN_FilterMode:操作CAN_FM1R篩選器模式寄存器的位27:0
- CAN_FilterScale:操作CAN_FS1R篩選器尺度寄存器的位27:0和CAN_FiRx篩選器組i寄存器
- CAN_FilterIdHigh、CAN_FilterIdLow、CAN_FilterMaskIdHigh、CAN_FilterMaskIdLow都是配合操作CAN_FiRx篩選器組i寄存器
- CAN_FilterFIFOAssignment:操作CAN_FFA1R篩選器FIFO分配寄存器的位27:0
- CAN_FilterActivation:操作CAN_FA1R篩選器激活寄存器的位27:0
2:發送數據
u8 CAN1_Send_Msg(u8* msg,u8 len) { u8 mbox; u16 i=0; CanTxMsg TxMessage; TxMessage.StdId=0x12; // 標準標識符爲0 TxMessage.ExtId=0x12; // 設置擴展標示符(29位) TxMessage.IDE=0; // 使用擴展標識符 TxMessage.RTR=0; // 消息類型爲數據幀,一幀8位 TxMessage.DLC=len; // 發送兩幀信息 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++; //等待發送結束 if(i>=0XFFF)return 1; return 0; }
- StdId、IDE、RTR :在IDE的基礎上,決定在CAN_TIxR發送郵箱標識符寄存器上標識符類型和幀類型
- ExtId、IDE、RTR:在IDE的基礎上,決定在CAN_TIxR發送郵箱標識符寄存器上標識符類型和幀類型
- len:操作CAN_TDTxR郵箱數據長度控制和時間戳寄存器的位3:0
- Data:操作CAN_TDL\HxR郵箱數據低\高寄存器
- 最後查詢CAN_TSR發送狀態寄存器,等待發送結束
3:接受數據
u8 CAN1_Receive_Msg(u8 *buf) { u32 i; CanRxMsg RxMessage; if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0; //沒有接收到數據,直接退出 CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//讀取數據 for(i=0;i<RxMessage.DLC;i++) buf[i]=RxMessage.Data[i]; return RxMessage.DLC; }
- 先查詢CAN_RF0R接受FIFI 0寄存器的位1:0
- 然後去讀取CAN_RDL\HxR接受FIFO郵箱數據低\高位寄存器的數據存放在RxMessage.Data中