在CAN节点较多的项目中,通过配置CAN过滤器的方式,降低总线上的负载率;通过“CAN硬件层”的处理自动过滤掉不希望接收的数据。
过滤器分为两大类:
1、列表模式
列表模式:简单来说就是把希望通过的ID号,“告诉CAN”。例如我希望通过的ID号是0X580,则就可以把0x580告知can;此方式简洁明了,但是筛选范围放大之后,随之需要写入的ID号也随着增加;有100个节点就需要,手动添加100个数据。而且对于资源紧张的嵌入式开发而言该方式也并不是最优。
在实际使用时:bxCAN的一个过滤器若工作在列表模式下,scale为32时,每个过滤器的列表只能写入两个报文ID,若scale为16时,每个过滤器的列表最多可写入4个CAN ID,由此可见,MCU的资源是非常非常有限的,并不能任我们随心所欲。因此,我们需要考虑另外一种替代方案,这种方案应该不受到数量限制。
2、掩码模式
掩码模式:掩码模式的基本逻辑是 分为了验证码和屏蔽码;
验证码:验证码是希望通过的任一ID号,
屏蔽码:屏蔽码是希望通过的所有ID 同或,
机器在执行任务的时候先将获取的身份*号码 ID 与屏蔽码进行“与”操作,再将结果与验证码的进行比较,根据判断是否相同来决定是否通过。整个判别流程如下所示:
从上图可以很容易地理解屏蔽码与验证码的含义,这样一来,能通过的结果数量就完全取决于屏蔽码,设得宽,则可以通过的多(所有位为0,则不过任何过滤操作,则谁都可以通过),设得窄,则通过的少(所有位设为1,则只有一个能通过)。那么知道这个有什么用呢?因为bxCAN的过滤器的掩码模式就是采用这种方式,在bxCAN中,分别采用了两个寄存器(CAN_FiR1,CAN_FiR2)来存储屏蔽码与验证码,从而实现掩码模式的工作流程的。这样,我们就知道了bxCAN过滤器的掩码模式的大概工作原理。
但是,我们得注意到,采用掩码模式的方式并不能精确的对每一个ID进行过滤,打个比方,还是采用之前的守卫的例子,假如城主要求只有1150~1158年出生的人能通过,那么,若我们还是才用掩码模式,那么掩码就设为第7-9位为”1”,对应的,验证码的7-9位分别为”115”,这样就可以了。但是,仔细一想,出生于1159的人还是可以通过,是不是?但总体来说,虽然没有做到精确过滤,但我们还是能做到大体过滤的,而这个就是掩码模式的缺点了。在实际应用时,取决于需求,有时我们会同时使用到列表模式和掩码模式,这都是可能的。
3、过滤器模式
过滤器一共有4种工作模式:
32位宽的掩码模式, 配置过滤1个不同的ID号
32位宽的列表模式, 配置过滤2个不同的ID号
16位宽的列表模式, 配置过滤4个不同的ID号
16位宽的掩码模式, 配置过滤2个不同的ID号
滤波模式有以下两种:
屏蔽位模式
标识符列表模式
过滤器的位宽:
16位过滤器
32位过滤器
屏蔽ID设置注意要点:
在配置为标识符掩码模式时,若配置了多组标识符掩码,则只要接收到的标识符符合其中任意一组掩码的都会通过滤波器,所以千万不要有其中一组是通配的(即掩码为0x0000),否则你设置的其它掩码组都会无效,这个问题在配置为16位标识符掩码模式时很容易犯,因为这个时候你必须得配两组,很多人就会只配置了自己要的那一组(因为很多时候都是只需要一组掩码就够了),另外一组就不配了(0x0000,即通配),如下代码:
CAN_FilterInitStructure.CAN_FilterIdHigh=0x1200<<5;
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000<<5;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xff00;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
代码本意是要让符合0x12xx的标识符通过滤波器,但是由于它第二组的掩码设置为0x0000,导致所有的标识符都通配了;如果要实现预期效果,则应该把第二组的ID和Mask也设置为一样,或者只把mask改为0xffff,这样就比预期多了一个0x0000可以通过滤波器。
4、程序
本例子使用在CAN 标准帧 使用掩码模式 32bit 过滤一组;在GD32C103上实现了对0x600+nodeID(0~127)通过;其他不响应。
CAN过滤器初始化:
/**
@function rewrite_can_filter_init
@brief CAN 过滤器 过滤 0X600+node_ID(0~127)
@param[in] dev_id: [in/out]
** len: [in/out]
** dat: [in/out]
@return L
@date 2025-07-04
*/
void rewrite_can_filter_init()
{
//can0 过滤器结构体
can_filter_parameter_struct can0_filter_parameter_struct;
uint16_t StdIdArray[128] = {0}; // 初始化数组为全0
uint16_t startId = 0x600; // 起始ID
uint16_t mask = 0x7FF; // 初始屏蔽码
uint16_t tmp;
// 合并填充数组与计算屏蔽码的循环
for (int i = 0; i < 128; i++)
{
StdIdArray = startId + i; // 填充数组
tmp = StdIdArray ^ (~StdIdArray[0]);
mask &= tmp; // 计算屏蔽码
}
can0_filter_parameter_struct.filter_number = 0; // 使用过滤器2
can0_filter_parameter_struct.filter_mode = CAN_FILTERMODE_MASK; // 掩码模式
can0_filter_parameter_struct.filter_bits = CAN_FILTERBITS_32BIT;// 32位过滤器
can0_filter_parameter_struct.filter_list_high = (StdIdArray[0] << 5); // 验证码高字节部分
can0_filter_parameter_struct.filter_list_low = 0; // 验证码低字节部分
can0_filter_parameter_struct.filter_mask_high = (mask << 5); // 过滤器掩码数高位
can0_filter_parameter_struct.filter_mask_low = 0 | 0x02; // 只接收数据帧
can0_filter_parameter_struct.filter_fifo_number = CAN_FIFO0; // 过滤器关联FIFO0
can0_filter_parameter_struct.filter_enable = ENABLE;
can_filter_init(&can0_filter_parameter_struct); // 初始化过滤器
}
CAN硬件初始化:
/**
@function com_can_init
@brief None
@param[in] None
@return None
@date 2023-06-27
*/
bool com_can_init(void)
{
// configure RCU
rcu_periph_clock_enable(RCU_CAN0);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_AF);
// configure IO
gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
// configure CAN
can_parameter_struct can_parameter;
can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
can_deinit(CAN0);
// initialize CAN parameters
can_parameter.time_triggered = DISABLE;
can_parameter.auto_bus_off_recovery = ENABLE;//DISABLE;
can_parameter.auto_wake_up = ENABLE;//DISABLE;
can_parameter.auto_retrans = DISABLE;//ENABLE;
can_parameter.rec_fifo_overwrite = DISABLE;
can_parameter.trans_fifo_order = DISABLE;
can_parameter.working_mode = CAN_NORMAL_MODE;
can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
can_parameter.prescaler = 12; //6:1MHz,12:500Khz
can_init(CAN0, &can_parameter);
can1_filter_start_bank(14);
rewrite_can_filter_init(); //can 过滤器初始化
// configure NVIC
nvic_irq_enable(CAN0_RX0_IRQn, 1, 0);
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
return true;
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_52785624/article/details/149027087
|