(轉)stm32的can匯流排理解及應用——程式對應stm32f103系列
CAN 是Controller Area Network 的縮寫(以下稱為CAN),是ISO國際標準化的序列通訊協議。
它的通訊速度較快,通訊距離遠,最高1Mbps(距離小於40米),最遠可達10千里(速率低於5Kbps)。在匯流排空閒時,所有單元都可以傳送訊息(多主控制),而兩個以上的單元同時開始傳送訊息時,根據識別符號(Identifier 以下稱為 ID)決定優先順序。ID 並不是表示傳送的目的地址,而是表示訪問匯流排的訊息的優先順序。兩個以上的單元同時開始傳送訊息時,對各訊息ID 的每個位進行逐個仲裁比較。仲裁獲勝(被判定為優先順序最高)的單元可繼續傳送訊息,仲裁失利的單元則立刻停止傳送而進行接收工作。
CAN協議經過ISO標準化後有兩個標準:ISO11898標準和ISO11519-2標準。其中ISO11898是針對通訊速率為125Kbps~1Mbps的高速通訊標準,而ISO11519-2是針對通訊速率為125Kbps以下的低速通訊標準。
本章,我們使用的是450Kbps的通訊速率,使用的是ISO11898標準,該標準的物理層特徵如圖1所示:
從該特性可以看出,顯性電平對應邏輯0,CAN_H和CAN_L之差為2.5V左右。而隱性電平對應邏輯1,CAN_H和CAN_L之差為0V。在匯流排上顯性電平具有優先權,只要有一個單元輸出顯性電平,匯流排上即為顯性電平。而隱形電平則具有包容的意味,只有所有的單元都輸出隱性電平,匯流排上才為隱性電平(顯性電平比隱性電平更強)。另外,在CAN匯流排的起止端都有一個120Ω的終端電阻,來做阻抗匹配,以減少回波反射。
CAN協議是通過以下5種型別的幀進行的:
l 資料幀
l 搖控幀
l 錯誤幀
l 過載幀
l 幀間隔
另外,資料幀和遙控幀有標準格式和擴充套件格式兩種格式。標準格式有11 個位的識別符號(ID),擴充套件格式有29 個位的ID。
1.資料幀
資料幀一般由7個段構成,即:
(1) 幀起始。表示資料幀開始的段。
(2) 仲裁段。表示該幀優先順序的段。
(3) 控制段。表示資料的位元組數及保留位的段。
(4) 資料段。資料的內容,一幀可傳送0~8個位元組的資料。
(5) CRC段。檢查幀的傳輸錯誤的段。
(6) ACK段。表示確認正常接收的段。
(7) 幀結束。表示資料幀結束的段。
如圖2為資料幀的構成:
圖中D表示顯性電平,R表示隱形電平(下同)。
幀起始,標準幀和擴充套件幀都是由1個位的顯性電平表示幀起始。
仲裁段,表示資料優先順序的段,標準幀和擴充套件幀格式在本段有所區別,標準格式的ID 有11 個位。從ID28 到ID18 被依次傳送。禁止高7 位都為隱性(禁止設定:ID=1111111XXXX,原因:can通訊採用的是NZR編碼,而can的仲裁是靠資料幀中的ID部分來實現的,全為隱性狀態,可能導致仲裁失敗!)。擴充套件格式的 ID 有29 個位。基本ID 從ID28 到ID18,擴充套件ID 由ID17 到ID0 表示。基本ID 和標準格式的ID 相同。禁止高7 位都為隱性(禁止設定:基本ID=1111111XXXX)。
其中RTR位用於標識是否是遠端幀(0,資料幀;1,遠端幀),IDE位為識別符號選擇位(0,使用標準識別符號;1,使用擴充套件識別符號),SRR位為代替遠端請求位,為隱性位,它代替了標準幀中的RTR位。
控制段,由6個位構成,表示資料段的位元組數。
資料段,該段可包含0~8個位元組的資料。從最高位(MSB)開始輸出,標準幀和擴充套件幀在這個段的定義都是一樣的。
CRC段,該段用於檢查幀傳輸錯誤。由15個位的CRC順序和1個位的CRC界定符(用於分隔的位)組成,標準幀和擴充套件幀在這個段的格式也是相同的。
ACK段,此段用來確認是否正常接收。由ACK槽(ACK Slot)和ACK界定符2個位組成。標準幀和擴充套件幀在這個段的格式也是相同的。
2.遠端幀(遙控幀)
遠端幀作用:只傳送ID號,不傳送資料,它將ID發給另一臺裝置,請求另一臺裝置返回資料。
3.CAN匯流排波特率設定
位速率:由傳送單元在非同步的情況下傳送的每秒鐘的位數稱為位速率。一個位可分為 4 段。
l 同步段(SS)
l 傳播時間段(PTS)
l 相位緩衝段1(PBS1)
l 相位緩衝段2(PBS2)
這些段又由可稱為 Time Quantum(以下稱為Tq)的最小時間單位構成。
1 位分為4 個段,每個段又由若干個Tq 構成,這稱為位時序。
1 位由多少個Tq 構成、每個段又由多少個Tq 構成等,可以任意設定位時序。通過設定位時序,多個單元可同時取樣,也可任意設定取樣點。STM32把傳播時間段和相位緩衝段1(STM32稱之為時間段1)合併了,所以STM32的CAN一個位只有3段:同步段(SYNC_SEG)、時間段1(BS1)和時間段2(BS2)。STM32的BS1段可以設定為1~16個時間單元,剛好等於我們上面介紹的傳播時間段和相位緩衝段1之和。STM32的CAN位時序如圖3所示:
圖中還給出了CAN波特率的計算公式,我們只需要知道BS1和BS2的設定,以及APB1的時脈頻率(一般為36Mhz),就可以方便的計算出波特率。比如設定TS1=6、TS2=7和BRP=4,在APB1頻率為36Mhz的條件下,即可得到CAN通訊的波特率=36000/[(7+8+1)*5]=450Kbps。圖4是常見CAN匯流排的波特率設定:
4.CAN匯流排遮蔽濾波
STM32的識別符號遮蔽濾波目的是減少了CPU處理CAN通訊的開銷。STM32的過濾器組最多有28個(互聯型),但是STM32F103ZET6只有14個(增強型),每個濾波器組x由2個32為暫存器,CAN_FxR1和CAN_FxR2組成。
STM32每個過濾器組的位寬都可以獨立配置,以滿足應用程式的不同需求。根據位寬的不同,每個過濾器組可提供:
● 1個32位過濾器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
● 2個16位過濾器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
此外過濾器可配置為,遮蔽位模式和識別符號列表模式。
在遮蔽位模式下,識別符號暫存器和遮蔽暫存器一起,指定報文識別符號的任何一位,應該按照“必須匹配”或“不用關心”處理。
而在識別符號列表模式下,遮蔽暫存器也被當作識別符號暫存器用。因此,不是採用一個識別符號加一個遮蔽位的方式,而是使用2個識別符號暫存器。接收報文識別符號的每一位都必須跟過濾器識別符號相同。
濾波過程舉例:
現有ID號為001,002,003,004的4個CAN,他們都能傳送、接收廣播報文。站在CAN002號角度看,它所能接受到報文的ID是通過濾波器濾波後的ID號,即這裡將過濾方式分兩種,一是002號能接收多個ID報文(遮蔽濾波模式),二是002號只能接收一個ID報文(識別符號列表模式)。
遮蔽濾波模式:
識別符號暫存器:0 0 1
遮蔽暫存器: 1 0 1
報文ID號: 0 0/1 1
如果設定識別符號暫存器和遮蔽暫存器為001和101;遮蔽濾波模式的作用是如果遮蔽暫存器某位上出現了1,則報文ID號對應的那位要與識別符號暫存器那位一致,即“必須匹配”原則,所以識別符號暫存器第一位0,報文ID號第一位也必須為0,因為遮蔽暫存器第一位為1,類似的第三位也是這樣。如果遮蔽暫存器某位上出現了0,則報文ID號對應的那位可與識別符號暫存器那位不一致也可以一致,即“不用關心”原則,第二位由於遮蔽暫存器上為0,所以報文ID號可以與識別符號暫存器上的0一致也可以不一致,故報文ID號第二位為0/1。所以002號(010)可以接受來自001號(001)和003號(011)的報文。
識別符號列表模式:將設定的遮蔽暫存器改為識別符號暫存器
識別符號暫存器:0 0 1
識別符號暫存器: 0 0 1
報文ID號: 0 0 1
如果設定2個識別符號暫存器為001和001;報文ID號必須與這兩個識別符號暫存器所對應的位相等。所以002號CAN只能接受001號的報文。
下圖5是CAN_FMR暫存器,可以配置過濾器組的暫存器位數16還是32位,工作模式以及它和標準幀、擴充套件幀位數的對應關係,方便我們在不同的幀模式(標準資料幀、擴充套件資料幀、標準遠端幀、擴充套件遠端幀)下對報文ID進行過濾。
5.CAN的傳送與接收流程
5.1CAN 傳送流程
傳送報文的流程為:應用程式選擇1個空傳送郵箱;設定識別符號、資料長度和待傳送資料;然後CAN_TIxR暫存器的TXRQ位置1,來請求傳送。TXRQ位置1後,郵箱就不再是空郵箱;而一旦郵箱不再為空,軟體對郵箱暫存器就不再有寫的許可權。TXRQ位置1後,郵箱馬上進入掛號狀態,並等待成為最高優先順序的郵箱。一旦郵箱成為最高優先順序的郵箱,其狀態就變為預定傳送狀態。當CAN匯流排進入空閒狀態,預定傳送郵箱中的報文就馬上被髮送(進入傳送狀態)。郵箱中的報文被成功傳送後,它馬上變為空郵箱,硬體相應地對CAN_TSR暫存器的RQCP和TXOK位置1,此時可以設定傳送中斷(入口地址:USB_HP_CAN_TX_IRQChannel()),進入中斷置can_tx_flag_success=1,來表明一次成功傳送。
5.2CAN接收流程
接收到的報文,被儲存在3級郵箱深度的FIFO中。FIFO完全由硬體來管理,從而節省了CPU的處理負荷,簡化了軟體並保證了資料的一致性。應用程式只能通過讀取FIFO輸出郵箱,來讀取FIFO中最先收到的報文。根據CAN協議,當報文被正確接收(直到EOF域的最後1位都沒有錯誤),且通過了識別符號過濾,那麼該報文被認為是有效報文。接收相關的中斷條件:
一旦往FIFO存入1個報文,硬體就會更新FMP[1:0]位,並且如果CAN_IER暫存器的FMPIE位為1,那麼就會產生一箇中斷請求,可以進入接收中斷讀取接收的資料(入口地址:USB_LP_CAN_RX0_IRQChannel())。
當FIFO變滿時(即第3個報文被存入),CAN_RFxR暫存器的FULL位就被置1,並且如果CAN_IER暫存器的FFIE位為1,那麼就會產生一個滿中斷請求。
在溢位的情況下,FOVR位被置1,並且如果CAN_IER暫存器的FOVIE位為1,那麼就會產生一個溢位中斷請求。
6.CAN匯流排應用——CAN與上位機通訊實驗(基於stm32f103zet6)
6.1硬體設計
本文的TX與RX採用PB9和PB8(埠重對映),他們與CAN收發器連線,CAN收發器(晶片有很多,如:TJA1050;SN65VD230)與USB/CAN轉換器連線到PC機上,具體電路如圖6。
CAN收發器:
usb/can轉換器:某寶上有賣,100多就行。
6.2程式
#include "pbdata.h"
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void CAN_Configuration(void);
int main(void)
{
CanTxMsg TxMessage;
RCC_Configuration(); //時鐘配置
GPIO_Configuration();//埠配置
NVIC_Configuration();
CAN_Configuration();
while(1)
{
//每隔1s傳送一個報文,一個報文8B
TxMessage.StdId=0xFF00>>5;//標準幀只有31-21位,對於16位暫存器而言,低五位為擴充套件幀,所以在寫16位資料時,最後5位置0
TxMessage.ExtId=0;
TxMessage.IDE=CAN_ID_STD;//選擇傳送標準幀
//TxMessage.StdId=0;
//TxMessage.ExtId=0xFFFFFFFF>>3;//擴充套件幀只有18位,在32位資料時最後三位為(IDE,RTR,TXRQ),所以在寫擴充套件幀時,最後三位要置0
//TxMessage.IDE=CAN_ID_EXT;
//傳送擴充套件幀
TxMessage.RTR=CAN_RTR_DATA;//傳送的是資料幀
//TxMessage.RTR=CAN_RTR_REMOTE;//遠端幀,只傳送ID,不傳送資料,將ID發給另一臺裝置,請求另一臺裝置返回資料
TxMessage.DLC=8;//資料長度8B
TxMessage.Data[0]=0x11;
TxMessage.Data[1]=0x22;
TxMessage.Data[2]=0x33;
TxMessage.Data[3]=0x44;
TxMessage.Data[4]=0x55;
TxMessage.Data[5]=0x66;
TxMessage.Data[6]=0x77;
TxMessage.Data[7]=0x88;
//資料內容
can_tx_success_flag = 0;
CAN_Transmit(CAN1,&tx_message);//can傳送資料
while(can_tx_success_flag == 0);//是否一次傳送成功
delay_ms(1000);//1s一次
}
}
void RCC_Configuration(void)
{
SystemInit();//72m
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//埠重對映
GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;//RX
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void CAN_Configuration(void)
{
//硬體上有個can/usb才能與PC通訊
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
//關閉時間觸發模式
CAN_InitStructure.CAN_TTCM=DISABLE;
//關閉自動離線管理
CAN_InitStructure.CAN_ABOM=DISABLE;
//關閉自動喚醒模式
CAN_InitStructure.CAN_AWUM=DISABLE;
//禁止報文自動重傳
CAN_InitStructure.CAN_NART=DISABLE;
//FIFO溢位時報文覆蓋原始檔
CAN_InitStructure.CAN_RFLM=DISABLE;
//報文傳送優先順序取決於ID號,本次只用了一個傳送郵箱,關閉TXFP
CAN_InitStructure.CAN_TXFP=DISABLE;
//工作模式(正常)
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;
//波特率設定125 KBPS
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;
CAN_InitStructure.CAN_Prescaler = 48;
//初始化CAN
CAN_Init(CAN1,&CAN_InitStructure);
//遮蔽濾波(can接收才涉及)
CAN_FilterInitStructure.CAN_FilterNumber=0;//0號濾波器
//遮蔽濾波模式
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//識別符號遮蔽位模式
//32位暫存器
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
//識別符號暫存器高16位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0F00;
//識別符號暫存器低16位
CAN_FilterInitStructure.CAN_FilterIdLow=0;
//遮蔽暫存器高16位
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0F00;
//遮蔽暫存器低16位
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0;
//過濾器將ID報文關聯到FIFO0快取區中,資料只能從這裡匯出
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;
//過濾器使能
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
//初始化過濾器
CAN_FilterInit(&CAN_FilterInitStructure);
//接收中斷使能
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
//傳送中斷使能
CAN_ITConfig(CAN1,CAN_IT_TME,ENABLE);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
CanTxMsg TxMessage;
//CAN接收
CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);//can接收的資料存在FIFO0的RxMessage裡
TxMessage.StdId=RxMessage.StdId;//標準ID
TxMessage.ExtId=RxMessage.ExtId;//擴充套件ID
TxMessage.IDE=RxMessage.IDE;//標準幀還是擴充套件幀
TxMessage.RTR=RxMessage.RTR;//資料幀還是遠端幀
TxMessage.DLC=RxMessage.DLC;//待傳輸資料長度
TxMessage.Data[0]=RxMessage.Data[0];
TxMessage.Data[1]=RxMessage.Data[1];
TxMessage.Data[2]=RxMessage.Data[2];
TxMessage.Data[3]=RxMessage.Data[3];
TxMessage.Data[4]=RxMessage.Data[4];
TxMessage.Data[5]=RxMessage.Data[5];
TxMessage.Data[6]=RxMessage.Data[6];
TxMessage.Data[7]=RxMessage.Data[7];
//CAN傳送
CAN_Transmit(CAN1,&TxMessage);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
//進傳送中斷的目的是為了設定can傳送成功標誌位
void USB_HP_CAN1_TX_IRQHandler(void) //CAN TX
{
if (CAN_GetITStatus(CAN1,CAN_IT_TME)!= RESET)
{
CAN_ClearITPendingBit(CAN1,CAN_IT_TME);
can_tx_success_flag=1;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
相關文章
- CAN匯流排協議簡介及其常見的應用領域協議
- Can匯流排介紹
- CAN匯流排原理_學習
- CAN匯流排分析儀工具-CAN轉USB智慧協議轉換器協議
- LLM-kimi:BMS-CAN匯流排
- 嵌入式作業6.3 CAN 匯流排程式設計程式設計
- CAN匯流排協議 學習筆記協議筆記
- Kvaser—靈活多變的CAN匯流排介面方案
- 如何通過波形解析can匯流排資料
- ECU通訊:CAN匯流排模擬測試
- 你玩過輕量系統軟匯流排應用嗎?
- 流應用程式——流
- 匯流排
- 管理應用程式——流
- 【轉】設定Qt應用程式圖示及應用程式名QT
- 微信小程式、流應用、原生應用app、輕應用微信小程式APP
- 匯流排協議系列——USART協議初探協議
- IIC序列匯流排的組成及工作原理
- 事件匯流排事件
- 前端匯流排前端
- STM32F103 高階應用(2)——中斷應用
- MACH SYSTEMS—匯流排介面轉換工具Mac
- 單調棧理解及應用
- 事件匯流排demo事件
- javascript事件匯流排JavaScript事件
- CAN(FD)、LIN匯流排通訊和資料庫設計工具-VDE資料庫
- WebApi系列~對HttpClient的響應流進行解壓WebAPIHTTPclient
- 序列匯流排的學習
- EventBridge 事件匯流排及 EDA 架構解析事件架構
- 事件匯流排 + 函式計算構建雲上最佳事件驅動架構應用事件函式架構
- RxJS進階——關於流的理解和應用JS
- 理解企業應用框架 (轉)框架
- 將Abp預設事件匯流排改造為分散式事件匯流排事件分散式
- CMD FIFO的深入理解:一種避免佔用匯流排頻寬的仲裁方法
- [轉]SSH原理及應用
- 說說對WebSocket的理解?應用場景?Web
- Vue事件匯流排(EventBus)Vue事件
- Vue 事件中央匯流排Vue事件