打印
[STM32F4]

【转】stm32f407之CAN控制器(操作寄存器)

[复制链接]
877|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
焚琴煮鹤|  楼主 | 2016-9-10 21:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
   首先简单介绍一下CAN总线,关于CAN总线是谁发明的,CAN总线的历史,CAN总线的发展,CAN总线的应用场合,这些,通通不说。这里只是以我个人理解,简单说说CAN通信。CAN总线的端点没有地址(除非自己在帧里定义地址),CAN总线通信不用地址,用标识符,不是单独的谁发给谁,而是,你总是发送给整个网络。然后每个节点都有过滤器,对网络上的传播的帧的标识符进行过滤,自己想要什么样的帧,可以设置自己的过滤器,接收相关的帧信息。如果两个节点同时发送怎么办?这个不用我们担心,CAN控制器会自己仲裁,让高优先级的帧先发。
         然后我们可以了解一下stm32的CAN控制器。

         如上图所示,stm32有两个can控制器,can1(主),和can2(从),其中过滤器的设置是通过can1来设置,其他工作模式,波特率等,可以各自设置。每个控制器有三个发送邮箱,两个fifo,每个fifo有三个接收邮箱。


         发送:选择一个空的发送邮箱,把帧信息写到该发送邮箱的寄存器里,请求发送,控制器就会根据标识符的优先级把帧先后发送出去。
         接收:如果接收到的帧的标识符能过过滤表的一系列过滤,该帧信息就会保存在fifo接收邮箱的寄存器里。
         过滤器:stm32f407共有28组过滤器,每组过滤器可以设置关联到fifo0或者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
根据以上数据,有
(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.  编写相应服务程序。



沙发
焚琴煮鹤|  楼主 | 2016-9-10 21:52 | 只看该作者

电路请参见本博客:小工具之——CAN收发器




程序:


  • /************************************  
  •     标题:操作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  
  •    



使用特权

评论回复
板凳
焚琴煮鹤|  楼主 | 2016-9-10 21:53 | 只看该作者
  •    /*  
  •   过滤器组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;   
  • }  
  •   


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

63

主题

106

帖子

3

粉丝