详解CAN通信的标识符掩码和标识符列表两种过滤机制

CAN 通信的应用非常广泛,本文不涉及CAN通信的基础配置,重点分析一下STM32和GD32的CAN通信两种ID过滤方式。

首先,不管是STM32还是GD32,实现CAN通信ID过滤的机制和原理一定是一样的,只是用到的寄存器有差别。

1. ID过滤原理:
在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符的值决定软件是否需要该报文。
为满足这一需求,在互联型产品中,bxCAN控制器为应用程序提供了28个位宽可变的、可配置的过滤器组(270);在其它产品中,bxCAN控制器为应用程序提供了14个位宽可变的、可配置的过滤器组(130),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。

每个过滤器组x由2个32位寄存器,在STM32中是由CAN_FxR0和CAN_FxR1组成。在GD32中是由器CAN_FxDATA0和CAN_ FxDATA1组成。

2. ID过滤方式:
掩码模式、列表模式。
不管是掩码模式还是列表模式,目的肯定都是为了让数据接收方接收特定ID的数据,但是既然分了两种模式,肯定有他们的不同的目的。

3.ID过滤方式1——掩码模式:
在掩码模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
举个例子:
假如是标准帧模式,以16位宽度为例,预设的ID=0x0001,当期望接收所有ID尾号为1的数据,那么设置对应的掩码为MASK=0x0001即可。
为什么呢?将ID的0x0001和MASK的0x0001解析成2进制:
预设ID:0000 0000 0000 0001;
MASK:0000 0000 0000 0001;
MSAK值的1的位表示:接收的ID必须与预设ID的位一致;
MASK值为0的位表示:接收的ID可以不与预设ID的位一致;
因此示例的MASK仅限制了ID的最后1位与预设ID的最后1为一致即可,其余的位不做限制,只要满足这样形式的ID数据,都能通过示例的过滤机制,从而被接收方正确接收,此处可知,掩码的作用就是要以预设ID为模板,决定过滤掉哪些类型的ID;

也就是说:
为了过滤出一组标识符,应该设置过滤器组工作在掩码模式。

注意,示例选用了标准帧模式,以16位宽度进行过滤,因此原本一个过滤器组的2个32位寄存器就分成了4个16位的空间,分别去保存预设的ID和相应的掩码:
格式如下:
预设ID1:【占用寄存器1的低16位】;
ID1的掩码:【占用寄存器1的高16位】;
同理:
预设ID2:【占用寄存器2的低16位】;
ID2的掩码:【占用寄存器2的高16位】;

由此可知,此种方式下,最多可预设2种ID,可过滤出多个ID;
STM32与GD32的过滤器机制一模一样:
(1)STM32参考手册的16位掩码模式过滤器如下:
在这里插入图片描述
(2)GD32参考手册的16位掩码模式过滤器如下:
在这里插入图片描述

注意,此种模式下,在配置时需要将对应的ID和掩码数据分别写进寄存器的STID区域,如上图所示,在16位空间中,STID区域处于高11位,因此需要将预设ID和掩码数据左移5位后写进寄存器。代码如下:

/**
 * @brief    can外设配置
 * @param    None
 * @retval   返回值
 */
void can_config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	CAN_InitTypeDef CAN_InitStructure;
	CAN_FilterInitTypeDef CAN_FilterInitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

	/*
    CAN1_RX -- PA11
    CAN1_TX -- PA12
    */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);
	CAN_InitStructure.CAN_TTCM = DISABLE; //不生成时间戳
	CAN_InitStructure.CAN_ABOM = ENABLE;  //自动总线关闭管理
	CAN_InitStructure.CAN_AWUM = DISABLE; //自动唤醒模式
	CAN_InitStructure.CAN_NART = DISABLE; //仲裁丢失或出错后的自动重传功能
	CAN_InitStructure.CAN_RFLM = DISABLE; //接收FIFO加锁模式
	CAN_InitStructure.CAN_TXFP = ENABLE;  //传输FIFO优先级
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
	CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS1_8tq;
	CAN_InitStructure.CAN_Prescaler = 40; // 波特率36000000/18/40 = 50KHz
	CAN_Init(CAN1, &CAN_InitStructure);

	CAN_FilterInit(&CAN_FilterInitStructure);
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
	if (can.device_mode == DEVICE_MASTER) //识别所有0x0xx类型的从设备地址
	{
		CAN_FilterInitStructure.CAN_FilterIdHigh = CAN_ID_BASE_SLAVE << 5; //ID1
		CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x700 << 5;		   //ID1_MASK
		CAN_FilterInitStructure.CAN_FilterIdLow = CAN_ID_DEFAULT << 5;	   //ID2
		CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x7FF << 5;		   //ID2_MASK
	}
	else //仅识别与本设备地址匹配的地址,保证主设备对从设备实现一对一通讯,也识别0x0000广播
	{
		CAN_FilterInitStructure.CAN_FilterIdHigh = can.std_id << 5; //ID1
		CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x7FF << 5;	//ID1_MASK
		CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000 << 5;		//ID2
		CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x7FF << 5;	//ID2_MASK
	}

	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);

	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //FIFO0消息挂号中断
	nvic_set(USB_LP_CAN1_RX0_IRQn, IRQ_PRIO_CAN1);
}

4. ID过滤方式2——列表模式:
在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。通俗一点讲就是:接收的ID必须与预设的ID一模一样才能通过过滤,最终被接收到。

举个例子:
假如是标准帧模式,以16位宽度为例,预设的ID=0x0001,当期望仅接收与预设ID一致的数据,那么只要发送的ID与预设ID一样就可以被接收到,其余类型的ID数据都被过滤掉,接收方将接收不到此类数据。

也就是说:
为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。

注意,示例选用了标准帧模式,以16位宽度进行过滤,因此原本一个过滤器组的2个32位寄存器就分成了4个16位的空间,分别去保存预设的ID:
格式如下:
预设ID1:【占用寄存器1的低16位】;
预设ID2:【占用寄存器1的高16位】;
预设ID3:【占用寄存器2的低16位】;
预设ID4:【占用寄存器2的高16位】;

由此可知,此种方式下,最多可预设4种ID,可过滤出4个ID;
STM32与GD32的过滤器机制一模一样:
(1)STM32参考手册的16位列表模式过滤器如下:
在这里插入图片描述
(2)GD32参考手册的16位列表模式过滤器如下:
在这里插入图片描述

注意,此种模式下,在配置时需要将对应的4个ID分别写进寄存器的STID区域,如上图所示,在16位空间中,STID区域处于高11位,因此需要将预设ID数据左移5位后写进寄存器。示例代码如下:

CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;     //??????  
  CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;    //?????16?  
  CAN_FilterInitStructure.CAN_FilterIdHigh = std_id<<5;  //4???CAN ID?????4????  
  CAN_FilterInitStructure.CAN_FilterIdLow = std_id1<<5;  
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh = std_id<<5;  
  CAN_FilterInitStructure.CAN_FilterMaskIdLow = std_id1<<5;  
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;           //?????????FIFO0?  
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;//激活过滤器0	

5. 总结一下:
两种过滤方式各有千秋,需要过滤出一组ID,使用掩码模式;
需要过滤出特定的几个ID,使用列表模式。
实际使用中可巧妙地调整预设ID和掩码,甚至组合使用掩码模式和列表模式实现自己想要的过滤效果。

  • 10
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值