CAN
屏蔽码/验证码
也就是说,屏蔽码设得宽度,得到其验证码
ID
标准
11位
扩展
29位(不够用之后拓宽
过滤器
掩码和列表模式
定义在CAN_FM1R寄存器中FBMx位上,bxCAN共有28个过滤器,于是上图的每一个位对应地表示这28个过滤器的工作模式,供用户设置。”0”表示掩码模 式,”1”表示列表模式。
表示CAN ID位宽
寄存器CAN_FS1R来表示CAN ID的位宽,每一个位对应着bxCAN中28个过滤器的位宽,这个需要用户来设置
各种组合模式
具体工作模式(解决方案
每个过滤器都存在这么两个寄存器CAN_FxR1和CAN_FxR2,这两个寄存器都是32位的
掩码模式—32
CAN_FxR1用做32位宽的验证码,而CAN_FxR2则用作32位宽的屏蔽码
只针对标准CAN ID
对于验证码,任意一个期望通过的CAN ID都是可以设为验证码的,但屏蔽码,却是所有期望通过的CAN ID相互同或后的最终结果,这个即是屏蔽码
static void CANFilterConfig_Scale32_IdMask_StandardIdOnly(void)
{
CAN_FilterConfTypeDef sFilterConfig;
uint16_t StdIdArray[10] ={0x7e0,0x7e1,0x7e2,0x7e3,0x7e4,
0x7e5,0x7e6,0x7e7,0x7e8,0x7e9}; //定义一组标准CAN ID
uint16_t mask,num,tmp,i;
sFilterConfig.FilterNumber = 2; //使用过滤器2
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置为32位宽
sFilterConfig.FilterIdHigh =(StdIdArray[0]<<5); //验证码可以设置为StdIdArray[]数组中任意一个,这里使用StdIdArray[0]作为验证码
sFilterConfig.FilterIdLow =0;
mask =0x7ff; //下面开始计算屏蔽码
num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);
for(i =0; i<num; i++) //屏蔽码位StdIdArray[]数组中所有成员的同或结果
{
tmp =StdIdArray[i] ^ (~StdIdArray[0]); //所有数组成员与第0个成员进行同或操作
mask &=tmp;
}
sFilterConfig.FilterMaskIdHigh =(mask<<5);
sFilterConfig.FilterMaskIdLow =0|0x02; //只接收数据帧
sFilterConfig.FilterFIFOAssignment = 0; //设置通过的数据帧进入到FIFO0中
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
只针对扩展CAN ID
扩展CAN ID的验证码与屏蔽码放入到相对应的寄存器时所移动的位数与标准CAN ID时有所差别,其他的都一样
static void CANFilterConfig_Scale32_IdMask_ExtendIdOnly(void)
{
CAN_FilterConfTypeDef sFilterConfig;
//定义一组扩展CAN ID用来测试
uint32_t ExtIdArray[10] ={0x1839f101,0x1835f102,0x1835f113,0x1835f124,0x1835f105,
0x1835f106,0x1835f107,0x1835f108,0x1835f109,0x1835f10A};
uint32_t mask,num,tmp,i;
sFilterConfig.FilterNumber = 3; //使用过滤器3
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设为32位宽
sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff;//数组任意一个成员都可以作为验证码
sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff) | CAN_ID_EXT;
mask =0x1fffffff;
num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);
for(i =0; i<num; i++) //屏蔽码位数组各成员相互同或的结果
{
tmp =ExtIdArray[i] ^ (~ExtIdArray[0]); //都与第一个数据成员进行同或操作
mask &=tmp;
}
mask <<=3; //对齐寄存器
sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;
sFilterConfig.FilterMaskIdLow = (mask&0xffff)|0x02; //只接收数据帧
sFilterConfig.FilterFIFOAssignment = 0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
标准和扩展混合过滤
在混合的情况下,只需稍微修改下屏蔽码的计算方式就可以了,其他的基本没有什么变化。
static void CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix(void)
{
CAN_FilterConfTypeDef sFilterConfig;
//定义一组标准CAN ID
uint32_t StdIdArray[10] ={0x711,0x712,0x713,0x714,0x715,
0x716,0x717,0x718,0x719,0x71a};
//定义另外一组扩展CAN ID
uint32_t ExtIdArray[10] ={0x1900fAB1,0x1900fAB2,0x1900fAB3,0x1900fAB4,0x1900fAB5,
0x1900fAB6,0x1900fAB7,0x1900fAB8,0x1900fAB9,0x1900fABA};
uint32_t mask,num,tmp,i,standard_mask,extend_mask,mix_mask;
sFilterConfig.FilterNumber = 4; //使用过滤器4
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设为32位宽
sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff; //使用第一个扩展CAN ID作为验证码
sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff);
standard_mask =0x7ff; //下面是计算屏蔽码
num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);
for(i =0; i<num; i++) //首先计算出所有标准CAN ID的屏蔽码
{
tmp =StdIdArray[i] ^ (~StdIdArray[0]);
standard_mask &=tmp;
}
extend_mask =0x1fffffff;
num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);
for(i =0; i<num; i++) //接着计算出所有扩展CAN ID的屏蔽码
{
tmp =ExtIdArray[i] ^ (~ExtIdArray[0]);
extend_mask &=tmp;
}
mix_mask =(StdIdArray[0]<<18)^ (~ExtIdArray[0]); //再计算标准CAN ID与扩展CAN ID混合的屏蔽码
mask =(standard_mask<<18)& extend_mask &mix_mask; //最后计算最终的屏蔽码
mask <<=3; //对齐寄存器
sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;
sFilterConfig.FilterMaskIdLow = (mask&0xffff);
sFilterConfig.FilterFIFOAssignment = 0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
掩码模式—16
CAN_FxR1和CAN_FxR2都要各自拆分成两个16位宽的寄存器来使用,CAN_FxR1的低16位是作为验证码,对应的16位屏蔽码为CAN_FxR1的高16位,同样的,CAN_FxR2的低16位是作为验证码,对应与CAN_FxR2的高16位为屏蔽码
static void CANFilterConfig_Scale16_IdMask(void)
{
CAN_FilterConfTypeDef sFilterConfig;
uint16_t StdIdArray1[10] ={0x7D1,0x7D2,0x7D3,0x7D4,0x7D5, //定义第一组标准CAN ID
0x7D6,0x7D7,0x7D8,0x7D9,0x7DA};
uint16_t StdIdArray2[10] ={0x751,0x752,0x753,0x754,0x755, //定义第二组标准CAN ID
0x756,0x757,0x758,0x759,0x75A};
uint16_t mask,tmp,i,num;
sFilterConfig.FilterNumber = 5; //使用过滤器5
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //设为16位宽
//配置第一个过滤对
sFilterConfig.FilterIdLow =StdIdArray1[0]<<5; //设置第一个验证码
mask =0x7ff;
num =sizeof(StdIdArray1)/sizeof(StdIdArray1[0]);
for(i =0; i<num; i++) //计算第一个屏蔽码
{
tmp =StdIdArray1[i] ^ (~StdIdArray1[0]);
mask &=tmp;
}
sFilterConfig.FilterMaskIdLow =(mask<<5)|0x10; //只接收数据帧
//配置第二个过滤对
sFilterConfig.FilterIdHigh = StdIdArray2[0]<<5; //设置第二个验证码
mask =0x7ff;
num =sizeof(StdIdArray2)/sizeof(StdIdArray2[0]);
for(i =0; i<num; i++) //计算第二个屏蔽码
{
tmp =StdIdArray2[i] ^ (~StdIdArray2[0]);
mask &=tmp;
}
sFilterConfig.FilterMaskIdHigh = (mask<<5)|0x10; //只接收数据帧
sFilterConfig.FilterFIFOAssignment = 0; //通过的CAN 消息放入到FIFO0中
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
列表模式—32
static void CANFilterConfig_Scale32_IdList(void)
{
CAN_FilterConfTypeDef sFilterConfig;
uint32_t StdId =0x321; //这里写入两个CAN ID,一个位标准CAN ID
uint32_t ExtId =0x1800f001; //一个位扩展CAN ID
sFilterConfig.FilterNumber = 0; //使用过滤器0
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //设为列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //配置为32位宽
sFilterConfig.FilterIdHigh = StdId<<5; //基本ID放入到STID中
sFilterConfig.FilterIdLow = 0|CAN_ID_STD; //设置IDE位为0
sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;
sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT; //设置IDE位为1
sFilterConfig.FilterFIFOAssignment = 0; //接收到的报文放入到FIFO0中
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
存储某个具体的期望通过的CAN ID,这样就可以存入2个期望通过的CAN ID(标准CAN ID和扩展CAN ID均可)
CAN_FxR1寄存器的高16位对应着上面代码中的FilterIdHigh,低16位对应着FilterIdLow,而CAN_FxR2寄存器的高16位对应着FilterMaskIdHigh,低16位对应着FilterMaskIdLow(看成4个变量来用)
列表模式—16
static void CANFilterConfig_Scale16_IdList(void)
{
CAN_FilterConfTypeDef sFilterConfig;
uint32_t StdId1 =0x123; //这里采用4个标准CAN ID作为例子
uint32_t StdId2 =0x124;
uint32_t StdId3 =0x125;
uint32_t StdId4 =0x126;
sFilterConfig.FilterNumber = 1; //使用过滤器1
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //设为列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //位宽设置为16位
sFilterConfig.FilterIdHigh = StdId1<<5; //4个标准CAN ID分别放入到4个存储中
sFilterConfig.FilterIdLow = StdId2<<5;
sFilterConfig.FilterMaskIdHigh = StdId3<<5;
sFilterConfig.FilterMaskIdLow = StdId4<<5;
sFilterConfig.FilterFIFOAssignment = 0; //接收到的报文放入到FIFO0中
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;
if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
2对验证码+屏蔽码组合来用,但它只能对标准CAN ID进行过滤
在16位宽的列表模式下,FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow这4个16位变量都是用来存储一个标准CAN ID
发送和接收
发送
设置邮箱,设置ID,设置CAN_TlxR(邮箱标识符寄存器)的TXRQ为1请求发送,邮箱挂号(等待成为最高优先级),预定发送,发送,邮箱空值
接收
通过读取FIFO输出邮箱来读取最先收到的报文(有效报文:正确被接收且通过标识符过滤的报文)。 CAN 的接收有 2 个 FIFO,我们每个滤波器组都可以设置其关联的 FIFO,通过 CAN_FFA1R 的设置,可以将滤波器组关联到FIFO0/FIFO1。
注意事项
屏蔽码和验证码的设置
验证码可以设置为某个确定的ID
屏蔽码是所有期望通过的CAN ID相互同或后的最终结果