//配置过滤器
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
CAN的过滤器是硬件设置接受指定地址数据用的。
假如说1号机设置FilterID为0x01010101,FilterMask设置为0xFFFFFFFF,那么他只能接受CAN通讯数据ID为0x01010101的数据,其他的硬件就会被屏蔽掉。如果FilterMask设置为0,那么就是所有ID的数据都可以接受。
FilterID为过滤的地址,FilterMask与FilterID对应每一位表示是否需要匹配当前位。还是上面的例子,mask设置为全1,表示所有为必须匹配,也就是只接受和FilterID一样的数据;mask设置为全0,就是任何一位都不需要匹配;mask设置为1,就是最低位匹配即可。就是这么个道理
CAN总线传送到数据是基于消息而不是地址的,每个消息用不同的编号表达(2.0A用11位、2.0B用29位)。在CAN上进行简单传送而自定义传送协议时,要把所有需要传送的命令列出,然后根据传送的紧急程度(优先级)从高到低进行排序,然后把最高优先级的设定一个最低的编号、以此类推…最低优先级的设定最高的编号。因为CAN物理上是不分主从,所以当有几个站点同时发送而发生碰撞时,编号最低的将优先传送。
从总线上接收消息:每个站点可能只对所有协议中的几个消息感兴趣,CAN初始化时,在过滤器中设置本站点需要接收的消息编号,这样一旦总线上有需要的消息将会自动接收,并产生中断,通知CPU收到新消息,CPU在中断程序中接收、处理。
发送消息到总线上:CAN初始化时设置本站点将来需要发送的消息编号,当运行过程中需要发送消息时,填入相关数据,设置相关消息对象发送。
CAN控制器内部一般设有32个消息对象,分成2组,分别各用一组寄存器来操作。一般一组用来接收过滤,另一组用来发送。
当将FilterMode 设置为列表模式的时候,屏蔽寄存器FiterMask也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符FilterId相同, 所以列表模式下是过滤特定的ID模式,列表的方式受到列表容量大小的限制,bxCAN的一个过滤器若工作在列表模式下,scale为32时,每个过滤器的列表只能写入两个报文ID,若scale为16时,每个过滤器的列表最多可写入4个CAN ID。
如果将FilterMode设置为CAN_FILTERMODE_IDMASK模式,FilterMaskId设置为0时,表示不过滤,可以接收任意的canid数据,
当filterMaskId不为0时,则表示过滤 对应MaskID 为1的bit必须与FilterID中的bit位相同的canid才能接收过来。
比如filterid=0x10101010, maskid=0x0000ffff, 则只有id=0x xxxx 1010的数据才能接收,xxxx可以不用与filterid的高2字节相同,可以任意。
STM32之CAN通讯接收过滤器过滤分析
再谈STM32的CAN过滤器-bxCAN的过滤器的4种工作模式以及使用方法总结
1、在工程文件夹下,新建CAN目录,copy can.h can.c到该目录。
2、keil 项目栏中增加CAN目录,把can.c加入到 CAN目录
3、编译报错
报错
…\OBJ\Template.axf: Error: L6218E: Undefined symbol CAN_FilterInit (referred from can.o).
…
解决:加入外设库文件
keil 项目栏FWLIB目录中加入**\FWLIB\STM32F4xx_StdPeriph_Driver\src、stm32f4xx_can.c
感谢:
stm32OBJ\template.axf: Error: L6218E: Undefined symbol
//从卡使用标准帧(TxMessage.IDE=CAN_Id_Standard)发送,ExtId无效,目标(主卡)ID为 TargetAddr,从卡本机ID为SourceAddr
u8 E6432_CAN1_Send(u8 TargetAddr,u8 SourceAddr, u8* msg,u8 len)
{
u8 mbox;
u16 i=0;
CanTxMsg TxMessage;
TxMessage.StdId=((SourceAddr << 4) & 0xf0) | TargetAddr; // 标准标识符//高位是从卡id号
TxMessage.ExtId=SourceAddr; // 设置扩展标示符(29位)
TxMessage.IDE=CAN_Id_Standard; // 使用扩展标识符CAN_Id_Extended
TxMessage.RTR=0; // 消息类型为数据帧,一帧8位
TxMessage.DLC=len; // 发送两帧信息
for(i=0;i<len;i++)
TxMessage.Data[i]=msg[i]; // 第一帧信息
mbox= CAN_Transmit(CAN1, &TxMessage);
i=0;
while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束
if(i>=0XFFF)return 1;
return 0;
}
/*
E6432_CAN1_Send(主卡Id,从卡(本机)Id, u8* msg,8);//从卡发出
E6432_CAN1_Send(从卡Id,0, u8* msg,8);//主卡发出,主卡ID号=0;
主卡接收目标地址为TargetAddr的标准帧
TxMessage.StdId=((SourceAddr << 4) & 0xf0) | TargetAddr; // 高4位是从卡SourceAddr 号;TargetAddr-目标主卡地址
接收端完全匹配目标主卡地址(本机)TargetAddr,并且不过滤SourceAddr 接收SourceAddr 范围为0-16(0-0XF),则:
CAN_FilterInitStructure.CAN_FilterIdHigh=StdId<< 5;//主卡ID号
这里一定要左移5位,才能跟TxMessage.StdId 对上
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
低位也要左移,详见见后面大神文章链接
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(uint16_t)((0xFF0F<<5) | 0x1F);//32位MASK
对应TxMessage.StdId=((extId << 4) & 0xf0) | stdId; // 高4位是从卡extId 号;stdId-目标主卡地址
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
*/
//配置过滤器
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
if(NODE_MI==0)//从机
{
CAN_FilterInitStructure.CAN_FilterIdHigh=Read_IP() << 5;//从机ID号为IP地址号
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;//
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
}
else//主机
{
CAN_FilterInitStructure.CAN_FilterIdHigh=can_master_id << 5;//主卡ID 号(0)
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;//
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(uint16_t)((0xFF0F<<5) | 0x1F);//32位MASK
//(0xFF0F<<5)与ID号同样左移5位后,| 0x1F 低位5为补1(完全匹配)
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;//0xFF0F;//
}
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
STM32之CAN —CAN ID过滤器分析
以下是上面文章中的两段例程,膜拜下、
位宽为32位的屏蔽模式
下面给出一个代码例子,假设我们要接收多个ID:0x7e9,0x1800f001,前面为标准ID,后面为扩展ID,要同时能接收这两个ID,那么该如何设置这个过滤器呢?
CAN_FilterInitTypeDef CAN_FilterInitStructure;
U16 std_id =0x7e9;
U32 ext_id =0x1800f001;
U32 mask =0;
CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量
CAN_FilterInitStructure.CAN_FilterNumber=0; //设置过滤器组0,范围为0~13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //设置过滤器组0为屏蔽模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //设置过滤器组0位宽为32位
//标识位寄存器的设置
//ext_id<<3对齐,见上图9,再>>16取高16位
CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff; //设置标识符寄存器高字节。
CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT; //设置标识符寄存器低字节
//这里也可以这样设置
//CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5; //设置标识符寄存器高字节.这里为什么是左移5位呢?从上图可以看出,CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],标准CAN ID本身是不包含扩展ID数据,因此为了要将标准CAN ID放入此寄存器,标准CAN ID首先应左移5位后才能对齐.
//CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT; //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD
//屏蔽寄存器的设置
//这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。
mask =(std_id<<18);//这里为什么左移18位?因为从ISO11898中可以看出,标准CAN ID占ID18~ID28,为了与CAN_FilterIdHigh对齐,应左移2位,接着为了与扩展CAN对应,还应该再左移16位,因此,总共应左移2+16=18位。也可以用另一个方式来理解:直接看Mapping的内容,发现STDID相对EXID[0]偏移了18位,因此左移18位.
mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反
mask =~mask;
mask <<=3;//再整体左移3位
mask |=0x02; //只接收数据帧,不接收远程帧
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节
CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff; //设置屏蔽寄存器低字节
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此过滤器组关联到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
位宽为32位的标识符列表模式
CAN_FilterInitTypeDef CAN_FilterInitStructure;
U16 std_id =0x7e9;
U32 ext_id =0x1800f001;
CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量
CAN_FilterInitStructure.CAN_FilterNumber=0; //设置过滤器组0,范围为0~13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; //设置过滤器组0为标识符列表模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //设置过滤器组0位宽为32位
//设置屏蔽寄存器,这里当标识符寄存器用
CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ; //为什么左移5位?与上面相同道理,这里不再重复解释
CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
//设置标识符寄存器
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节
CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT; //设置屏蔽寄存器低字节
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此过滤器组关联到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
我的理解是,
如果要过滤一个或大于两个ID,用位宽为32位的屏蔽模式
如果要过滤两个ID,用位宽为32位的标识符列表模式刚好