簡介:
CAN是Controller Area Network 的縮寫(以下稱為CAN),是ISO國際標準化的串行通信協(xié)議。由德國電氣商博世公司在1986年率先提出。此后,CAN通過ISO11898及ISO11519進行了標準化。現(xiàn)在在歐洲已是汽車網(wǎng)絡的標準協(xié)議。
CAN協(xié)議經(jīng)過ISO標準化后有兩個標準:ISO11898標準和ISO11519-2標準。其中ISO11898是針對通信速率為125Kbps~1Mbps的高速通信標準,而ISO11519-2是針對通信速率為125Kbps以下的低速通信標準。
CAN具有很高的可靠性,廣泛應用于:汽車電子、工業(yè)自動化、船舶、醫(yī)療設備、工業(yè)設備等方面。
特點:多主控制??偩€空閑時,所有單元都可發(fā)送消息,而兩個以上的單元同時開始發(fā)送消息時,根據(jù)標識符(ID,非地址)決定優(yōu)先級。兩個以上的單元同時開始發(fā)送消息時,對各消息ID 的每個位進行逐個仲裁比較。仲裁獲勝(優(yōu)先級最高)的單元可繼續(xù)發(fā)送消息,仲裁失利的單元則立刻停止發(fā)送而進行接收工作。
系統(tǒng)柔軟性。連接總線的單元,沒有類似“地址”的信息,因此,在總線上添加單元時,已連接的其他單元的軟硬件和應用層都不需要做改變。
速度快,距離遠。最高1Mbps(距離<40M),最遠可達10KM(速率<5Kbps)。
具有錯誤檢測、錯誤通知和錯誤恢復功能。所有單元都可以檢測錯誤(錯誤檢測功能),檢測出錯誤的單元會立即同時通知其他所有單元(錯誤通知功能),正在發(fā)送消息的單元一旦檢測出錯誤,會強制結(jié)束當前的發(fā)送。強制結(jié)束發(fā)送的單元會不斷反復地重新發(fā)送此消息直到成功發(fā)送為止(錯誤恢復功能)。
故障封閉功能。CAN可以判斷出錯誤的類型是總線上暫時的數(shù)據(jù)錯誤(如外部噪聲等)還是持續(xù)的數(shù)據(jù)錯誤(如單元內(nèi)部故障、驅(qū)動器故障、斷線等)。由此功能,當總線上發(fā)生持續(xù)數(shù)據(jù)錯誤時,可將引起此故障的單元從總線上隔離出去。
連接節(jié)點多。CAN 總線是可同時連接多個單元的總線??蛇B接的單元總數(shù)理論上是沒有限制的。但實際上可連接的單元數(shù)受總線上的時間延遲及電氣負載的限制。降低通信速度,可連接的單元數(shù)增加;提高通信速度,則可連接的單元數(shù)減少。
物理特征:總線電平=CAN_H的電壓-CAN_L的電壓
顯性電平對應邏輯0=總線電平為2V左右
隱性電平對應邏輯0=總線電平為0V
顯性電平具有優(yōu)先權,只要有一個單元輸出顯性電平,總線上即為顯性電平。而隱形電平則具有包容的意味,只有所有的單元都輸出隱性電平,總線上才為隱性電平(顯性電平比隱性電平更強)。另外,在CAN總線的起止端都有一個120Ω的終端電阻,來做阻抗匹配,以減少回波反射。
幀種類介紹:注:其中,數(shù)據(jù)幀和遙控幀有標準格式和擴展格式兩種格式。
標準格式有11 個位的標識符(ID),擴展格式有29 個位的ID 。
支持CAN協(xié)議2.0A和2.0B主動模式
波特率最高達1Mbps
支持時間觸發(fā)通信
具有3個發(fā)送郵箱
具有3級深度的2個接收FIFO
可變的篩選器組(也稱過濾器組,最多28個,F(xiàn)1普通為14個,互聯(lián)和F4為28個,另外F4有兩個can,F(xiàn)1只有一個)
3種模式:
工作模式:
初始化模式(INRQ=1,SLEEP=0)
正常模式(INRQ=0,SLEEP=0)
睡眠模式(SLEEP=1)
測試模式:
靜默模式( LBKM=0,SILM=1 )
環(huán)回模式( LBKM=1,SILM=0 )
環(huán)回靜默模式(LBKM=1,SILM=1)
調(diào)試模式(不常用)
STM32 CAN篩選器位寬和模式配置:CAN的標識符不表示目的地址而是表示發(fā)送優(yōu)先級,接收節(jié)點根據(jù)標識符的值,來決定是否接收對應消息。
標識符屏蔽模式:過濾一組標識符
標識符列表模式:過濾一個標識符
例:設置篩選器組0工作在:1個32位篩選器-標識符屏蔽模式,然后設置CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00。其中存放到CAN_F0R1的值就是期望收到的ID,即(STID+EXTID+IDE+RTR)最好是:0XFFFF0000。而0XFF00FF00就是設置我們需要必須關心的ID,表示收到的映像,其位[31:24]和位[15:8]這16個位的必須和CAN_F0R1中對應的位一模一樣,而另外的16個位則不關心,可以一樣,也可以不一樣,都認為是正確的ID,即收到的映像必須是0XFFxx00xx,才算是正確的(x表示不關心)。
波特率設置:寄存器:TM32F103,設TS1=8、TS2=7、BRP=3,波特率=36000/[(9+8+1)*4]=500Kbps。
STM32F407,設TS1=6、TS2=5、BRP=5,波特率=42000/[(7+6+1)*6]=500Kbps。
CAN主控制寄存器(CAN_MCR)
該寄存器的我們僅介紹下INRQ位,該位用來控制初始化請求。
設置INRQ=0,可使CAN從初始化模式進入正常工作模式。
設置INRQ=1,可使CAN從正常工作模式進入初始化模式。
CAN初始化時,先設置INRQ=1,進入初始化模式,進行初始化(尤其是CAN_BTR的設置,該寄存器,必須在CAN正常工作之前設置),之后再設置INRQ=0,進入正常工作模式。
CAN位時序寄存器(CAN_BTR)設置波特率
CAN接收FIFO寄存器(CAN_RF0R/CAN_RF1R)
CAN發(fā)送郵箱標識符寄存器(CAN_TIxR)(x=0~2)
CAN發(fā)送郵箱數(shù)據(jù)長度和時間戳寄存器 (CAN_TDTxR) (x=0~2)
低4位用于設置發(fā)送多少個字節(jié),最多為8個字節(jié)
CAN發(fā)送郵箱數(shù)據(jù)寄存器(CAN_TDLxR/CAN_TDHxR) (x=0~2)
CAN接收FIFO郵箱標識符寄存器(CAN_RIxR)(x=0/1)
CAN接收FIFO郵箱數(shù)據(jù)長度和時間戳寄存器(CAN_RDTxR) (x=0/1)
CAN接收FIFO郵箱郵箱數(shù)據(jù)寄存器(CAN_RDLxR/CAN_RDHxR) (x=0/1)
CAN篩選器模式寄存器(CAN_FM1R)(0標識符屏蔽,1標識符列表)
CAN篩選器尺度寄存器(CAN_FS1R)(0雙16位,1單32位)
CAN篩選器FIFO關聯(lián)寄存器(CAN_FFA1R)(0篩選器分到FIFO0,1篩選器分到FIFO1)
CAN篩選器激活寄存器(CAN_FA1R)(0未激活,1激活)
CAN篩選器組i寄存器x(CAN_FiRx)(i=0~27,x=1/2)(F103篩選器只有14個)
①配置相關引腳的 復用功能,使能CAN時鐘。
N的時鐘通過APB1ENR的第25位來設置。其次要設置CAN的相關引腳為復用輸出,這里我們需要設置PA11為上拉輸入(CAN_RX引腳)PA12為復用輸出(CAN_TX引腳),并使能PA口的時鐘(CAN_TX引腳),并使能PA口的時鐘
②設置CAN工作模式及波特率等。
通過先設置CAN_MCR寄存器的INRQ位,讓CAN進入初始化模式,然后設置CAN_MCR的其他相關控制位。再通過CAN_BTR設置波特率和工作模式(正常模式/環(huán)回模式)等信息。 最后設置INRQ為0,退出初始化模式。
③設置濾波器。
CODE:本例程,我們將使用篩選器組0,并工作在32位標識符屏蔽位模式下。先設置CAN_FMR的FINIT位,進入初始化模式,然后設置篩選器組0的工作模式以及標識符ID和屏蔽位。最后激活篩選器,并退出初始化模式。
//can.c#include"can.h"#include"led.h"#include"delay.h"#include"usart.h"http://CAN初始化//tsjw:重新同步跳躍時間單元.范圍:CAN_SJW_1tq~CAN_SJW_4tq//tbs2:時間段2的時間單元.范圍:CAN_BS2_1tq~CAN_BS2_8tq;//tbs1:時間段1的時間單元.范圍:CAN_BS1_1tq~CAN_BS1_16tq//brp:波特率分頻器.范圍:1~1024;tq=(brp)*tpclk1//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回環(huán)模式;//Fpclk1的時鐘在初始化的時候設置為36M,如果設置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//則波特率為:36M/((8+9+1)*4)=500Kbps//返回值:0,初始化OK;//其他,初始化失敗;u8CAN_Mode_Init(u8tsjw,u8tbs2,u8tbs1,u16brp,u8mode){GPIO_InitTypeDefGPIO_InitStructure;CAN_InitTypeDefCAN_InitStructure;CAN_FilterInitTypeDefCAN_FilterInitStructure;#ifCAN_RX0_INT_ENABLENVIC_InitTypeDefNVIC_InitStructure;#endifRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);//使能CAN1時鐘GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化IOGPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//上拉輸入GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化IO//CAN單元設置CAN_InitStructure.CAN_TTCM=DISABLE;//非時間觸發(fā)通信模式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;//優(yōu)先級由報文標識符決定CAN_InitStructure.CAN_Mode=mode;//模式設置:mode:0,普通模式;1,回環(huán)模式;//設置波特率CAN_InitStructure.CAN_SJW=tsjw;//重新同步跳躍寬度(Tsjw)為tsjw+1個時間單位CAN_SJW_1tqCAN_SJW_2tqCAN_SJW_3tqCAN_SJW_4tqCAN_InitStructure.CAN_BS1=tbs1;//Tbs1=tbs1+1個時間單位CAN_BS1_1tq~CAN_BS1_16tqCAN_InitStructure.CAN_BS2=tbs2;//Tbs2=tbs2+1個時間單位CAN_BS2_1tq~CAN_BS2_8tqCAN_InitStructure.CAN_Prescaler=brp;//分頻系數(shù)(Fdiv)為brp+1CAN_Init(CAN1,&CAN_InitStructure);//初始化CAN1CAN_FilterInitStructure.CAN_FilterNumber=0;//過濾器0CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//屏蔽位模式CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//32位寬CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;//32位IDCAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASKCAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//過濾器0關聯(lián)到FIFO0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活過濾器0CAN_FilterInit(&CAN_FilterInitStructure);//濾波器初始化#ifCAN_RX0_INT_ENABLECAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息掛號中斷允許.NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//主優(yōu)先級為1NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//次優(yōu)先級為0NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);#endifreturn0;}#ifCAN_RX0_INT_ENABLE//使能RX0中斷//中斷服務函數(shù)voidUSB_LP_CAN1_RX0_IRQHandler(void){CanRxMsgRxMessage;inti=0;CAN_Receive(CAN1,0,&RxMessage);for(i=0;i<8;i++)printf("rxbuf[%d]:%drn",i,RxMessage.Data[i]);}#endif//can發(fā)送一組數(shù)據(jù)(固定格式:ID為0X12,標準幀,數(shù)據(jù)幀)//len:數(shù)據(jù)長度(最大為8)//msg:數(shù)據(jù)指針,最大為8個字節(jié).//返回值:0,成功;//其他,失敗;u8Can_Send_Msg(u8*msg,u8len){u8mbox;u16i=0;CanTxMsgTxMessage;TxMessage.StdId=0x12;//標準標識符TxMessage.ExtId=0x12;//設置擴展標示符TxMessage.IDE=CAN_Id_Standard;//標準幀TxMessage.RTR=CAN_RTR_Data;//數(shù)據(jù)幀TxMessage.DLC=len;//要發(fā)送的數(shù)據(jù)長度for(i=0;i=0XFFF)return1;return0;}//can口接收數(shù)據(jù)查詢//buf:數(shù)據(jù)緩存區(qū);//返回值:0,無數(shù)據(jù)被收到;//其他,接收的數(shù)據(jù)長度;u8Can_Receive_Msg(u8*buf){u32i;CanRxMsgRxMessage;if(CAN_MessagePending(CAN1,CAN_FIFO0)==0)return0;//沒有接收到數(shù)據(jù),直接退出CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);//讀取數(shù)據(jù)for(i=0;i<8;i++)buf[i]=RxMessage.Data[i];returnRxMessage.DLC;}main.c#include"led.h"#include"delay.h"#include"key.h"#include"sys.h"#include"lcd.h"#include"usart.h"#include"can.h"intmain(void){u8key;u8i=0,t=0;u8cnt=0;u8canbuf[8];u8res;u8mode=CAN_Mode_LoopBack;//CAN工作模式;CAN_Mode_Normal(0):普通模式,CAN_Mode_LoopBack(1):環(huán)回模式delay_init();//延時函數(shù)初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置中斷優(yōu)先級分組為組2:2位搶占優(yōu)先級,2位響應優(yōu)先級uart_init(115200);//串口初始化為115200LED_Init();//初始化與LED連接的硬件接口LCD_Init();//初始化LCDKEY_Init();//按鍵初始化CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化環(huán)回模式,波特率500KbpsPOINT_COLOR=RED;//設置字體為紅色LCD_ShowString(60,50,200,16,16,"WarShipSTM32");LCD_ShowString(60,70,200,16,16,"CANTEST");LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(60,110,200,16,16,"2015/1/15");LCD_ShowString(60,130,200,16,16,"LoopBackMode");LCD_ShowString(60,150,200,16,16,"KEY0:SendWK_UP:Mode");//顯示提示信息POINT_COLOR=BLUE;//設置字體為藍色LCD_ShowString(60,170,200,16,16,"Count:");//顯示當前計數(shù)值LCD_ShowString(60,190,200,16,16,"SendData:");//提示發(fā)送的數(shù)據(jù)LCD_ShowString(60,250,200,16,16,"ReceiveData:");//提示接收到的數(shù)據(jù)while(1){key=KEY_Scan(0);if(key==KEY0_PRES)//KEY0按下,發(fā)送一次數(shù)據(jù){for(i=0;i<8;i++){canbuf[i]=cnt+i;//填充發(fā)送緩沖區(qū)if(i<4)LCD_ShowxNum(60+i*32,210,canbuf[i],3,16,0X80);//顯示數(shù)據(jù)elseLCD_ShowxNum(60+(i-4)*32,230,canbuf[i],3,16,0X80);//顯示數(shù)據(jù)}res=Can_Send_Msg(canbuf,8);//發(fā)送8個字節(jié)if(res)LCD_ShowString(60+80,190,200,16,16,"Failed");//提示發(fā)送失敗elseLCD_ShowString(60+80,190,200,16,16,"OK");//提示發(fā)送成功}elseif(key==WKUP_PRES)//WK_UP按下,改變CAN的工作模式{mode=!mode;CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);//CAN普通模式初始化,波特率500KbpsPOINT_COLOR=RED;//設置字體為紅色if(mode==0)//普通模式,需要2個開發(fā)板{LCD_ShowString(60,130,200,16,16,"NnormalMode");}else//回環(huán)模式,一個開發(fā)板就可以測試了.{LCD_ShowString(60,130,200,16,16,"LoopBackMode");}POINT_COLOR=BLUE;//設置字體為藍色}key=Can_Receive_Msg(canbuf);if(key)//接收到有數(shù)據(jù){LCD_Fill(60,270,130,310,WHITE);//清除之前的顯示for(i=0;i