CAN (Controller Area Network )是 ISO 国际标准化的串行半双工异步(位时序同步)通信协议。
(1)由于系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个 LAN,进行大量数据的高速通信”的需要。
1986 年德国电气商博世公司开发出面向汽车的 CAN 通信协议。此后,CAN 通过 ISO11898 及ISO11519 进行了标准化,现在在欧洲已是汽车网络的标准协议。
其中 ISO11898是针对通信速率为125Kbps~1Mbps 的高速通信标准,而 ISO11519-2是针对通信速率为 125Kbps以下的低速通信标准。
(2)CAN 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设备、工业设备等方面。现场总线是当今自动化领域技术发展的热点之一,被誉为自动化领域的计算机局域网。它的出现为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有力的技术支持。
(3)CAN 控制器根据两根线(CAN_H、CAN_L)上的电位差,产生的差分信号
来判断总线电平。
多主控制:在总线空闲时,所有单元都可以发送消息。
1)两个以上的单元(uint)同时开始发送消息时,根据标识符(Identifier 称为 ID)决定优先级
。
注意:ID 并不是表示发送的 目的地址,而是表示访问总线时消息的优先级。
2)两个以上的单元同时开始发送消息时,对各消息 ID 的每个位进行逐个仲裁比较。
仲裁获胜,即判定比较时优先级最高的单元可继续发送消息,仲裁失利的单元则立刻停止发送,立刻转为接收状态。
系统的柔软性:表示与总线相连的单元没有类似于“地址”的形式。
因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。
最高 1Mbps:距离小于 40M
最远可达 10KM:速率低于 5Kbps
所有单元都可以检测错误(错误检测功能)
:
检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。
强制结束发送的单元会 不断反复地 重新发送此消息 直到成功发送为止(错误恢复功能)。
故障封闭功能:CAN 可以判别出总线上的错误类型,区分总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。
由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。
CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的,但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。
降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。
正是因为 CAN 协议的这些特点,使得 CAN 特别适合工业过程监控设备的互连,因此,越来越受到工业界的重视,并已公认为最有前途的现场总线之一。
隐性电平(Recessiveness -简称 R):逻辑值0,CAN_H 和 CAN_L 之差为 2.5V 左右。
显性电平(Dominance -简称 D):逻辑值1,CAN_H 和 CAN_L 之差为 0V。
在总线上显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。而隐形电平则具有包容的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)。
协议规范,这么设计是有一定的技巧的:
显性或者隐性的优先级可以看成是每个 CAN单元unit 与 CAN总线Bus 通信时,电平逻辑关系 相与&的关系
。
(1)显性电平(电平 = 0)优先级高是因为 CAN独立单元 和 CAN总线相与&后,把CAN总线的电平,也同时拉低了。只要有一个 CAN独立单元为显性电平,则整个CAN总线就被拉高。
(2)但是CAN独立单元隐形电平(电平 = 1)和 CAN总线相与&后,CAN总线电平状态保持不变。因此只有所有的CAN独立单元全为隐形电平时,CAN总线电平才为隐性电平。
另外,在 CAN 总线的起止端都有一个 120Ω终端电阻来做阻抗匹配,以减少回波反射。
注意:120Ω的终端电阻,在CAN通信中是必不可少的。因为很多情况下,CAN通信在正常模式调试时,
MCU片上CAN设备接收不到消息,有一种失败原因是CAN分析仪上面的 120Ω终端电阻拨片没有打开ON。
数据帧和遥控帧有标准格式和扩展格式两种格式。
标准格式有 11 个位的标识符ID,扩展格式有 29 个位的标识符ID
帧类型基本上就是消息类型,也就是报文的各种格式规范。
此部分CAN协议详细理论介绍请下载文档:
https://pan.baidu.com/s/1KGlG1u_ew7VFnpJqF3oJeQ
密码:vcfg
如果链接失效,请下载正点原子的参考资料,在 软件资料->CAN学习资料,有CAN理论入门PDF。
STM32F4 自带的是 bxCAN,即基本扩展 CAN。它支持 CAN 协议 2.0A 和 2.0B。
它的设计目标是:以最小的 CPU 负荷来高效处理大量收到的报文。
它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用,bxCAN 提供所有支持时间触发通信模式所需的硬件功能。
过滤器(筛选器)的作用是:减少了 CPU 处理 CAN 通信的开销
。此部分内容参考文章: 过滤器.
(1)为什么要使用 过滤器(filter)?
在这里,我们可以将CAN总线看成一个广播消息通道,上面传输着各种类型的消息,好比报纸,有体育新闻,财经新闻,政治新闻,还有军事新闻,每个人都有自己的喜好,不一定对所有新闻都感兴趣,因此,在看报纸的时候,一般人都是只看自己感兴趣的那类新闻,而过滤掉其他不感兴趣的内容。那么我们一般是怎么过滤掉那些不感兴趣的内容的呢?下面有两种方法来实现这个目的:
(1)第一种方法:
(2)第二种方法:
那么上面那种方法好呢?很明显,第二种方法是最好的,因为你不用自己每次判断哪些新闻内容是你感兴趣的,可以免受“垃圾”新闻干扰,从而可以节省时间忙其他事。bxCAN的过滤器就是采用上述第二种方法,你只需要设置好你感兴趣的那些CAN报文ID,那么MCU就只能收到这些CAN报文,是从硬件上过滤掉,完全不需要软件参与进来,从而节省了大大节省了MCU的时间,可以更加专注于其他事务,这个就是bxCAN过滤器的意义所在。
(2)假设我们是bxCAN的设计者,现在由我们来设计过滤器,那么我们该如何设计呢?
首先我们是不是很快就会想到只要准备好一张表,把我们需要关注的所有CAN报文ID写上去,开始过滤的时候只要对比这张表,如果接收到的报文ID与表上的相符,则通过,如果表上没有,则不通过,这个就是简单的过滤方案。恭喜你!bxCAN过滤器的列表模式
采用的就是这种方案。
但是,这种列表方案有点缺陷,即如果我们只关注一个报文ID,则需要往列表中写入这个ID,如果需要关注两个,则需要写入两个报文ID,如果需要关注100个,则需要写入100个,如果需要1万个,那么需要写入1万个,可问题是,有这个大的列表供我们使用吗?大家都知道,MCU上的资源是有限的,不可能提供1万个或更多,甚至100个都嫌多。非常明显,这种列表的方式受到列表容量大小的限制。
实际上,bxCAN的一个过滤器如果工作在列表模式下,数值范围scale为32时,每个过滤器的列表只能写入两个报文ID;若scale为16时,每个过滤器的列表最多可写入4个CAN ID。由此可见,MCU的资源仍是非常有限的并不能被我们随心所欲的使用。这种指定ID的方式虽然很精确但是效率太低,有些太死板。因此需要考虑另外一种替代方案,即ID不受到数量的限制:掩码模式
。
(3)过滤器引入 标识符掩码模式(屏蔽位模式)
下面假设我们是古时候一座城镇的守卫,城主要求只有1156年出生的人才可以进城,我们又该如何执行呢?假设古时候的人也有类似今天的身份证(…->_<-…),大家都知道,身份份证号码中有4位是表示出生年月,身份证中第7~10这4位数表示的是出生年份,那么,我们可以这么执行:
再变下,假设现在使用机器来当守卫,不再是人来执行这个“筛选”工作。机器是死的,没有人那么灵活,那么机器又该如何执行呢?
对于机器来说,每一步都得细化到机器可以理解的程度,于是我们可以作如下细化:
第一步:获取想进城的人的身份证号码
第二步:只看获取到身份证的第7~9位,其他位忽略
第三步:将忽略后的结果与1156进行比较
第四步:比较结果相同则通过,不同则不能通过
这种方式,我们称之为掩码模式,即屏蔽位模式
(4)标识符掩码模式(屏蔽位模式)的过程
对于机器来说,我们要为它准备好两张纸片,一片写上屏蔽码,另一片纸片写上验证码,屏蔽码上相应位为1时,表示此位需要与验证码对应位进行比较,反之,则表示不需要。机器在执行任务的时候先将获取的身份证号码与屏蔽码进行 “&” 与操作,再将结果与验证码的进行比较,根据判断是否相同来决定是否通过。整个判别流程如下所示:
从上图可以很容易地理解屏蔽码与验证码的含义,这样一来,能通过的结果数量就完全取决于屏蔽码,屏蔽码设置地得宽,则可以通过的多(所有位为0,则不过任何过滤操作,则谁都可以通过),设得窄,则通过的少(所有位设为1,则只有一个能通过)。
那么知道这个有什么用呢?因为bxCAN 过滤器的掩码模式就是采用这种方式。因为在bxCAN中,分别采用了两个寄存器(CAN_FxR1,CAN_FxR2)来存储屏蔽位码与验证位码
,从而实现掩码模式的工作流程的。因此这样,我们就可以知道bxCAN过滤器掩码模式的大概工作原理。
但是,我们得注意到,掩码模式的缺点:采用掩码模式的方式并不能精确的对每一个ID进行过滤。打个比方,还是采用之前的守卫的例子,假如城主要求只有1150-1158年出生的人能通过,那么,若我们还是才用掩码模式,那么掩码就设为第7-9位为”1”,对应验证码的7~9位分别为”115”,这样就可以了。
但是,仔细一想,出生于1159的人还是可以通过,是不是?但总体来说,虽然没有做到精确过滤,但我们还是能做到大体过滤的,而这个就是掩码模式的缺点了。在实际应用时,取决于需求,有时我们会同时使用到列表模式和掩码模式。
先简单介绍一下配置过滤器时,需要用到的寄存器:
(1)CAN_FMR 筛选器主寄存器
主CAN1、从CAN2 都分别拥有自己的发送邮箱 mailbox和接收 FIFO,它们一起共用 28 个滤波器组。这28 个滤波器组是通过 CAN_FMR 寄存器的配置可以设置滤波器的分配方式。也就是主CAN1、从CAN2谁都可以用到哪些寄存器组。
(2)CAN_FiRx 筛选组寄存器
STM32F4 的过滤器组(即筛选器 filter)最多有 28 个,每个滤波器组 x 由 2 个 32 位的寄存器:
CAN_FxR1 和 CAN_FxR2 组成:
(3)CAN_FS1R 筛选器尺度寄存器
STM32F4中,每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。
根据位宽的不同,每个过滤器组可提供:
● 1 个 32 位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE 和 RTR 位
● 2 个 16 位过滤器,包括:STDID[10:0]、IDE、RTR 和 EXTID[17:15] 位
(4)CAN_FM1R 筛选器模式寄存器
此外,过滤器还可配置模式为:标识符屏蔽位模式 或 标识符列表模式
在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此不是采用一个标识符加一个屏蔽位的方式,而是使用 2 个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。
根据模式与位宽的设置,我们共可以得出4中不同的组合:
32位宽的列表模式,16位宽的列表模式;
32位宽掩码模式,16位宽的掩码模式;
如下图所示:
为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。
为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。
应用程序不用的过滤器组,应该保持在禁用状态。
在bxCAN中,每组过滤器都存在这么两个寄存器CAN_FxR1和CAN_FxR2,这两个寄存器都是32位的,他的定义并不是固定的,针对不同的工作模式组合他的定义是不一样的:
(1)32位宽模式下
如列表模式-32位宽模式下,这两个过滤器寄存器的各位定义都是一样的,都用来存储某个具体期望通过的CAN ID,这样就可以存入2个期望通过的CAN ID(标准CAN ID和扩展CAN ID均可);
若在掩码模式-32位宽模式下时,则CAN_FxR1用做32位宽的验证码(比较码),而CAN_FxR2则用作32位宽的屏蔽码。
(2)在16位宽模式下
CAN_FxR1和CAN_FxR2都要各自拆分成两个16位宽的寄存器来使用。
在列表模式-16位宽模式下,CAN_FxR1和CAN_FxR2定义一样,且各自拆成两个,则总共可以写入4个标准CAN ID,
若在16位宽的掩码模式下,则当做 2对验证码 + 屏蔽码组合来用,但它只能对标准CAN ID进行过滤。
bxCAN 主要有三种工作模式: 初始化(Initialize)、 正常(Normal)和睡眠(Sleeping,低功耗)
这三种模式相关的寄存器是:CAN_MSR主状态寄存器 和 CAN_MCR主控制寄存器
设置CAN_MCR主控制寄存器相应位:
SLEEP / INRQ 请求进入初始化,正常,睡眠模式
设置CAN_MSR寄存器相应的位:
bxCAN启动过程:
在硬件复位Reset或者上电重启时,bxCAN 首先进入睡眠模式以降低功耗,此时SLAK = 1,INAK = 0。
可以通过软件设置CAN_MCR主控制寄存器,SLEEP(睡眠模式请求 :Sleep mode request)或者INRQ(初始化请求:Initialization request),将相应位置1即可使bxCAN 进入初始化模式或者睡眠模式。
正常流程是先进入初始化模式,一旦进入初始化模式,硬件自动将bxCAN的主状态寄存器CAN_MSR设置为SLAK = 0,INAK =1,以确认初始化模式。随后在此模式下,可以进行相关寄存器的初始化配置。
配置完成之后,一方面可以设置CAN_MCR主控制寄存器的SLEEP / INRQ进入正常模式,或者继续返回到低功耗睡眠模式。
在进入到正常模式下,硬件自动将bxCAN的主状态寄存器CAN_MSR设置为SLAK = 0,INAK = 0,以确认初始化模式。CAN进行正常工作状态,发送或者接收报文。
测试模式:环回模式,静默模式,环回与静默组合模式
详细请参考,STM32参考手册
CAN邮箱发送时需设置的寄存器
(1)CAN 发送状态寄存器 (CAN_TSR)
RQCPx : 邮箱 x 请求完成 (Request completed mailbox x)
最后一个请求(发送或中止)执行完毕时,由硬件置 1。由软件通过写入“1”清零,或是在发生发送请求(CAN_TI1R 寄存器中的 TXRQx位)时由硬件清零。
如果将此位清零,邮箱 x 的所有状态位(TXOK1、ALST1 和 TERR1)都将清零。
TXOKx :邮箱 x 发送成功 (Transmission OK of mailbox x)
每次发送成功后,硬件都将更新此位。
0:上一次发送失败
1:上一次发送成功
当邮箱 x 的发送请求成功完成时,此位由硬件置 1。
TMEx : 发送邮箱 x 为空状态 (Transmit mailbox x empty)
当 x 邮箱为空,即邮箱没有挂起发送请求时,硬件自动置1。
ABRQx :邮箱 x 中止请求 (Abort request for mailbox x)
由软件置 1,用于中止相应邮箱的发送请求。
邮箱变为空后,此位由硬件清零。邮箱未挂起等待发送时,将此位置 1 没有任何作用。
(2)CAN 发送邮箱标识符寄存器(CAN_TIxR)
最开始发送报文时,x邮箱TMPx = 1 表示邮箱内容为空,此时需要把报文(数据帧等)填充 x发送邮箱,紧接着将 TXRQ = 1,请求发送x邮箱中的内容,此时 x邮箱 进入挂号(挂起 pending)状态,等待成为优先级最高的邮箱,相应的状态寄存器的TMPx位清零,表明x邮箱有数据不为空。
此过程可以被中止ABRQx = 1,中止相应邮箱的发送请求,进入发送失败状态,邮箱置空 TMPx = 1;RQCPx = 1;TXOKx = 0.
此后由调度器统一调度选择具有最高优先级的邮箱,安排发送。当x邮箱成为优先级最高的邮箱时,会将邮箱内的数据进行打包(报文),待CAN 总线变为空闲后,被安排好的邮箱将开始发送报文(进入发送态)。邮箱一旦发送成功,则邮箱立即恢复 空状态TMPx = 1;RQCPx = 1;TXOKx = 1.
如果发送失败,失败原因将由 CAN_TSR 寄存器的 ALST位( 邮箱 x 仲裁丢失)和 TERR位 (邮箱x 发送错误)提示,进入发送失败状态,邮箱置空 TMPx = 1;RQCPx = 1;TXOKx = 0.
如果设置了自动重发送模式,则会重新回到等待调度器再次调度重发。
通过CAN_TOOL和CAN分析仪测试发现:
0、0x7FF / 0x1FFF FFFF 为独立单一的can_id
(1)配置情形1
配置一 配置二 配置三
filter_id 0 0 0x7FF / 0x1FFFFFFF
mask_id 0 0x7FF / 0x1FFFFFFF 0
只要 filter_id / mask_id 有一个配置为0,则过滤器组将会使所有id都可以通过过滤,不屏蔽任何id,任何id都可以通过筛选。
(2)配置情形2
配置
filter_id 0x7FF / 0x1FFFFFFF
mask_id 0x7FF / 0x1FFFFFFF
此时过滤器可以屏蔽所有id,不让任何id通过筛选(包括 0 和 0x7FF / 0x1FFFFFFF)。这种模式可以用于过滤器不想使用(即关闭过滤器)时,全部以 0x7FF / 0x1FFFFFFF 填充 filter_id 和 mask_id 对应的2组寄存器。