打印
[研电赛技术支持]

基于GD32C103 CAN标准帧的掩码模式 32bitCAN过滤器

[复制链接]
141|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
  在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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

48

主题

200

帖子

1

粉丝