STM32F767IG平台的CAN1/CAN2/CAN3的驱动调试(寄存器版)

        一开始是基于STM32Cube来生成的驱动进行调试,但是直接生成的项目并不能用,到网上去搜索发现资料不仅少的可怜,而且使用的库不一样,仅仅得到的信息就是使用CAN2前必须使能CAN1的时钟,然而我使能后依然无法使用。尝试无果之后决定采用寄存器来从底层开始弄。

        寄存器基础代码使用正点原子的例子程序。该例子程序使用的是CAN1。

       重点是:多看手册,看手册,手册!!!!!!!!

       CAN配置过程中的要点:

       1、硬件线路,硬件线路必须接对,这是最基本的,硬件线路接不对,软件肯定是跑不通的。

      2、复用CAN,复用CAN的地方CAN1,CAN2是AF9,CAN3是AF11,这个是查手册,中文版中没有CAN3,要看英文版的。在寄存器RCC_APB1RSTR中有说明。

       3、时钟配置,CAN1和CAN3是独立使能自己就行,CAN2使能前必须先使能CAN1,这里的必须是项目中只要在CAN2之前使能过CAN1就可以了,不必分要把使能代码也放在一起。       比如例子工程中的初始化顺序是CAN1 CAN2 CAN3,那么CAN2在初始化时就不再需要使能CAN1了。

     4、配置CAN属性和波特率,这部分很正常,没出现问题。

     5、配置过滤器,STM32Cube创建的项目里没有这一项,导致了怎么调都调不通,也可能是我不太会用这个工具。

          配置这个要分为CAN1&CAN2一组,CAN3一组

          先来看CAN1&CAN2这一组,CAN1也好CAN2也罢,必须要配置CAN1的过滤器才行,配置CAN2是没用的,总共有28个过滤器,CAN1是从0-13   can2从14-27
         再来看CAN3这一组,CAN3是独立的一个CAN通道,所有东西都是自己的,与CAN1和CAN2不关联。它的过滤器是从0开始,总共14个。

         具体的配置过程看各路CAN的配置代码。

     6、配置中断,我是将CAN1和CAN2配置给了FIFO0,这个的FIFO0和前面的过滤器挂在的FIFO要一直,过滤器挂在在FIFO0中断就必须配置在FIFO0,否则是收不到数据的。

 

//------------------------------------------  代码展示 -------------------------------------------------

        CAN1配置代码:

/*
说明:CAN1初始化
输入:tsjw:重新同步跳跃时间单元.范围:1~3;
      tbs2:时间段2的时间单元.范围:1~8;
      tbs1:时间段1的时间单元.范围:1~16;
      brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1
      注意以上参数任何一个都不能设为0,否则会乱.
      波特率=Fpclk1/((tbs1+tbs2+1)*brp);
      mode:0,普通模式;1,回环模式;
      Fpclk1的时钟在初始化的时候设置为54M,如果设置CAN1_Mode_Init(1,7,10,6,1);
      则波特率为:54M/((7+10+1)*6)=500Kbps
返回:0,初始化OK;
     其他,初始化失败;
*/
u8 CAN1_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
	u16 i=0;
 	if(tsjw==0||tbs2==0||tbs1==0||brp==0)return 1;
	tsjw-=1;//先减去1.再用于设置
	tbs2-=1;
	tbs1-=1;
	brp-=1;

	RCC->AHB1ENR|=1<<0;  	//使能PORTA口时钟 
	GPIO_Set(GPIOA,PIN11|PIN12,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PA11,PA12,复用功能,上拉输出
 	GPIO_AF_Set(GPIOA,11,9);//PA11,AF9
	GPIO_AF_Set(GPIOA,12,9);//PA12,AF9 	   
 
	RCC->APB1ENR|=1<<25;//使能CAN1时钟 CAN1使用的是APB1的时钟(max:48M)
	CAN1->MCR=0x0000;	//退出睡眠模式(同时设置所有位为0)
	CAN1->MCR|=1<<0;		//请求CAN进入初始化模式
	while((CAN1->MSR&1<<0)==0)
	{
		i++;
		if(i>100)return 2;//进入初始化模式失败
	}
	CAN1->MCR|=0<<7;		//非时间触发通信模式
	CAN1->MCR|=0<<6;		//软件自动离线管理
	CAN1->MCR|=0<<5;		//睡眠模式通过软件唤醒(清除CAN1->MCR的SLEEP位)
	CAN1->MCR|=1<<4;		//禁止报文自动传送
	CAN1->MCR|=0<<3;		//报文不锁定,新的覆盖旧的
	CAN1->MCR|=0<<2;		//优先级由报文标识符决定
	CAN1->BTR=0x00000000;	//清除原来的设置.
	CAN1->BTR|=mode<<30;	//模式设置 0,普通模式;1,回环模式;
	CAN1->BTR|=tsjw<<24; 	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位
	CAN1->BTR|=tbs2<<20; 	//Tbs2=tbs2+1个时间单位
	CAN1->BTR|=tbs1<<16;	//Tbs1=tbs1+1个时间单位
	CAN1->BTR|=brp<<0;  	//分频系数(Fdiv)为brp+1
							//波特率:Fpclk1/((Tbs1+Tbs2+1)*Fdiv)
	CAN1->MCR&=~(1<<0);		//请求CAN退出初始化模式
	while((CAN1->MSR&1<<0)==1)
	{
		i++;
		if(i>0XFFF0)return 3;//退出初始化模式失败
	}
	//过滤器初始化
	CAN1->FMR|=1<<0;		//过滤器组工作在初始化模式
	CAN1->FA1R&=~(1<<0);	//过滤器0不激活
	CAN1->FS1R|=1<<0; 		//过滤器位宽为32位.
	CAN1->FM1R|=0<<0;		//过滤器0工作在标识符屏蔽位模式
	CAN1->FFA1R|=0<<0;		//过滤器0关联到FIFO0
	CAN1->sFilterRegister[0].FR1=0X00000000;//32位ID
	CAN1->sFilterRegister[0].FR2=0X00000000;//32位MASK
	CAN1->FA1R|=1<<0;		//激活过滤器0
	CAN1->FMR&=0<<0;		//过滤器组进入正常模式

 	//使用中断接收
	CAN1->IER|=1<<1;		//FIFO0消息挂号中断允许.	    
	MY_NVIC_Init(1,0,CAN1_RX0_IRQn,2);//组2

	return 0;
}   

CAN2配置代码:

/*
说明:CAN2初始化
输入:tsjw:重新同步跳跃时间单元.范围:1~3;
      tbs2:时间段2的时间单元.范围:1~8;
      tbs1:时间段1的时间单元.范围:1~16;
      brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1
      注意以上参数任何一个都不能设为0,否则会乱.
      波特率=Fpclk1/((tbs1+tbs2+1)*brp);
      mode:0,普通模式;1,回环模式;
      Fpclk1的时钟在初始化的时候设置为54M,如果设置CAN1_Mode_Init(1,7,10,6,1);
      则波特率为:54M/((7+10+1)*6)=500Kbps
返回:0,初始化OK;
     其他,初始化失败;
*/
u8 CAN2_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
	u16 i=0;
 	if(tsjw==0||tbs2==0||tbs1==0||brp==0)return 1;
	tsjw-=1;//先减去1.再用于设置
	tbs2-=1;
	tbs1-=1;
	brp-=1;

    // 使能PORTB口时钟 
	RCC->AHB1ENR|=1<<1;  	
    
    // 初始化GPIOB 5  GPIOB 13时钟
	GPIO_Set(GPIOB,PIN13|PIN5,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);
    
    // 复用CAN2 即AF9
 	GPIO_AF_Set(GPIOB,5,9);//PB5,AF9
	GPIO_AF_Set(GPIOB,13,9);//PB13,AF9 	   
 
    // 使能CAN1时钟  使能CAN2时钟  用CAN2前必须要使能CAN1
	RCC->APB1ENR|=1<<25;//使能CAN1时钟 CAN1使用的是APB1的时钟(max:48M)
    RCC->APB1ENR|=1<<26;//使能CAN2时钟 CAN2使用的是APB1的时钟(max:48M)
    
    // 退出睡眠模式(同时设置所有位为0)
	CAN2->MCR=0x0000;	
    
    // 请求CAN进入初始化模式
	CAN2->MCR|=1<<0;		
	while((CAN2->MSR&1<<0)==0)
	{
		i++;
		if(i>100)return 2;//进入初始化模式失败
	}
    
    // 配置CAN2
	CAN2->MCR|=0<<7;		//非时间触发通信模式
	CAN2->MCR|=0<<6;		//软件自动离线管理
	CAN2->MCR|=0<<5;		//睡眠模式通过软件唤醒(清除CAN2->MCR的SLEEP位)
	CAN2->MCR|=1<<4;		//禁止报文自动传送
	CAN2->MCR|=0<<3;		//报文不锁定,新的覆盖旧的
	CAN2->MCR|=0<<2;		//优先级由报文标识符决定
    
    // 配置CAN2的模式和波特率
	CAN2->BTR=0x00000000;	//清除原来的设置.
	CAN2->BTR|=mode<<30;	//模式设置 0,普通模式;1,回环模式;
	CAN2->BTR|=tsjw<<24; 	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位
	CAN2->BTR|=tbs2<<20; 	//Tbs2=tbs2+1个时间单位
	CAN2->BTR|=tbs1<<16;	//Tbs1=tbs1+1个时间单位
	CAN2->BTR|=brp<<0;  	//分频系数(Fdiv)为brp+1
							//波特率:Fpclk1/((Tbs1+Tbs2+1)*Fdiv)
    
    // 配置完成 退出初始化模式
	CAN2->MCR&=~(1<<0);		//请求CAN退出初始化模式
	while((CAN2->MSR&1<<0)==1)
	{
		i++;
		if(i>0XFFF0)return 3;//退出初始化模式失败
	}
    
    // -------------  配置过滤器  ------------------
    // CAN1也好CAN2也罢,必须要配置CAN1的过滤器才行,配置CAN2是没用的
    // 总共有28个过滤器,CAN1是从0-13   can2从14-27
    // 开始过滤器配置模式
    
    // 1  过滤器组工作在初始化模式
    CAN1->FMR |= 1; 

    // 2  FMR寄存器的 【13~8】位:CAN 起始存储区 (CAN start bank) 这些位将由软件置 1 和清零。它们为处于 1 到 27 范围内的 CAN 接口(从模式)定义起始存 储区
    //                     13~8位
    //‭111111111111111111 000000 11111111‬
    CAN1->FMR &= 0xffffc0ff;// 将FMR的8-13位全部置0,具体为什么不太清楚  和hal库里的操作时一直的
    CAN1->FMR |= (14<<8); // 这里左移8位也不太清除  和hal库里的操作时一直的

    // 3  FM1R的28个位表示28个过滤器组,0~13是CAN1的  14~27是CAN2的
    //    0: 处于标识符屏蔽模式。 1:处于标识符列表模式
    //    0<<14 说明过滤器组14的寄存器工作在标识符屏蔽模式  
    CAN1->FM1R |= (0<<14);//

    // 4  配置32位过滤器  28个位来表示  如果不打算过滤,这个配不配或者不管配成啥都能收到报文
    //    bit  为0:双 16 位尺度配置      bit为1:单 32 位尺度配置
    CAN1->FS1R |= (1<<14);//过滤器组14为单个32位寄存器,用于扩展标识符

    // 6  14~27过滤器      0~13过滤器        一次全部赋值
    //    ‭11111111111111  00000000000000‬     0表示给fifo0   1表示给fifo1
    //    CAN1->FFA1R = 0x0fffc000;//0~13号过滤器组关联到fifo0,14~27号过滤器组关联到fifo1
    // test
    CAN1->FFA1R|=0<<14;		//过滤器14关联到FIFO0  0<<14  左边的1表示的是FIFO0  14表示的是14号过滤器

    // 7  先禁用14号过滤器  禁用后对其进行配置
    //    0:不激活   1:激活过滤器
    CAN1->FA1R &= ~(1<<14);//禁用过滤器组14

    // 8  配置过滤寄存器的值,sFilterRegister是个28元素的数组,配置的是几号,这里就是几
    // 0x00000000 表示任何数都无所谓,也就是不过滤
    CAN1->sFilterRegister[14].FR1 &= 0x00000000;
    CAN1->sFilterRegister[14].FR2 &= 0x00000000;

    // 9  配置完以后激活它
    CAN1->FA1R |= (1<<14);
    
    // 10  过滤器组正常工作
    CAN1->FMR &= ~1; 

// 配置接收中断
 	// 使用中断接收   FIFO0就要用CAN2_RX0_IRQn   FIFO1就要用CAN2_RX1_IRQn
    // IER寄存器的bit1 FMPIE0:FIFO 消息挂起中断使能 (FIFO message pending interrupt enable) 
    //                0:不产生中断。     1:产生中断。
    // IER寄存器的bit4 FMPIE1:FIFO 消息挂起中断使能 (FIFO message pending interrupt enable) 
    //                0:不产生中断。     1:产生中断。
	CAN2->IER|=1<<1;
    
    // CAN2_RX1_IRQn应该是对应于FIFO1的中断
	MY_NVIC_Init(1,0,CAN2_RX0_IRQn,2);//组2 
	return 0;
}  

 

CAN3配置代码:

/*
说明:CAN3初始化
输入:tsjw:重新同步跳跃时间单元.范围:1~3;
      tbs2:时间段2的时间单元.范围:1~8;
      tbs1:时间段1的时间单元.范围:1~16;
      brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1
      注意以上参数任何一个都不能设为0,否则会乱.
      波特率=Fpclk1/((tbs1+tbs2+1)*brp);
      mode:0,普通模式;1,回环模式;
      Fpclk1的时钟在初始化的时候设置为54M,如果设置CAN1_Mode_Init(1,7,10,6,1);
      则波特率为:54M/((7+10+1)*6)=500Kbps
返回:0,初始化OK;
     其他,初始化失败;
*/
u8 CAN3_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
	u16 i=0;
 	if(tsjw==0||tbs2==0||tbs1==0||brp==0)return 1;
	tsjw-=1;//先减去1.再用于设置
	tbs2-=1;
	tbs1-=1;
	brp-=1;

	RCC->AHB1ENR|=1<<0;  	//使能PORTA口时钟 
	GPIO_Set(GPIOA,PIN8|PIN15,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PA11,PA12,复用功能,上拉输出
 	GPIO_AF_Set(GPIOA,8,11);//PA11,AF11
	GPIO_AF_Set(GPIOA,15,11);//PA12,AF11 	   
 
    // 使能CAN3时钟,不必须先使能CAN1和CAN2时钟
    RCC->APB1ENR|=1<<13;//使能CAN3时钟 CAN2使用的是APB1的时钟(max:48M)
    
	CAN3->MCR=0x0000;	//退出睡眠模式(同时设置所有位为0)
	CAN3->MCR|=1<<0;		//请求CAN进入初始化模式
	while((CAN3->MSR&1<<0)==0)
	{
		i++;
		if(i>100)return 2;//进入初始化模式失败
	}
	CAN3->MCR|=0<<7;		//非时间触发通信模式
	CAN3->MCR|=0<<6;		//软件自动离线管理
	CAN3->MCR|=0<<5;		//睡眠模式通过软件唤醒(清除CAN3->MCR的SLEEP位)
	CAN3->MCR|=1<<4;		//禁止报文自动传送
	CAN3->MCR|=0<<3;		//报文不锁定,新的覆盖旧的
	CAN3->MCR|=0<<2;		//优先级由报文标识符决定
	CAN3->BTR=0x00000000;	//清除原来的设置.
	CAN3->BTR|=mode<<30;	//模式设置 0,普通模式;1,回环模式;
	CAN3->BTR|=tsjw<<24; 	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位
	CAN3->BTR|=tbs2<<20; 	//Tbs2=tbs2+1个时间单位
	CAN3->BTR|=tbs1<<16;	//Tbs1=tbs1+1个时间单位
	CAN3->BTR|=brp<<0;  	//分频系数(Fdiv)为brp+1
							//波特率:Fpclk1/((Tbs1+Tbs2+1)*Fdiv)
	CAN3->MCR&=~(1<<0);		//请求CAN退出初始化模式
	while((CAN3->MSR&1<<0)==1)
	{
		i++;
		if(i>0XFFF0)return 3;//退出初始化模式失败
	}
	//过滤器初始化
	CAN3->FMR|=1<<0;		//过滤器组工作在初始化模式
	CAN3->FA1R&=~(1<<0);	//过滤器0不激活
	CAN3->FS1R|=1<<0; 		//过滤器位宽为32位.
	CAN3->FM1R|=0<<0;		//过滤器0工作在标识符屏蔽位模式
	CAN3->FFA1R|=1<<0;		//过滤器0关联到FIFO1
	CAN3->sFilterRegister[0].FR1=0X00000000;    //32位ID
	CAN3->sFilterRegister[0].FR2=0X00000000;    //32位MASK
	CAN3->FA1R|=1<<0;		//激活过滤器0
	CAN3->FMR&=0<<0;		//过滤器组进入正常模式

 	//使用中断接收
	CAN3->IER|=1<<4;		//FIFO1消息挂号中断允许.	    
	MY_NVIC_Init(1,0,CAN3_RX1_IRQn,2);//组2

	return 0;
}   

中断接收函数代码


/*
说明:接收CAN数据
输入:CAN_TypeDef* can  CAN实例 CAN1 CAN2 or CAN3
      u8 fifox  邮箱编号  0 or 1
返回:CanFrame_t结构体数据
*/
CanFrame_t CAN_RecvFrame(CAN_TypeDef* can, u8 fifox)
{
    CanFrame_t frame;
    memset(&frame,0x00,sizeof(CanFrame_t));
    //
	frame.IDE=can->sFIFOMailBox[fifox].RIR&0x04;//得到标识符选择位的值  
 	if(frame.IDE==0)//标准标识符
	{
		frame.ID=can->sFIFOMailBox[fifox].RIR>>21;
	}else	   //扩展标识符
	{
		frame.ID=can->sFIFOMailBox[fifox].RIR>>3;
	}
    //
	frame.RTR=can->sFIFOMailBox[fifox].RIR&0x02;	//得到远程发送请求值.
	frame.dataLen=can->sFIFOMailBox[fifox].RDTR&0x0F;//得到DLC
    
	//接收数据
	frame.data[0]=can->sFIFOMailBox[fifox].RDLR&0XFF;
	frame.data[1]=(can->sFIFOMailBox[fifox].RDLR>>8)&0XFF;
	frame.data[2]=(can->sFIFOMailBox[fifox].RDLR>>16)&0XFF;
	frame.data[3]=(can->sFIFOMailBox[fifox].RDLR>>24)&0XFF;    
	frame.data[4]=can->sFIFOMailBox[fifox].RDHR&0XFF;
	frame.data[5]=(can->sFIFOMailBox[fifox].RDHR>>8)&0XFF;
	frame.data[6]=(can->sFIFOMailBox[fifox].RDHR>>16)&0XFF;
	frame.data[7]=(can->sFIFOMailBox[fifox].RDHR>>24)&0XFF;    
  	if(fifox==0)can->RF0R|=0X20;//释放FIFO0邮箱
	else if(fifox==1)can->RF1R|=0X20;//释放FIFO1邮箱	 
    return frame;
}

// CAN1中断服务函数			    
void CAN1_RX0_IRQHandler(void)
{
	CanFrame_t frame;    
 	frame = CAN_RecvFrame(CAN1,0);
    printf("\n----- CAN1 Recved ---------\n");
    printf("id:%04x\t",frame.ID);
    printf("ide:%d\t",frame.IDE);
    printf("rtr:%d\t",frame.RTR);
    printf("len:%d\t",frame.dataLen);
    printf("rxbuf[%02x ",frame.data[0]);
    printf("%02x ",frame.data[1]);
    printf("%02x ",frame.data[2]);
    printf("%02x ",frame.data[3]);
    printf("%02x ",frame.data[4]);
    printf("%02x ",frame.data[5]);
    printf("%02x ",frame.data[6]);
    printf("%02x]\n",frame.data[7]);
}
// CAN2中断服务函数			    
void CAN2_RX0_IRQHandler(void)
{
	CanFrame_t frame;    
 	frame = CAN_RecvFrame(CAN2,0);
    printf("\n----- CAN2 Recved ---------\n");
    printf("id:%04x\t",frame.ID);
    printf("ide:%d\t",frame.IDE);
    printf("rtr:%d\t",frame.RTR);
    printf("len:%d\t",frame.dataLen);
    printf("rxbuf[%02x ",frame.data[0]);
    printf("%02x ",frame.data[1]);
    printf("%02x ",frame.data[2]);
    printf("%02x ",frame.data[3]);
    printf("%02x ",frame.data[4]);
    printf("%02x ",frame.data[5]);
    printf("%02x ",frame.data[6]);
    printf("%02x]\n",frame.data[7]);
}
// CAN3中断服务函数			    
void CAN3_RX1_IRQHandler(void)
{
	CanFrame_t frame;    
 	frame = CAN_RecvFrame(CAN3,1);
    printf("\n----- CAN3 Recved ---------\n");
    printf("id:%04x\t",frame.ID);
    printf("ide:%d\t",frame.IDE);
    printf("rtr:%d\t",frame.RTR);
    printf("len:%d\t",frame.dataLen);
    printf("rxbuf[%02x ",frame.data[0]);
    printf("%02x ",frame.data[1]);
    printf("%02x ",frame.data[2]);
    printf("%02x ",frame.data[3]);
    printf("%02x ",frame.data[4]);
    printf("%02x ",frame.data[5]);
    printf("%02x ",frame.data[6]);
    printf("%02x]\n",frame.data[7]);
}

发送函数代码:


/*
说明:获得发送状态
输入:CAN_TypeDef* can  CAN1/CAN2/CAN3
      mbox:邮箱编号
返回:0挂起;  0X05发送失败;  0X07发送成功.
*/
u8 CAN_SendStaus(CAN_TypeDef* can, u8 mbox)
{	
	u8 sta=0;					    
	switch (mbox)
	{
		case 0: 
			sta |= can->TSR&(1<<0);			//RQCP0
			sta |= can->TSR&(1<<1);			//TXOK0
			sta |=((can->TSR&(1<<26))>>24);	//TME0
			break;
		case 1: 
			sta |= can->TSR&(1<<8)>>8;		//RQCP1
			sta |= can->TSR&(1<<9)>>8;		//TXOK1
			sta |=((can->TSR&(1<<27))>>25);	//TME1	   
			break;
		case 2: 
			sta |= can->TSR&(1<<16)>>16;	//RQCP2
			sta |= can->TSR&(1<<17)>>16;	//TXOK2
			sta |=((can->TSR&(1<<28))>>26);	//TME2
			break;
		default:
            printf("mbox[%d]default!\n",mbox);
			sta=0X05;//邮箱号不对,肯定失败.
		break;
	}
	return sta;
} 

/*
说明:发送CAN数据帧
输入:要发送的CAN数据帧
返回:u8 发送成功返回0  失败返回1  0XFF无空邮箱,无法发送
*/
u8 CAN_SendFrame(CAN_TypeDef* can, CanFrame_t frame)
{	   
    u16 i = 0;
	u8 mbox;	
    //
	if(can->TSR&(1<<26))mbox=0;			//邮箱0为空
	else if(can->TSR&(1<<27))mbox=1;	//邮箱1为空
	else if(can->TSR&(1<<28))mbox=2;	//邮箱2为空
	else return 0XFF;					//无空邮箱,无法发送 
    //
	can->sTxMailBox[mbox].TIR=0;		//清除之前的设置
	/*
	if(frame.IDE==0)	//标准帧
	{
		frame.ID&=0x7ff;//取低11位stdid
		frame.ID<<=21;		  
	}else		//扩展帧
	{
		frame.ID&=0X1FFFFFFF;//取低32位extid
		frame.ID<<=3;									   
	}*/
    frame.ID&=0X1FFFFFFF;//取低32位extid
	can->sTxMailBox[mbox].TIR|=frame.ID<<3;		 
	can->sTxMailBox[mbox].TIR|=frame.IDE;	 // 已经计算过移位了,这里不需要再移动
	can->sTxMailBox[mbox].TIR|=frame.RTR;	 // 已经计算过移位了,这里不需要再移动
	frame.dataLen &= 0X0F;//得到低四位
	can->sTxMailBox[mbox].TDTR&=~(0X0000000F);
	can->sTxMailBox[mbox].TDTR|=frame.dataLen;		   //设置DLC.
	//待发送数据存入邮箱.
	can->sTxMailBox[mbox].TDHR=(((u32)frame.data[7]<<24)|
								((u32)frame.data[6]<<16)|
 								((u32)frame.data[5]<<8)|
								((u32)frame.data[4]));
	can->sTxMailBox[mbox].TDLR=(((u32)frame.data[3]<<24)|
								((u32)frame.data[2]<<16)|
 								((u32)frame.data[1]<<8)|
								((u32)frame.data[0]));
	can->sTxMailBox[mbox].TIR|=1<<0; //请求发送邮箱数据
    //
	while((CAN_SendStaus(can, mbox)!=0X07)&&(i<0XFFF))i++;//等待发送结束
	if(i>=0XFFF)return 1;							//发送失败
	return 0;										//发送成功
}




/*
说明:发送CAN数据帧的测试函数
输入:void
返回:u8 发送成功返回0  失败返回1  0XFF无空邮箱,无法发送
*/
u8 CAN1_SendFrameTest(void)
{
	CanFrame_t frame;    
    memset(&frame,0x00,sizeof(CanFrame_t));
    frame.ID = 0x181056F4;
    frame.IDE = CAN_ID_EXT;  // 扩展帧是1
    frame.RTR = CAN_RTR_DATA;  // 数据帧是0
    frame.dataLen = 8;
    frame.data[0] = 0x01;
    frame.data[1] = 0x02;
    frame.data[2] = 0x03;
    frame.data[3] = 0x04;
    frame.data[4] = 0x05;
    frame.data[5] = 0x06;
    frame.data[6] = 0x07;
    frame.data[7] = 0x08;
    return CAN_SendFrame(CAN1,frame);
}


/*
说明:发送CAN数据帧的测试函数
输入:void
返回:u8 发送成功返回0  失败返回1  0XFF无空邮箱,无法发送
*/
u8 CAN2_SendFrameTest(void)
{
	CanFrame_t frame;    
    memset(&frame,0x00,sizeof(CanFrame_t));
    frame.ID = 0x181056F4;
    frame.IDE = CAN_ID_EXT;  // 扩展帧是1
    frame.RTR = CAN_RTR_DATA;  // 数据帧是0
    frame.dataLen = 8;
    frame.data[0] = 0x01;
    frame.data[1] = 0x02;
    frame.data[2] = 0x03;
    frame.data[3] = 0x04;
    frame.data[4] = 0x05;
    frame.data[5] = 0x06;
    frame.data[6] = 0x07;
    frame.data[7] = 0x08;
    return CAN_SendFrame(CAN2,frame);
}

/*
说明:发送CAN数据帧的测试函数
输入:void
返回:u8 发送成功返回0  失败返回1  0XFF无空邮箱,无法发送
*/
u8 CAN3_SendFrameTest(void)
{
	CanFrame_t frame;    
    memset(&frame,0x00,sizeof(CanFrame_t));
    frame.ID = 0x181056F4;
    frame.IDE = CAN_ID_EXT;  // 扩展帧是1
    frame.RTR = CAN_RTR_DATA;  // 数据帧是0
    frame.dataLen = 8;
    frame.data[0] = 0x01;
    frame.data[1] = 0x02;
    frame.data[2] = 0x03;
    frame.data[3] = 0x04;
    frame.data[4] = 0x05;
    frame.data[5] = 0x06;
    frame.data[6] = 0x07;
    frame.data[7] = 0x08;
    return CAN_SendFrame(CAN3,frame);
}

至此三路CAN全部配置完成,下面是串口打印的效果

CAN1 Init OK 
CAN2 Init OK  
CAN3 Init OK  

Can1 send test 
Can1 send OK    

----- CAN1 Recved ---------
id:180156f4	ide:4	rtr:0	len:8	rxbuf[11 22 33 44 55 66 77 88]
   
initCanRes2 = 0 
Can2 send test 
Can2 send OK    

----- CAN2 Recved ---------
id:180156f4	ide:4	rtr:0	len:8	rxbuf[11 22 33 44 55 66 77 88]

Can3 send test 
Can3 send OK    

----- CAN3 Recved ---------
id:180156f4	ide:4	rtr:0	len:8	rxbuf[11 22 33 44 55 66 77 88]

注:1、由于板子上只有一个CAN芯片,每次测试时都要将需要测试的这一路CAN的引脚用杜邦线连接到CAN芯片上。

       2、测试CAN2的时候,必须要先连接好线路之后再启动,否则CAN2初始化会失败。

完整项目下载地址https://download.csdn.net/download/captainusop/11777819

 

你可能感兴趣的:(单片机,驱动)