首先簡單介紹一下CAN總線,關(guān)于CAN總線是誰發(fā)明的,CAN總線的歷史,CAN總線的發(fā)展,CAN總線的應用場合,這些,通通不說。這里只是以我個人理解,簡單說說CAN通信。CAN總線的端點沒有地址(除非自己在幀里定義地址),CAN總線通信不用地址,用標識符,不是單獨的誰發(fā)給誰,而是,你總是發(fā)送給整個網(wǎng)絡。然后每個節(jié)點都有過濾器,對網(wǎng)絡上的傳播的幀的標識符進行過濾,自己想要什么樣的幀,可以設置自己的過濾器,接收相關(guān)的幀信息。如果兩個節(jié)點同時發(fā)送怎么辦?這個不用我們擔心,CAN控制器會自己仲裁,讓高優(yōu)先級的幀先發(fā)。
然后我們可以了解一下stm32的CAN控制器。
如上圖所示,stm32有兩個can控制器,can1(主),和can2(從),其中過濾器的設置是通過can1來設置,其他工作模式,波特率等,可以各自設置。每個控制器有三個發(fā)送郵箱,兩個fifo,每個fifo有三個接收郵箱。
發(fā)送:選擇一個空的發(fā)送郵箱,把幀信息寫到該發(fā)送郵箱的寄存器里,請求發(fā)送,控制器就會根據(jù)標識符的優(yōu)先級把幀先后發(fā)送出去。
接收:如果接收到的幀的標識符能過過濾表的一系列過濾,該幀信息就會保存在fifo接收郵箱的寄存器里。
fifo1,每組都包括兩個32位存儲器,可以配置成一個32位有位屏蔽功能的標識符過濾器,或者兩個32位完全匹配的標識符過濾器,或者兩個16位有位屏蔽功能的標識符過濾器,或者四個16位完全匹配的標識符過濾器。如下圖所示:
我所說的完全匹配的意思是,接收到的幀的標識符每一位都要跟過濾器對應的位一樣,才能過得了這個過濾器。有位屏蔽功能的意思是一個寄存器放標識符,一個放屏蔽掩碼,屏蔽掩碼為1的位對應的接收到的幀的標識符的位與對應的放標識符的寄存器的位一致,就能通過。
傳輸一位的時間和波特率的計算:
CAN控制器的波特率是由APB時鐘線和CAN位時序寄存器CAN_BTR的TS2[3:0]、TS1[2:0]和BRP[9:0]確定的,其中,TS1[2:0]定義了時間段1占用多少個時間單元,TS2[3:0]定義了時間段2占用多少個時間單元,BRP[9:0]定義對APB1時鐘的分頻。
PS:設置波特率為1M
其中Tpclk為APB1的時鐘周期,假設為
Tpclk = 1/42M
0≦TS1≦7
0≦TS2≦15
0≦BRP≦1021
根據(jù)以上數(shù)據(jù),有
(TS2+TS1+3)(BRP+1)=42
令BRP=2,有
TS2+TS1=11
令TS1=8,TS2=3
設置步驟:
1.設置中斷優(yōu)先級分組(如果之前沒有設置),這個最好一個程序里只在開頭設置一次。
2.使能相關(guān)GPIO時鐘。
3.選擇相關(guān)GPIO引腳的復用功能。
4.設置相關(guān)GPIO引腳為復用模式。
5.設置相關(guān)GPIO引腳的速度,方式。
6.設置主控制寄存器MCR,進入初始化模式
7.等待進入初始化模式
8.設置波特率。
9.其他設置。
10.如果要用到中斷,在中斷使能寄存器IER中使能相關(guān)中斷響應。
11.如果要用到中斷,設置相關(guān)中斷優(yōu)先級(NVIC_IP)。
12.如果要用到中斷,使能相關(guān)中斷(NVIC_ISER)。
13.設置主控制寄存器MCR,進入正常工作模式。
14.設置FMR,使過濾器組工作在初始化模式。
15.設置FMR的CAN2SB,確定CAN2的過濾器組從哪一組開始。
16.設置用到的過濾器組的工作方式。
17.設置用到的過濾器組的位寬。
18.給fifo0和fifo2劃分(關(guān)聯(lián))過濾組。
19.禁用用到的過濾器組。
20.設置過濾器組的標識符,幀類型等。
21.使能相關(guān)過濾器組。
22.設置FMR,使過濾器組工作在正常模式。
23.如果要用中斷,編寫中斷服務函數(shù)(函數(shù)名是固定的)。
24.中斷服務函數(shù)里檢查是哪個中斷。
25.編寫相應服務程序。
程序:
/************************************
標題:操作CAN的練習
軟件平臺:IAR for ARM6.21
硬件平臺:stm32f4-discovery
主頻:168M
描述:通過硬件收發(fā)器連接CAN1,CAN2
組成一個兩個端點的網(wǎng)絡
CAN1循環(huán)發(fā)出數(shù)據(jù)幀
CAN2接收過濾數(shù)據(jù)幀
用uart把CAN2接收到
的數(shù)據(jù)幀發(fā)到超級終端
author:小船
data:2012-08-14
*************************************/
#include
#include "MyDebugger.h"
#define RECEIVE_BUFFER_SIZE 20
u32 CAN2_receive_buffer[RECEIVE_BUFFER_SIZE][4];
u8 UART_send_buffer[1800];
u8 Consumer = 0;
u8 Producer = 0;
u32 Gb_TimingDelay;
void Delay(uint32_t nTime);
void TIM7_init();//定時1s
u32 get_rece_data();
void CAN_GPIO_config();
void main ()
{
u32 empty_box;
SysTick_Config(SystemCoreClock / 1000); //設置systemtick一毫秒中斷
SCB->AIRCR = 0x05FA0000 " 0x400; //中斷優(yōu)先級分組 搶占:響應=3:1
MyDebugger_Init();
TIM7_init();
MyDebugger_Message( "nrtesting......nr" ,
sizeof("nrtesting......nr")/sizeof(char) );
CAN_GPIO_config();
RCC->APB1ENR |= ((1<<25)|(1<<26));//使能CAN1、CAN2時鐘
CAN1->MCR = 0x00000000;
/*
請求進入初始化模式
禁止報文自動重傳
自動喚醒模式
*/
CAN1->MCR |= ((1<<0)|(1<<4)|(1<<5));
CAN1->MCR &= ~(1<<16);//在調(diào)試時,CAN照常工作
while(!(CAN1->MSR & 0xfffffffe)) //等待進入初始化模式
{
MyDebugger_LEDs(orange, on);
}
MyDebugger_LEDs(orange, off);
/*
正常模式
重新同步跳躍寬度(1+1)tq
TS2[2:0]=3
TS1[3:0]=8
BRP[9:0]=2
ps:
tq = (BRP[9:0] + 1) x tPCLK,
tBS2 = tq x (TS2[2:0] + 1),
tBS1 = tq x (TS1[3:0] + 1),
NominalBitTime = 1 × tq+tBS1+tBS2,
BaudRate = 1 / NominalBitTime
波特率設為1M
*/
CAN1->BTR = ((0<<30)|(0x01<<24)|(3<<20)|(8<<16)|(2<<0));
CAN1->MCR &= ~(0x00000001);//正常工作模式
CAN2->MCR = 0x00000000;
/*
請求進入初始化模式
禁止報文自動重傳
自動喚醒模式
*/
CAN2->MCR |= ((1<<0)|(1<<4)|(1<<5));
CAN2->MCR &= ~(1<<16);//在調(diào)試時,CAN照常工作
while(!(CAN2->MSR & 0xfffffffe)) //等待進入初始化模式
{
MyDebugger_LEDs(orange, on);
}
MyDebugger_LEDs(orange, off);
/*
正常模式
重新同步跳躍寬度(1+1)tq
TS2[2:0]=3
TS1[3:0]=8
BRP[9:0]=2
ps:
tq = (BRP[9:0] + 1) x tPCLK,
tBS2 = tq x (TS2[2:0] + 1),
tBS1 = tq x (TS1[3:0] + 1),
NominalBitTime = 1 × tq+tBS1+tBS2,
BaudRate = 1 / NominalBitTime
波特率設為1M
*/
CAN2->BTR = ((0<<30)|(0x01<<24)|(3<<20)|(8<<16)|(2<<0));
CAN2->IER &= 0x00000000;
/*
FIFO1消息掛號中斷使能
FIFO1滿中斷使能
FIFO1溢出中斷使能
*/
CAN2->IER |= ((1<<4)|(1<<5)|(1<<6));
NVIC->IP[65] = 0xa0; //搶占優(yōu)先級101,響應優(yōu)先級0
NVIC->ISER[2] |= (1<<1); //使能中斷線65,也就是can2_rx1中斷
CAN2->MCR &= ~(0x00000001);//正常工作模式
//總共有28組過濾器
CAN1->FMR |= 1; //過濾器組工作在初始化模式
CAN1->FMR &= 0xffffc0ff;//CAN2的過濾器組從14開始
CAN1->FMR |= (14<<8);
CAN1->FM1R |= (1<<14);//過濾器組14的寄存器工作在標識符列表模式
//位寬為16位,2個32位