Bootstrap

STM32 CAN模块问题:1、CAN收发器断电后重新上电,CAN模块死机(离线)现象;2、过滤器配置完之后没有过滤效果

做了一个项目,使用STM32F103VBT6来做GPS终端,在调试过程中发现两个问题,记录下来以便今后参考!

  • 问题一:
    给电路板上电,CAN模块正常收发,然后断电,此时因为有电池原因CPU不断电,正常工作。但硬件上CAN模块断电,此硬件设计没问题,就是这种方式。再次给电路板上电,CAN模块不能收发,但此时CPU正常,量CAN收发器电压正常!

  • 解决方法:

     百度了一下,发现有不少人遇到类似问题,他们大多是因为开启了错误中断,在CANH和CANL短接或者其他原因造成CAN模块收发有误,在错误帧没有得到处理的时候CAN模块会因为错误中断而进入死循环。
     解决链接:https://blog.csdn.net/u014515202/article/details/54135882
    

我把错误中断使能禁止 CAN_ITConfig(CAN1,CAN_IT_ERR,DISABLE);(库函数)发现还是不行,,后来查阅STM32数据手册发现就算用户不去禁止,他默认也是关闭的
在这里插入图片描述之前的中断错误被排除了,查看数据手册中有这么一段
在这里插入图片描述当CAN收发器断电后,STM32 CAN模块会进行发送错误计数,当TEC大于255时CAN模块进入离线状态,此时并不用产生错误中断就可以让CAN模块停止发送和接收。
后来看到一篇专门讲出错管理的一篇文章:https://blog.csdn.net/flydream0/article/details/8161418
于是修改了程序

void CAN_Mode_Init(void)
{ 
	GPIO_InitTypeDef 		GPIO_InitStructure; 
	CAN_InitTypeDef        	CAN_InitStructure;
	NVIC_InitTypeDef  		NVIC_InitStructure;


	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽
	GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化IO

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	//上拉输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化IO
	

	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	//CAN单元设置
	CAN_InitStructure.CAN_TTCM=DISABLE;			//非时间触发通信模式  
	CAN_InitStructure.CAN_ABOM=ENABLE;			//软件自动离线管理	 
	CAN_InitStructure.CAN_AWUM=DISABLE;			//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
	CAN_InitStructure.CAN_NART=DISABLE;			//不使能非自动重传模式
	CAN_InitStructure.CAN_RFLM=DISABLE;		 	//报文不锁定,新的覆盖旧的  
	CAN_InitStructure.CAN_TXFP=DISABLE;			//优先级由报文标识符决定 
	CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;//模式设置: CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
	//设置波特率250Kbps
	CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;		//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq	 CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
	CAN_InitStructure.CAN_BS1=CAN_BS1_8tq; 		//Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
	CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;		//Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~	CAN_BS2_8tq
	CAN_InitStructure.CAN_Prescaler=8;        	//分频系数(Fdiv)为brp+1	
	CAN_Init(CAN1, &CAN_InitStructure);        	//初始化CAN1 
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);								//接收中断允许.		    
	CAN_ITConfig(CAN1,CAN_IT_ERR,DISABLE);								//禁止错误中断

}

CAN_InitStructure.CAN_ABOM=ENABLE; //软件自动离线管理
CAN_ITConfig(CAN1,CAN_IT_ERR,DISABLE); //禁止错误中断
修改以上两个语句,问题得到解决。

- 问题二:
之前学程序时候参考了一份非常有价值的文章
1、https://blog.csdn.net/flydream0/article/details/8148791
2、https://blog.csdn.net/bonson2004/article/details/68942442
程序编写完之后验证时发现过滤器根本不起作用,又是一个坑,以后写程序得先看一遍官方数据手册是很有必要的!
在这里插入图片描述发现STM32的CAN过滤器在配置时必须要进入初始化,才能对其进行配置。

/***********************************************************
函数名称:CANFilterConfig_List_Extend(u8 FGrop,u32 Ext_Id1,u32 Ext_Id2)
函数功能:设置过滤器与屏蔽寄存器  列表模式
入口参数:FGrop 过滤器组,Ext_Id1、Ext_Id2 需要过滤的扩展ID
出口参数:无
备    注:32位列表模式下,屏蔽寄存器也被当作标识符寄存器用,即两个寄存器各作为过滤值用
***********************************************************/ 	
void CANFilterConfig_List_Extend(u8 FGrop,u32 Ext_Id1,u32 Ext_Id2)
{  
	 CAN_FilterInitTypeDef	CAN_FilterInitStructure;
	 
	 CAN1->FMR |= 1;            //过滤器组工作在初始化模式
	 CAN_FilterInitStructure.CAN_FilterNumber = FGrop;				 //设置过滤器组0,范围为0~13
	 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;	 //设置过滤器组0为标识符列表模式
	 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //设置过滤器组0位宽为32位
	  
	 //设置标识符寄存器
	 CAN_FilterInitStructure.CAN_FilterIdHigh=((Ext_Id1<<3)>>16)&0xffff ;		   //设置标识符寄存器高字节
	 CAN_FilterInitStructure.CAN_FilterIdLow=((Ext_Id1<<3)&0xffff)|CAN_Id_Extended;//设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
	  
	 //设置屏蔽寄存器,这里当标识符寄存器用
	 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((Ext_Id2<<3)>>16)&0xffff;			//设置屏蔽寄存器高字节
	 CAN_FilterInitStructure.CAN_FilterMaskIdLow=((Ext_Id2<<3)&0xffff)|CAN_Id_Extended; //设置屏蔽寄存器低字节
	  
	 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此过滤器组关联到接收FIFO0
	 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;		 //激活此过滤器组
	 CAN_FilterInit(&CAN_FilterInitStructure);					 //设置过滤器
	 
     CAN1->FMR &=~1;            //过滤器组正常工作
 }

重要的两句:CAN1->FMR |= 1; //过滤器组工作在初始化模式
CAN1->FMR &=~1; //过滤器组正常工作
实测可以进行过滤|

;