再谈STM32的CAN过滤器
扫描二维码
随时随地手机看文章
1. 前言
bxCAN是STM32系列最稳定的IP核之一,无论有哪个新型号出来,这个IP核基本未变,可见这个IP核的设计是相当成熟的。本文所讲述的内容属于这个IP核的一部分,掌握了本文所讲内容,就可以很方便地适用于所有STM32系列中包含bxCAN外设的型号。有关bxCAN的过滤器部分的内容在参考手册中往往看得“不甚明白“,本文就过滤器的4种工作模式进行详细讲解并使用具体的代码进行演示,这些代码都进行过实测验证通过的,希望能给读者对于bxCAN过滤器有一个清晰的理解。
在这里,我们可以将CAN总线看成一个广播消息通道,上面传输着各种类型的消息,好比报纸,有体育新闻,财经新闻,政治新闻,还有军事新闻,每个人都有自己的喜好,不一定对所有新闻都感兴趣,因此,在看报纸的时候,一般人都是只看自己感兴趣的那类新闻,而过滤掉其他不感兴趣的内容。那么我们一般是怎么过滤掉那些不感兴趣的内容的呢?下面有两种方法来实现这个目的:
第一种方法:
每次看报纸时,你都看下每篇文章的标题,如果感兴趣则继续看下去,如果不感兴趣,则忽略掉。
第二种方法:
你告诉邮递员,你只对财经新闻感兴趣,请只将财经类报纸送过来,其他的就不要送过来了,就这样,你看到的内容必定是你感兴趣的财经类新闻。
上面那种方法好呢?很明显,第二种方法是最好的,因为你不用自己每次判断哪些新闻内容是你感兴趣的,可以免受“垃圾”新闻干扰,从而可以节省时间忙其他事。bxCAN的过滤器就是采用上述第二种方法,你只需要设置好你感兴趣的那些CAN报文ID,那么MCU就只能收到这些CAN报文,是从硬件上过滤掉,完全不需要软件参与进来,从而节省了大大节省了MCU的时间,可以更加专注于其他事务,这个就是bxCAN过滤器的意义所在。
2.2.两种过滤模式(列表模式与掩码模式)假设我们是bxCAN这个IP的设计者,现在由我们来设计过滤器,那么我们该如何设计呢?
首先我们是不是很快就会想到只要准备好一张表,把我们需要关注的所有CAN报文ID写上去,开始过滤的时候只要对比这张表,如果接收到的报文ID与表上的相符,则通过,如果表上没有,则不通过,这个就是简单的过滤方案。恭喜你!bxCAN过滤器的列表模式采用的就是这种方案。
但是,这种列表方案有点缺陷,即如果我们只关注一个报文ID,则需要往列表中写入这个ID,如果需要关注两个,则需要写入两个报文ID,如果需要关注100个,则需要写入100个,如果需要1万个,那么需要写入1万个,可问题是,有这个大的列表供我们使用吗?大家都知道,MCU上的资源是有限的,不可能提供1万个或更多,甚至100个都嫌多。非常明显,这种列表的方式受到列表容量大小的限制,实际上,bxCAN的一个过滤器若工作在列表模式下,scale为32时,每个过滤器的列表只能写入两个报文ID,若scale为16时,每个过滤器的列表最多可写入4个CAN ID,由此可见,MCU的资源是非常非常有限的,并不能任我们随心所欲。因此,我们需要考虑另外一种替代方案,这种方案应该不受到数量限制。
下面假设我们是古时候一座城镇的守卫,城主要求只有1156年出生的人才可以进城,我们又该如何执行呢?假设古时候的人也有类似今天的身份证(...->_<-…),大家都知道,身份份证号码中有4位是表示出生年月,如下图:
图 1 18位身份证号码的各位定义
如上图,身份证中第7~10这4位数表示的是出生年份,那么,我们可以这么执行:
检查想要进城的所有人的身份证号码的第7~10位数字,如果这个数字依次为1156则可以进入,否则则不可以,至于身份证号码的其他位则完全不关心。假如过几天城主放宽进城条件为只要是1150年~1160前的人都可以进城,那么,我们就可以只关注身份证号码的第7~9这3位数是否为115就可以了,对不对?这样一来,我们就可以非常完美地执行城主的要求了。
再变下,假设现在使用机器来当守卫,不再是人来执行这个“筛选”工作。机器是死的,没有人那么灵活,那么机器又该如何执行呢?
对于机器来说,每一步都得细化到机器可以理解的程度,于是我们可以作如下细化:
第一步:获取想进城的人的身份证号码
第二步:只看获取到身份证的第7~9位,其他位忽略
第三步:将忽略后的结果与1156进行比较
第四步:比较结果相同则通过,不同则不能通过
这种方式,我们称之为掩码模式。
2.3.验证码与屏蔽码仔细查看上面4个步骤,这不就是C代码中的if语句吗?如下:
if(x&y==z)//x表示待检查身份证号码,y表示只关注第7~9位的屏蔽码,Z则为1156,这里叫做验证码
{
//可以通过
}
else
{
//不可以通过
}
对于机器来说,我们要为它准备好两张纸片,一片写上屏蔽码,另一片纸片写上验证码,屏蔽码上相应位为1时,表示此位需要与验证码对应位进行比较,反之,则表示不需要。机器在执行任务的时候先将获取的身份证号码与屏蔽码进行“与”操作,再将结果与验证码的进行比较,根据判断是否相同来决定是否通过。整个判别流程如下所示:
图 2 掩码模式的计算过程
从上图可以很容易地理解屏蔽码与验证码的含义,这样一来,能通过的结果数量就完全取决于屏蔽码,设得宽,则可以通过的多(所有位为0,则不过任何过滤操作,则谁都可以通过),设得窄,则通过的少(所有位设为1,则只有一个能通过)。那么知道这个有什么用呢?因为bxCAN的过滤器的掩码模式就是采用这种方式,在bxCAN中,分别采用了两个寄存器(CAN_FiR1,CAN_FiR2)来存储屏蔽码与验证码,从而实现掩码模式的工作流程的。这样,我们就知道了bxCAN过滤器的掩码模式的大概工作原理。
但是,我们得注意到,采用掩码模式的方式并不能精确的对每一个ID进行过滤,打个比方,还是采用之前的守卫的例子,假如城主要求只有1150~1158年出生的人能通过,那么,若我们还是才用掩码模式,那么掩码就设为第7~9位为”1”,对应的,验证码的7~9位分别为”115”,这样就可以了。但是,仔细一想,出生于1159的人还是可以通过,是不是?但总体来说,虽然没有做到精确过滤,但我们还是能做到大体过滤的,而这个就是掩码模式的缺点了。在实际应用时,取决于需求,有时我们会同时使用到列表模式和掩码模式,这都是可能的。
综合之前所述,下面我们来对比一下列表模式与掩码模式这两种模式的优缺点。
1986 年德国电气商BOSCH公司开发出面向汽车的CAN 通信协议,刚开始的时候,CAN ID定义为11位,我们称之为标准格式,ISO11898-1标准中CAN的基本格式如下图所示:
图 3 标准CAN报文格式定义
如上图所示,标准CAN ID存放在上图ID18~ID28中,共11位。随着工业发展,后来发现11位的CAN ID已经不够用,于是就增加了18位,扩展CAN ID到29位,如下图所示:
图 4 扩展CAN报文格式定义
从上图对比扩展CAN报文与标准CAN报文,发现在仲裁域部分,扩展CAN报文的CAN ID包含了base Identifier与extension Identifier,即基本ID与扩展ID,而标准CAN报文的CAN ID部分只包含基本ID,扩展ID(ID0~ID17)被放在基本ID的右方,也就是说,属于低位。知道这些有什么用呢?至少我们可以得到这两条信息:
标准ID一般小于或等于<=0x7FF(11位),只包含基本ID。
对于扩展CAN的低18位为扩展ID,高11位为基本ID。
例如标准CAN ID 0x7E1,二进制展开为0b 0[111 1110 0001],只有中括号内的11位才有效,其全部是基本ID。
再例如扩展CAN ID 0x1835f107,二进制展开为0b 000[1 1000 0011 10][01 11110001 0000 0111],只有红色中括号和绿色中括号内的位才有效,总共29位,左边红色中括号中的11位为基本ID,右边绿色中括号内的18位为扩展ID,请记住这个信息!知道这个之后,我们可以很方便地将一个CANID拆分成基本ID和扩展ID,这个也将在后续的内容中多次用到,再次留意一下,扩展ID是位于基本ID的右方,在扩展CAN ID的构成中,扩展ID位于低18位,而基本ID位于高11位,于是要获取一个扩展CANID的基本ID,就只需要将这个CANID右移18位(这种算法后续将多次用到,请务必记住!)。
3. bxCAN的过滤器的解决方案终于进入到正题了!前面已经介绍了过滤器的列表模式与掩码模式,以及掩码模式下的屏蔽码与验证码的含义,还介绍了标准CAN ID与扩展CAN ID的组成部分。现在我们终于要站在bxC