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