在使用MCP2518FD时,需要多个标准帧接收,但是需要用到屏蔽器和过滤器,否则庞大的数据量会导致设备接收处理不过来。若使用接收中断(中断或查询方式),会导致设备工作异常。
程序处理环境:
1、需要接收多个id
2、自动计算屏蔽器赋值
---------------------------------------------------------------
原理讲解
MCP2518FD的(大多数的CAN芯片或者芯片内的CAN接收)接收数据,需要用到接收屏蔽和过滤器。
过滤器对象寄存器简而言之就是需要接收到的id。
屏蔽寄存器简而言之就是对过滤器对象寄存器哪些位必须对应,哪些无所谓。
例如1:
需要接收1个id - 0x50D
那么:
过滤对象寄存器 = 0x50D = 101 0000 1101
屏蔽寄存器 = 7FF = 111 1111 1111
得到的接收id的结果即为0x50D(两个寄存器配合接收id的规则为:屏蔽对象寄存器为1,则接收的id对应bit必须和过滤对象寄存器bit相同)。
上面屏蔽寄存器bit都为1,所以接收的id必须 = 过滤对象寄存器的值。
解释:
分析1 | ||
二进制 | ||
过滤对象寄存器 | 0x0000050D | 0000 0000 0000 0000 0000 0101 0000 1101 |
屏蔽寄存器 | 0x400007FF | 0100 0000 0000 0000 0000 0111 1111 1111 |
只看后11bit(后面的11bit为标准帧id) | ||
接收的id | 0x50D | 101 0000 1101 |
例如2:
根据上面规则,若是有多个id需要接收。
分析2 | ||
二进制 | ||
过滤对象寄存器(需要的id) | 0x0000050D | 0000 0000 0000 0000 0000 0101 0000 1101 |
0x0000050B | 0000 0000 0000 0000 0000 0101 0000 1011 | |
屏蔽寄存器 | 0x400007F9 | 0100 0000 0000 0000 0000 0111 1111 1001 |
只看后11bit,屏蔽对象寄存器为0则接收可为0/1 | ||
可以接收的id为 | 101 0000 1xx1 | |
接收的id | 0x509 | 101 0000 1001 |
0x50B | 101 0000 1011 | |
0x50D | 101 0000 1101 | |
0x50F | 101 0000 1111 |
如表格内容:想要接收id,0x50D、0x50B。此时屏蔽寄存器不能为0x7FF,因为此时有两个id,不能写死。对比0x50D、0x50B的二进制位。可以看到,低(从0开始)1、2bit都不相同,可能为0,也可能为1。所以屏蔽寄存器的低(从0开始)1、2bit需要为0。屏蔽寄存器 = 0x7F9。这样我们可以接收到0x509、0x50B、0x50D、0x50F共四种id。我们只需要在软件中将接收到的id进行判断即可。
例如3:
那如果是有2个以上或者很多id呢???
我们先通过2个id和3个id查看规律。可以看到,我们得到屏蔽寄存器的值都是通过 同或(异或取反)运算 得到的,即bit相同为1,不同为0。
2个id我们还可以直接使用同或计算。3个即以上却没有办法了,本人基础差,只能询问AI,AI表示只能逐位比较得到。于是我自己写了程序。
先放一下3bit计算的结果。
分析3 | ||
二进制 | ||
过滤对象寄存器(需要的id) | 0x0000050D | 0000 0000 0000 0000 0000 0101 0000 1101 |
0x0000050A | 0000 0000 0000 0000 0000 0101 0000 1010 | |
0x0000050B | 0000 0000 0000 0000 0000 0101 0000 1011 | |
屏蔽寄存器 | 0x400007F8 | 0100 0000 0000 0000 0000 0111 1111 1000 |
只看后11bit,屏蔽对象寄存器为0则接收可为0/1 | ||
101 0000 1101 | ||
101 0000 1010 | ||
101 0000 1011 | ||
同或运算结果 | 111 1111 1000 |
逐位比较程序(直接放程序,我现在devC上面测试的,可以直接移植到自己的程序上):
#include "stdio.h"
#define CANReveiveIDNum 2 //需要接收的CANid数量
unsigned int CAN_Response_ID[CANReveiveIDNum] = {0x50B,0x50D};//id,数量对应CANReveiveIDNum
unsigned int CAN_ReceiveID_FilterValue= 0x40000000;//用于配置屏蔽寄存器,过滤寄存器使用其中1个需要接收的id即可
//根据宏定义的id进行配置,,获取屏蔽寄存器的算法在数学上为a XNOR b = (a AND b) OR (NOT a AND NOT b)简化为a XNOR b = NOT (a XOR b)
//使用代码处理则需要进行逐位比较
void CAN_ReceiveID_FilterConfig(void){
unsigned char ResultBit;//用于存储当前位比较的结果
unsigned char NowBit,NextBit;//分别用于存储 当前的比较位,和下个id的比较位
unsigned short int CAN_ReceiveID_FilterID = 0;//用于存储当前获取的id
if(CANReveiveIDNum>0){//如果有id
if(CANReveiveIDNum>1){//如果id数量大于1
for(unsigned char i=0;i<11;i++){//id 11bit
for(unsigned char j=0;j<CANReveiveIDNum-1;j++){//id数量
NowBit = (CAN_Response_ID[j]>>i)&0x01;//当前比较的bit
NextBit = (CAN_Response_ID[j+1]>>i)&0x01;//下一个id的比较bit
if(NowBit == NextBit){
ResultBit = 1;
}else{
ResultBit = 0;
break;
}
}
CAN_ReceiveID_FilterID |= ResultBit<<i;
}
}else{
CAN_ReceiveID_FilterValue = 0x400007FF;//如果只有1个id
}
}else{//如果没有id
;
}
CAN_ReceiveID_FilterValue += CAN_ReceiveID_FilterID;
printf("%x",CAN_ReceiveID_FilterValue);
}
int main(){
CAN_ReceiveID_FilterConfig();
return 0;
}
上面的运行结果(例子2)为:
修改参数运行:
#include "stdio.h"
#define CANReveiveIDNum 3 //需要接收的CANid数量
unsigned int CAN_Response_ID[CANReveiveIDNum] = {0x50B,0x50D,0x50A};//id,数量对应CANReveiveIDNum
unsigned int CAN_ReceiveID_FilterValue= 0x40000000;//用于配置屏蔽寄存器,过滤寄存器使用其中1个需要接收的id即可
//根据宏定义的id进行配置,,获取屏蔽寄存器的算法在数学上为a XNOR b = (a AND b) OR (NOT a AND NOT b)简化为a XNOR b = NOT (a XOR b)
//使用代码处理则需要进行逐位比较
void CAN_ReceiveID_FilterConfig(void){
unsigned char ResultBit;//用于存储当前位比较的结果
unsigned char NowBit,NextBit;//分别用于存储 当前的比较位,和下个id的比较位
unsigned short int CAN_ReceiveID_FilterID = 0;//用于存储当前获取的id
if(CANReveiveIDNum>0){//如果有id
if(CANReveiveIDNum>1){//如果id数量大于1
for(unsigned char i=0;i<11;i++){//id 11bit
for(unsigned char j=0;j<CANReveiveIDNum-1;j++){//id数量
NowBit = (CAN_Response_ID[j]>>i)&0x01;//当前比较的bit
NextBit = (CAN_Response_ID[j+1]>>i)&0x01;//下一个id的比较bit
if(NowBit == NextBit){
ResultBit = 1;
}else{
ResultBit = 0;
break;
}
}
CAN_ReceiveID_FilterID |= ResultBit<<i;
}
}else{
CAN_ReceiveID_FilterValue = 0x400007FF;//如果只有1个id
}
}else{//如果没有id
;
}
CAN_ReceiveID_FilterValue += CAN_ReceiveID_FilterID;
printf("%x",CAN_ReceiveID_FilterValue);
}
int main(){
CAN_ReceiveID_FilterConfig();
return 0;
}
修改的地方(改成了例子3):
运行结果:
可见和例子中手算的结果相同。
-------------------------
其他:
程序中没有说过滤对象寄存器需要赋值多少,过滤对象寄存器只需要赋值需要接收的id的其中一个就行,因为频闭寄存器对应的bit = 0,都可以接收到。