您的位置 首页 资料

详解stm32的CAN控制器(程序共享)

详解stm32的CAN控制器(程序分享)-首先简单介绍一下CAN总线,关于CAN总线是谁发明的,CAN总线的历史,CAN总线的发展,CAN总线的应用场合,这些,通通不说。这里只是以我个人理解,简单说说CAN通信。CAN总线的端点没有地址(除非自己在帧里定义地址),CAN总线通信不用地址,用标识符,不是单独的谁发给谁,而是,你总是发送给整个网络。

首要简略介绍一下CAN总线,关于CAN总线是谁创造的,CAN总线的前史,CAN总线的开展,CAN总线的运用场合,这些,统统不说。这儿仅仅以我个人了解,简略说说CAN通讯。CAN总线的端点没有地址(除非自己在帧里界说地址),CAN总线通讯不必地址,用标识符,不是独自的谁发给谁,而是,你总是发送给整个网络。然后每个节点都有过滤器,对网络上的传达的帧的标识符进行过滤,自己想要什么样的帧,能够设置自己的过滤器,接纳相关的帧信息。假如两个节点一起发送怎么办?这个不必咱们忧虑,CAN操控器会自己裁定,让高优先级的帧先发。

然后咱们能够了解一下stm32的CAN操控器。

详解stm32的CAN操控器(程序共享)

如上图所示,stm32有两个can操控器,can1(主),和can2(从),其间过滤器的设置是经过can1来设置,其他作业形式,波特率等,能够各自设置。每个操控器有三个发送邮箱,两个fifo,每个fifo有三个接纳邮箱。

发送:挑选一个空的发送邮箱,把帧信息写到该发送邮箱的寄存器里,恳求发送,操控器就会依据标识符的优先级把帧先后发送出去。

接纳:假如接纳到的帧的标识符能过过滤表的一系列过滤,该帧信息就会保存在fifo接纳邮箱的寄存器里。

过滤器:stm32f407共有28组过滤器,每组过滤器能够设置相关到fifo0或许fifo1,每组都包含两个32位存储器,能够装备成一个32位有位屏蔽功用的标识符过滤器,或许两个32位彻底匹配的标识符过滤器,或许两个16位有位屏蔽功用的标识符过滤器,或许四个16位彻底匹配的标识符过滤器。如下图所示:

详解stm32的CAN操控器(程序共享)

我所说的彻底匹配的意思是,接纳到的帧的标识符每一位都要跟过滤器对应的位相同,才干过得了这个过滤器。有位屏蔽功用的意思是一个寄存器放标识符,一个放屏蔽掩码,屏蔽掩码为1的位对应的接纳到的帧的标识符的位与对应的放标识符的寄存器的位共同,就能经过。

传输一位的时刻和波特率的核算:

详解stm32的CAN操控器(程序共享)

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

详解stm32的CAN操控器(程序共享)

其间Tpclk为APB1的时钟周期,假设为

Tpclk = 1/42M

0≦TS1≦7

0≦TS2≦15

0≦BRP≦1021

依据以上数据,有

(TS2+TS1+3)(BRP+1)=42

令BRP=2,有

TS2+TS1=11

令TS1=8,TS2=3

设置过程:

1. 设置中止优先级分组(假如之前没有设置),这个最好一个程序里只在最初设置一次。

2. 使能相关GPIO时钟。

3. 挑选相关GPIO引脚的复用功用。

4. 设置相关GPIO引脚为复用形式。

5. 设置相关GPIO引脚的速度,方法。

6. 设置主操控寄存器MCR,进入初始化形式

7. 等候进入初始化形式

8. 设置波特率。

9. 其他设置。

10. 假如要用到中止,在中止使能寄存器IER中使能相关中止呼应。

11. 假如要用到中止,设置相关中止优先级(NVIC_IP)。

12. 假如要用到中止,使能相关中止(NVIC_ISER)。

13. 设置主操控寄存器MCR,进入正常作业形式。

14. 设置FMR,使过滤器组作业在初始化形式。

15. 设置FMR的CAN2SB,确认CAN2的过滤器组从哪一组开端。

16. 设置用到的过滤器组的作业方法。

17. 设置用到的过滤器组的位宽。

18. 给fifo0和fifo2区分(相关)过滤组。

19. 禁用用到的过滤器组。

20. 设置过滤器组的标识符,帧类型等。

21. 使能相关过滤器组。

22. 设置FMR,使过滤器组作业在正常形式。

23. 假如要用中止,编写中止服务函数(函数名是固定的)。

24. 中止服务函数里查看是哪个中止。

25. 编写相应服务程序。

电路请拜见本博客:小东西之——CAN收发器

程序:

[plain] view plaincopy/************************************

标题:操作CAN的操练

软件渠道:IAR for ARM6.21

硬件渠道:stm32f4-discovery

主频:168M

描绘:经过硬件收发器衔接CAN1,CAN2

组成一个两个端点的网络

CAN1循环宣布数据帧

CAN2接纳过滤数据帧

uart把CAN2接纳到

的数据帧发到超级终端

author:小舟

data:2012-08-14

*************************************/

#include 《stm32f4xx.h》

#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; //中止优先级分组 抢占:呼应=3:1

MyDebugger_Init();

TIM7_init();

MyDebugger_Message( “\n\rtesting.。。.。。\n\r” ,

sizeof(“\n\rtesting.。。.。。\n\r”)/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);//在调试时,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);//在调试时,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; //抢占优先级101,呼应优先级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位分为四个16位寄存器,过滤四个标识符

//CAN1-》FS1R |= (1《《15);//过滤器组15为单个32位寄存器,用于扩展标识符

CAN1-》FFA1R = 0x0fffc000;//0~13号过滤器组相关到fifo0,14~27号过滤器组相关到fifo1

CAN1-》FA1R &= ~(1《《14);//禁用过滤器组14

/*

过滤器组0寄存器分为4个十六位过滤器:

标识符列表:

过滤器编号 匹配规范标识符 RTR IDE EXID[17:15]

0 0x7cb(111 1100 1011b) 数据帧 规范标识符 000b

1 0x4ab(100 1010 1011b) 数据帧 规范标识符 000b

2 0x7ab(111 1010 1011b) 数据帧 规范标识符 000b

3 0x40b(100 0000 1011b) 数据帧 规范标识符 000b

*/

CAN1-》sFilterRegister[14].FR1 &= 0x00000000;

CAN1-》sFilterRegister[14].FR2 &= 0x00000000;

CAN1-》sFilterRegister[14].FR1 |= ((0x7cb《《5)|(0《《4)|(0《《3));

CAN1-》sFilterRegister[14].FR1 |= ((0x4ab《《21)|(0《《20)|(0《《19));

CAN1-》sFilterRegister[14].FR2 |= ((0x7ab《《5)|(0《《4)|(0《《3));

CAN1-》sFilterRegister[14].FR2 |= ((0x40b《《21)|(0《《20)|(0《《19));

CAN1-》FA1R |= (1《《14);//使能过滤器组14

CAN1-》FMR &= ~1; //过滤器组正常作业

while(1)

{

/*

挑选空的发送邮箱:

规范标识符0x7ab(111 1010 1011b)

数据帧

不运用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x7ab《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000008;//发送数据长度为8

CAN1-》sTxMailBox[empty_box].TDLR = 0x12345678;

CAN1-》sTxMailBox[empty_box].TDHR = 0x9abcdef0;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//恳求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

/*

挑选空的发送邮箱:

规范标识符0x4ab(100 1010 1011b)

数据帧

不运用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x4ab《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000008;//发送数据长度为8

CAN1-》sTxMailBox[empty_box].TDLR = 0x56781234;

CAN1-》sTxMailBox[empty_box].TDHR = 0x9abcdef0;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//恳求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

/*

挑选空的发送邮箱:

规范标识符0x7cb(100 1010 1011b)

数据帧

不运用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x7cb《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000006;//发送数据长度为6

CAN1-》sTxMailBox[empty_box].TDLR = 0x56781234;

CAN1-》sTxMailBox[empty_box].TDHR = 0x00009abc;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//恳求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

/*

挑选空的发送邮箱:

规范标识符0x40b(100 0000 1011b)

数据帧

不运用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x40b《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000004;//发送数据长度为4

CAN1-》sTxMailBox[empty_box].TDLR = 0x56781234;

CAN1-》sTxMailBox[empty_box].TDHR = 0x00000000;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//恳求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

}

}

/****************************************

函数名:CAN_GPIO_config

参数:无

返回值:无

功用:设置CAN1,2操控器用到IO口

CAN1_TX———PD1

CAN1_RX———PB8

CAN2_TX———PB13

CAN2_RX———PB5

****************************************/

void CAN_GPIO_config()

{

RCC-》AHB1ENR |= ((1《《1) | (1《《3));//使能GPIOB、D时钟

GPIOB-》AFR[0] |= 0x00900000; //AF9

GPIOB-》AFR[1] |= 0x00900009;

GPIOD-》AFR[0] |= 0x00000090;

GPIOB-》MODER &= 0xF3FCF3FF; //第二功用

GPIOB-》MODER |= 0x08020800;

GPIOD-》MODER &= 0xFFFFFFF3;

GPIOD-》MODER |= 0x00000008;

GPIOB-》OSPEEDR &= 0xF3FCF3FF; //50M

GPIOB-》OSPEEDR |= 0x08020800;

GPIOD-》OSPEEDR &= 0xFFFFFFF3;

GPIOD-》OSPEEDR |= 0x00000008;

GPIOB-》PUPDR &= 0xF3FCF3FF; //上拉

GPIOB-》PUPDR |= 0x04010400;

GPIOD-》PUPDR &= 0xFFFFFFF3;

GPIOD-》PUPDR |= 0x00000004;

}

/****************************************

函数名:CAN2_RX1_IRQHandler

参数:无

返回值:无

功用:CAN2fifo1接纳中止处理

把信息存进循环行列

****************************************/

void CAN2_RX1_IRQHandler()

{

if(CAN2-》RF1R & (0x00000003))//接纳到新的音讯,fifo1非空

{

Producer++;

if(Producer == RECEIVE_BUFFER_SIZE)Producer = 0;

if(Producer != Consumer)

{

CAN2_receive_buffer[Producer][0] = CAN2-》sFIFOMailBox[1].RIR;

CAN2_receive_buffer[Producer][1] = CAN2-》sFIFOMailBox[1].RDTR;

CAN2_receive_buffer[Producer][2] = CAN2-》sFIFOMailBox[1].RDLR;

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ziliao/347988.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部