http://www.stmcu.org/article/id-328212
STM8 CAN总线的IdMask模式的讲解
前言
在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时根据标识符的值决定软件是否需要该报文;如果需要,就拷贝到RAM里;如果不需要,报文就被丢弃且无需软件的干预。为满足这一需求,BeCAN为应用程序提供了个可配置的、位宽可变的6个(0-5)过滤器组,用于只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件进行过滤,从而占用一定的CPU资源。
一、IdMask模式
首先,需要明白IdMask的作用:
举个例子吧,过滤器长度为32位,模式为屏蔽模式,假如我要发送的标示符为0x1314;那过滤器设置如下
1、过滤器完全无效 接收到的标示符全部通过
0x1314 二进制码: 00000000 0000 0000 0001 0011 0001 0100
CAN_Filter xxxx xxxx xxxx xxxx xxxx xxxxxxxx xxxx
CAN_FilterMask 0000 0000 0000 0000 00000000 0000 0000
因为 CAN_FilterMask屏蔽寄存器所有位都是0 ,对应标识符全为“不关心”,也就是接收到数据的ID(标识符)不用与 CAN_Filter寄存器的任何一位进行匹配。
2、过滤器完全有效 接收到的标识符要跟据CAN_FilterMask寄存器指定需要匹配的位进行与CAN_Filter比较。
部分匹配 :
0x1314 二进制码: 00000000 0000 0000 0001 0011 0001 0100
CAN_Filter xxxx xxxx xxxx xxxx xxxx xxx1 xxxx xxxx
CAN_FilterMask 0000 0000 0000 0000 0000 0001 0000 0000
CAN_FilterMask 寄存器指定接收到的标示符要与第8位进行匹配,其他位不管。也就是说接收到的标示符第8位必须为1,否则报文就会被丢弃。
全部匹配:
0x1314 二进制码: 00000000 0000 0000 0001 0011 0001 0100
CAN_Filter 0000 0000 0000 0000 0000 0011 0001 0100
CAN_FilterMask 1111 1111 1111 1111 1111 1111 1111 1111
这种情况最为严格,接收到的标示符必须每一位都得与过滤器中的标示符的每一位进行匹配,有一位不对报文就会被丢弃。(这个标示符匹配的工作是CAN 模块内部硬件自动完成的)
二、IdMask库代码
本程序中,使用的软件代码是:
软件:
\STM8S_StdPeriph_Lib\Project\STM8S_StdPeriph_Examples\CAN\CAN_Networking路径下面的代码。
硬件:
STM8/128 EVAL板子,上面的MCU为
STM8
S208MBT6B ;
程序里面打开了接收的中断:
为了能够更有效的操作实践这一功能,我使用了如上图的
CAN总线
的分析仪器USB-CAN200 以及它的上位机.
在这里需要说明一点,将R0+与R0-相短接,则内部的120欧姆的电阻会被接入总线,不需要画蛇添足,在R0+与R0-之间自己再找一个120欧姆的电阻外部接上!!
在接收中断里面已经有现成的标准桢结构,所以设置好Idfliter或者Idmask就可以。
也就是上面的 这一段函数;
按照刚才的理解,
如果我的扩展id是0x12345678 ;想只接收0x12xxxxxx的标识符号,那么是否填入
CAN_FilterID1 = 0x12 ;
CAN_FilterIDMask = 0xFF
就可以了呢? 本以为是这样,结果通过上位机发出去之后,led板上的符号并没有变化;说明并没有接收到。这是为什么呢?
三、分析
所以对于扩展的ID号码它有29位,但是程序中设计的过滤器位32位,所以:
如果假设扩展id为0x12345678(0001,0010,0011,0100,0101,0110,0111,1000)
所以扩展id的顺序填入如上图所示意,这儿假设:
RTR位我们设置为0表示数据帧,IDE位设置为1表示扩展ID,因为我们的ID是29位的,所以RTR = 0; IDE = 1;
再来看我们参考手册中,定义的 :
所以可以看到颜色的顺序已经被打乱了,
如果要关心到具体的某一个比特位置;如果要过滤器让它只接收0x12xxxxxx的标识符号;
这时候要根据它实际在identifier中的位置去修改idmask ; 前八个比特,对应的就是黄色和绿色的部分,
所以其他的颜色,可以都填0表示不需要关心,则这里填入:1 1 1 1 ,1 xx x,我们这里填入0xF8 ;
即:
CAN_FilterID1=0x91;
CAN_FilterID2=0x00;
CAN_FilterID3=0x00;
CAN_FilterID4=0x00;
CAN_FilterIDMask1=0xF8; //0
CAN_FilterIDMask2=0x00; //0
CAN_FilterIDMask3=0x00; //0x0
CAN_FilterIDMask4=0x00; //
同理,对于下面的配置是只接收标准id=0x321(0011,0010,0001)的ID(也是32位过滤器),
因为也是数据帧,所以RTR = 0,标准的id,所以IDE= 0 ;所以填入到:
CAN_FilterID1=0x64;
CAN_FilterID2=0x20;
CAN_FilterID3=0x00;
CAN_FilterID4=0x00;
CAN_FilterIDMask1=0xFF; //0
CAN_FilterIDMask2=0xE0; //0
CAN_FilterIDMask3=0x0; //0x0
CAN_FilterIDMask4=0x0; //
如下图,测试通过
四、附录
在CAN规范中并未定义代表逻辑电平的物理状态(例如电压),iCAN网络使用符合ISO11898-2标准的电平信号,一般来讲,CAN总线为“隐性”(逻辑1)时,CAN_H和CAN_L的电平为2.5V(电位差为0V);CAN总线为“显性”(逻辑0)时,CAN_H和CAN_L的电平分别是3.5V和1.5V(电位差为2.5V)。
识别符
识别符—标准格式 识别符的长度为11 位,相当于扩展格式的基本ID(Base ID)。这些位按ID-28 到ID-18 的顺序发送。最低位是ID-18。7 个最高位(ID-28- ID-22)必须不能全是“隐性”。
识别符—扩展格式 和标准格式形成对比,扩展格式由29 位组成。其格式包含两个部分:11 位基本ID、18 位扩展ID。
基本ID:基本ID 包括11 位。它按ID-28 到ID-18 的顺序发送。它相当于标准识别符的格式。基本ID定义扩展帧的基本优先权。
扩展ID:扩展ID 18 位。它按ID-17 到ID-0 顺序发送。 标准帧里,识别符其后是RTR 位。 RTR 位(标准格式以及扩展格式) RTR 的全称为“远程发送请求位(RemoteTransmission Request BIT)”。 RTR 位在数据帧里必须为“显性”,而在远程帧里必须为“隐性” 。
扩展格式里,基本ID 首先发送,其次是IDE 位和SRR 位。扩展ID 的发送位与SRR 位之后。
SRR 位(扩展格式)
SRR 的全称是“替代远程请求位(SubstituteRemote Request BIT)”。
SRR 是一隐性位。它在扩展格式的标准帧RTR 位位置,因此代替标准帧的RTR 位。
标准帧与扩展帧的冲突是通过标准帧优先于扩展帧这一途径得以解决,扩展帧的基本ID(参见以下的“扩展识别符”)如同标准帧的识别符。
IDE 位(扩展格式) IDE 的全称是“识别符扩展位(IdentifierExtension Bit)”
IDE 位属于:
– 扩展格式的仲裁场
– 标准格式的控制场
标准格式里的IDE位为“显性(逻辑0)”,而扩展格式里的IDE位为“隐性”。
在标识符列表模式下,屏蔽寄存器当作标识符寄存器用。因此,使用2个标识符来代替上面的标识符加屏蔽位的方式。接收报文标识的每一位都必须跟过滤器标识符相同。
设置过滤器0只接收ID为0x1828A0EF和0x1828A0EE的数据帧。(工作在标识符列表模式)
首先我们把这两个ID写成二进制:
0x1828A0EF: 00011000001010001010000011101111
0x1828A0EE: 00011000001010001010000011101110
然后我们将0x1828A0EF二进制的格数据组成如上图mapping所示的格式
Cna_fxr1:1100 0001 0xc1
Cna_fxr2:01001001 0x49 //这里有个RTR位我们设置为0表示数据帧,IDE位设置为1表示扩展ID,
Cna_fxr3:0100 0001 0x41
Cna_fxr4:1101 1110 0xDE
这时我们工作在标识符列表模式,identifier/Mask的寄存器相当于identifier使用。
再将0x1828A0EE二进制的格数据组成如上图mapping所示的格式
Cna_fxr5:1100 0001 0xc1
Cna_fxr6:01001001 0x49 //这里有个RTR位我们设置为0表示数据帧,IDE设置为1表示扩展ID
Cna_fxr7:0100 0001 0x41
Cna_fxr8:1101 1100 0xDC
以下是用库函数配置的程序小片段:
CAN_FilterNumber =CAN_FilterNumber_0;
//注意这是的模式是跟
IdMask
例不一样的
CAN_FilterMode =CAN_FilterMode_IdList;
CAN_FilterScale =CAN_FilterScale_32Bit;
CAN_FilterID1=0xc1;
CAN_FilterID2=0x49;
CAN_FilterID3=0x41;
CAN_FilterID4=0xde;
CAN_FilterIDMask1=0xc1;
CAN_FilterIDMask2=0x49;
CAN_FilterIDMask3=0x41;
CAN_FilterIDMask4=0xdc;
相信看到这里你对这两种工作模式都会有了一定的了解。好了,到此例子就介绍完了,算是抛砖引玉。8位、16位的位宽是相似的,跟上面的分析一样。