目录
[1.1 CAN外设简介](#1.1 CAN外设简介)
[1.2 CAN网拓扑结构](#1.2 CAN网拓扑结构)
[1.3 CAN外设的引脚分布](#1.3 CAN外设的引脚分布)
[1.4 外围电路](#1.4 外围电路)
[2.1 CAN框图](#2.1 CAN框图)
[2.2 CAN外设基本结构](#2.2 CAN外设基本结构)
[2.3 收发流程细节](#2.3 收发流程细节)
[2.3.1 发送流程](#2.3.1 发送流程)
[2.3.2 接收流程](#2.3.2 接收流程)
[2.3.3 接收/发送配置位](#2.3.3 接收/发送配置位)
[2.4 标识符过滤器](#2.4 标识符过滤器)
[2.4.1 核心寄存器概述](#2.4.1 核心寄存器概述)
[2.4.2 过滤器设计规则](#2.4.2 过滤器设计规则)
[2.5 测试模式](#2.5 测试模式)
[2.5.1 静默模式](#2.5.1 静默模式)
[2.5.2 环回模式](#2.5.2 环回模式)
[2.5.3 环回静默模式](#2.5.3 环回静默模式)
[2.6 工作模式](#2.6 工作模式)
[2.6.1 三种工作模式](#2.6.1 三种工作模式)
[2.6.2 状态转换分析](#2.6.2 状态转换分析)
[2.7 位时间特性](#2.7 位时间特性)
[2.8 中断处理](#2.8 中断处理)
[2.9 时间触发通信](#2.9 时间触发通信)
[2.10 错误处理与时间恢复](#2.10 错误处理与时间恢复)
本部分借助一款32位单片机来介绍一下单片机中的CAN外设的使用方法,本次使用的单片机型号是STM32F103C8T6。
**一、**CAN 外设概述
1.1 CAN****外设简介
(1)STM32内置bxCAN 外设( CAN 控制器),支持 CAN2.0A 和 2.0B ,可以自动发送 CAN 报文和按照过滤器自动接收指定 CAN 报文,程序只需处理报文数据而无需关注总线的电平细节。

STM32上的CAN外设是芯片内部通过硬件电路实现 的,内置的是bxCAN外设,是一种CAN控制器。其中bx即基本扩展 的意思,表示其可以支持标准格式和扩展格式。同时,bxCAN支持 CAN 协议 2.0A 和 2.0B,意味着不仅支持旧版的CAN协议标准,还兼容升级后的扩展版本。
因为bxCAN外设是STM32的片上外设,所以设计时包揽了整个CAN协议的设计,我们只需要学会数据的收发流程和处理方法,其他内容细节都可以有STM32硬件自动完成,大大降低了使用的复杂性。
(2)波特率最高可达 1 兆位 / 秒, 3 个可配置优先级的发送邮箱, 2 个 3 级深度的接收 FIFO , 14 个过滤器组(互联型 28 个)。
STM32中的CAN外设波特率最高为1Mbps,对应前面介绍的CAN总线符合高速CAN的传输速率,因此STM32是完美支持高速CAN收发的。
发送邮箱可以理解成发送缓冲区,并带有可配置的优先级。STM32提供了3个这样的发送邮箱,可放置发送的报文。
接收FIFO可以理解成接收缓冲区,3级深度意思是可以存放三个接收报文,然后STM32提供了2个这样的FIFO,因此一个可以存放6个接收数据。
另外,STM32还提供了过滤器组,这是用于过滤报文ID的,因为CAN总线设备一般广播式发送,所以所有发送的数据都可以被接受。但是我们不一定需要接受所有的数据,所以可以通过设置过滤报文ID来过滤掉部分报文ID对应的数据。其中本次介绍的这款STM32提供了14个,然后互联型的STM32有28个。
(3)时间触发通信、自动离线恢复、自动唤醒、禁止自动重传、接收 FIFO 溢出处理方式可配置、发送优先级可配置、双 CAN 模式。
此外,STM32的CAN外设还有其特别的功能,这些功能初学时一般也不怎么使用,因此后面简单了解一下就行。
(4)STM32F103C8T6 CAN 资源: CAN1
对于本次使用的这款STM32F103C8T6而言,其内置的CAN外设只有一个,即CAN1。
至此,对于STM32中的CAN外设基本概述就介绍了,后面再继续详细介绍CAN外设的这些相关功能和特性,学习如何通过控制STM32的CAN控制器去发送我们希望的报文并接受其他设备发来的报文等内容。
1.2 CAN****网拓扑结构
接下来,看看STM32中CAN的外围电路,首先是手册中提到的CAN网络拓扑结构,如下图所示。

经过前面对于CAN总线的介绍,这张图应该很容易理解了。每一个CAN结点都是由设备上的一个CAN控制器与CAN收发器通过引出的串口相连,然后收发器与CAN总线上的差分线相连。其中CAN控制器一般是MCU内部的CAN控制器,对于STM32就是其bxCAN外设。同时,CAN总线上挂载多个结点也都是这样的结构。
1.3 CAN****外设的引脚分布
由于本次介绍的STM32F103C8T6只有CAN1一个外设,因此只有一对CAN串口引脚,如下图所示。

默认情况下,可以直接复用PA11和PA12的CAN外设功能,去使用对应的串口引脚。同时,还有重映射引脚,可以使用CAN功能,如下图所示。

1.4****外围电路
由于整个电路中还需要使用CAN收发器,因此这里再简单介绍一下CAN收发器的电路设计。以TJA1050 收发器芯片去介绍,后续实验使用的也是这款芯片。关于他的基本原理我们已经在前面介绍过。
首先介绍一下TJA1050芯片手册提供的参考应用电路设计图。

可以看出,这个电路还是比较简单的。收发器芯片的TX和RX与CAN控制器引出的TX和RX对应相连,千万不是交叉相连,与USART区分。
然后CANL 和 CANH 分别串联一个 120Ω 的终端电阻形成一个 CAN 总线网络,其他设备也是直接连接在这上面。
接着是电源引脚。GND直接接地,VCC接+5V,千万不要接3.3V,不然不符合CAN总线电平标准,可能导致通信异常。然后+5V输入时并联了大小电容,用于电源滤波。
接着,我们再看看实际的CAN收发器模块的电路设计。因为本次使用的是一款TJA1050收发器模块,且实际电路设计与手册提供的电路有一些差异,可能是别人设计的时候根据经验增加的。

从左往右来看,首先是一个排针,引出了电源引脚VCC和GND以及CAN串口引脚TX和RX。
然后收发器芯片引出CAN串口TX和RX,即连接到对应引脚排针上。然后电源引脚也是连接到引出的排针上,同时并联了一颗100nF的电源滤波电容。
接着收发器芯片的CANL和CANH即差分线连接到接线端子,中间先是分别串联了一个0欧电阻,然后并联了一颗30pF的电容,接着就是在差分线两端接了一个120Ω的终端电阻。其中关于为什么要多加0欧电阻和30pF的电容,这可能是设计者经验吧,让差分信号更加平滑稳定一些。
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 这里需要注意的是,理论上来说,CAN 总线网络上应该只有两个终端电阻,否则不符合 CAN 总线设计要求。而这里每接一个收发器,实际上就会多一个终端电阻,所以当连接了2个以上的收发器模块时,其实最好应该只留2个终端电阻,去掉多的终端电阻。但是为了便于实验以及不增加实验复杂性,就没有去掉。当然,实际总线上出现3个终端电阻时,总线通信还是可以正常的进行,只是后续实际开发时,还是需要注意这个问题。 同时就是理论上,CAN 总线差分信号应该使用 120Ω 阻抗匹配的双绞线去连接设备的,但是实际上这里我们也没有,其实也不太符合要求,只是实验能够正常看见现象。但是后面还是需要注意一下这个问题。 |
最后,再看一下这个CAN收发器模块的实物图。

至此,关于CAN的外围电路就介绍完毕了。
**二、**CAN 外设详细介绍
接下来,我们学习一下STM32中对于CAN外设的设计。
2.1 CAN****框图
首先了解一下CAN外设的功能框图,可以在STM32参考手册中的bxCAN章节找到,如下图所示。

该图描述了STM32中CAN外设的整体结构,当然这里描述的是互联型的CAN外设,也就是多了一个CAN2。在互联型产品中,CAN外设分成了主CAN即CAN1和从CAN即CAN2两部分,CAN2会辅助CAN1工作,两者共同去完成一个CAN总线的工作。
但是,本次介绍的芯片只有CAN1,所以下面部分的CAN2就不需要看了,即如下图所示是本次介绍的重点。

整个框图比较简单,展示了CAN总线收发过程的大致流程。
从左边看,首先是一对控制或配置寄存器,这就是用于配置CAN外设和发送控制指令的东西,通过软件读写这些寄存器,就可以去正确使用CAN外设进行一下功能。
接着是CAN2.0B 主动核心,会与存储器和读写控制器进行交互,我们需要发送的数据首先会放到主发送邮箱中,这里图示有三个,避免要发送的太快结果丢失一些报文。然后发送时将邮箱里面的的数据通过发送调度合理送进存储器和读写控制器自动处理。
当接收数据时,收到的报文会经过存储器读写控制器 过来,先给接受滤波器进行过滤处理,因为并不是所有数据都一定需要,可以根据实际情况设置接受滤波器,将某些不需要的报文通过滤波器过滤掉。一方面可以减少无用报文的接收,避免接收FIFO占用;另一方面也可以减轻程序的负担。
通过过滤的报文会给到主接收 FIFO0 或主接收 FIFO1 中,接收FIFO相当于队列,一个队列可以放3分报文,也就是可以排3个,总共两个队伍,即总共可以放6个报文。通过设置接收FIFO,可以一定程度上避免因为接收的数据来得太快导致的数据覆盖或丢失问题。
以上就是这个CAN外设框图传递的一些信息了,关于整个收发传输细节,这里其实并不明显。
2.2 CAN****外设基本结构
接着,我们再借助一张图总结一下CAN外设的基本结构。

从最上面看,CAN控制器引出CAN_TX和CAN_RX,根据STM32引脚定义,CAN_TX 对应 PA12 , CAN_RX 对应 PA11 。沿着线路深入硬件内部,我们首先要配置GPIO,由于CAN_TX 是发送即输出引脚,此时 CAN 总线控制权在 CAN 外设,所以 PA12 需要配置为复用推挽输出模式, CAN_RX 是接收引脚即输入,所以可以配置为上拉输入。
接着,数据通过TX或RX会经过发送接收控制器,且CAN 通信的相关处理都由这个发送和接收控制器全权管理,可以认为他是一个非常强大的管理员。你想发什么报文,只需要把报文内容告诉它,它就可以自动给发出去。同样当它接收到一个报文后,它也会自动和你配置的过滤器进行比较,符合过滤器的报文,它自动帮你存入接收FIFO的队列之中,此时CPU直接读取接收FIFO就行了。

所以说通过MCU去操作CAN总线时,绝大多数的工作都被发送 / 接收控制器这个管理员帮我们完成了,而我们编写的程序只需要告诉他我们想发出什么报文或读取它帮我们存入到FIFO里的接收报文就行了。
继续看下面的发送部分。当我们想发出一个报文时,我们只需把报文的各个参数比如报文ID、数据段、IDE、RTR等写入到其中一个发送邮箱,然后给一个请求发送的命令之后,这个管理员就会等待总线空闲,然后自动把这个报文广播到总线上。简单来看发送邮箱其实只需要一个,因为程序一次只会指定发送一个报文,所以发送邮箱只设计一个是没问题的。但是为了防止总线繁忙造成发送拥堵,导致上次写入的一个报文让管理员发出去,但是管理员迟迟等不到总线空闲,然后这个报文就在邮箱里滞留了很久。当CPU想再写入下一个报文时,这就没法存了,那这样CPU就也得被迫等待了。

所以为了避免短暂的拥堵造成CPU等待,STM32就设计了三个发送邮箱,分别是邮箱0、邮箱1和邮箱2。CPU想发送报文时,任意选一个空的邮箱写入报文请求发送,然后CPU就可以干别的事了。如果下次CPU又想发送了,然后看到上次的报文还在等待,那CPU就可以换另一个控制邮箱写入报文,再次请求发送。同样如果CPU第三次向发送,发现之前两个报文都还在等待,那CPU可以写入最后一个控制邮箱。当三个邮箱都写入报文了,CPU再向发送时,那没办法了,只能让CPU等待或者让CPU放弃本次发送了。
不过三个邮箱都写满了,看总线还没有出现空闲,说明CAN总线当前已经非常拥堵了,而一般情况下不会如此拥堵,所以当CPU写读一个邮箱后,这个待发送的报文都会在不久的时间内发出去,之后这个邮箱就释放出来了,重新变为空置邮箱。偶尔可能出现CPU发送过于频繁,然后上一个报文还没有发走的情况,这时三个邮箱就能提供缓冲区,减小 CPU 的等待时间,这就是这里设计三个邮箱的目的。
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 此外,如果有多个报文都在邮箱里等待发送,此时总线空闲,那么管理员会选择把哪个待发报文发出去呢? 实际上,发送部分可以设置发送策略。这个发送选择策略可以配置先请求先发送,或者按报文报文ID号优先级发送。先请求先发送就是先来后到,如果有多个代发的报文,那么谁先请求的谁就会优先发出。按报文ID号优先级,就是每次总线空闲了,管理员就会看一下三个邮箱,然后把其中报文ID号最小的先发出去。该策略可以根据实际需求去自己设置。 |
接着看右边的接收部分。当看总线出现任何一个数据帧或遥控帧的报文波形时,发送/接收控制器就会把这个报文收下来。但是总线上的报文各种各样,这个报文并不一定是我们这个设备需要的,所以这个报文收下来之后,按照这个箭头往后传递,经过的第一个处理就是接收过滤器。
过滤器可以根据报文 ID **号对报文进行过滤。**如果这个报文ID号并不是我们想要的,那么报文就通过不了过滤器,即这个报文就会直接丢弃,不会再向后传递了。这里过滤器总共有14个,在程序中我们可以对任意一个过滤器进行配置,把我们想要接收的报文ID规则写入到过滤器中,这样总线上一旦出现我们想要的报文,那么它就会通过其中某一个过滤器,进入到后续的FIFO之中,进而被CPU读取。

如果我们只需要几种类型的报文ID,那么使用几个过滤器就能够满足要求了,其他没有使用到的过滤器,我们不去配置它,它就默认处于失能的状态,自然也不会起作用。如果我们需要很多种类型的报文ID,那么就可以使用很多的过滤器,配置各种各样的过滤规则来满足我们的需求。
由于本次单片机的CAN外设总共有14个过滤器,可以允许我们配置很多的过滤规则,所以这个过滤器的功能还是非常强大的。有了硬件设计的过滤器,就节省了软件进行报文ID比对的工作,通过过滤器的报文就都是该设备所需要的报文,这是过滤器的作用和意义。
继续往后看,通过过滤器的报文会存储在下面两个接收 FIFO 中。FIFO即先进先出寄存器,简单说就是报文排队存放、等待CPU读取的位置。STM32设计了两个接收FIFO,即FIFO0和FIFO1,也就是有两个队伍,每个队伍都有三个邮箱,分别可以容纳三个报文进行排队等待被读取。

同时,在配置过滤器时,有参数可以指定通过对应过滤器的报文应该进哪一个 FIFO。也就是说通过滤波器的报文会经过两个箭头,根据实际设定,选择进FIFO0还是进FIFO1,这是一个二选一的通道。

比如,我们可以指定过滤器0出来的报文进FIFO0排队,过滤器1出来的报文进FIFO1排队,过滤器2出来的报文也进FIFO0排队。配置好之后,此时有个报文过来后经过过滤器比对,通过了过滤器0,那之后就会进入FIFO0。进FIFO0之后,如果其中的三个邮箱都是空的,那它直接排到最前面邮箱0的位置。之后若又有一个报文过来了,通过了过滤器2,则进入FIFO0,如果此时前面进来的报文还在邮箱0没有被读取掉,则后面这个报文就会紧跟着存入邮箱1。如果此时CPU还没有读取FIFO0,又来通过一个报文进FIFO0呢?那他就存入邮箱2,这时可以发现FIFO0的队伍就排满了。如果CPU还不读取FIFO0,又来了一个报文,那他就没地方存了。
这个时候STM32 可以配置 FIFO 的锁定状态来 处理,即FIFO 满之后新的报文的去向规则。如果配置了FIFO锁定,那么FIFO满之后新的报文会直接丢弃;如果配置FIFO不锁定,FIFO满之后,新的报文会把邮箱2的数据踢出去,自己占据邮箱2的位置,也就是覆盖末尾邮箱,这是队伍排满的处理方式。
因此,队伍排满后再来新报文时,必然会有报文丢失。要么是新来的丢失,要么是FIFO末尾的丢失。最后假如CPU读取了FIFO0,把邮箱0的报文读走了,那么邮箱1的报文就会向前存入邮箱0,邮箱2的报文也会向前存入邮箱1,此时队伍末尾邮箱2就空出来了,即可以存入新的接收报文。显然,这跟现实中的排队是一模一样的,来一个人后会紧跟着排队,队伍总是处理最前面一个人的需求,一旦队伍首位的人走了,那么后面的人就会整体往前上一个位置,进人都是从队伍末尾开始进,出人都是从队伍首位开始出,自然这个过程就是先来后到,先进先出,这也是FIFO的得名原因。
到这里,我们就清楚了FIF0的排队规则。FIFO1 也是同理的,那么 FIFO0 和 FIFO1 组合起来就相当于食堂打饭,设立了两个窗口。对于不同的报文会选择进入不同的FIFO中,之后CPU可以用轮询或者中断的方法,依次检查FIF0和FIFO1的队伍长度,只要队伍里有报文长度大于0,那CPU就可以读取对应队伍中的报文,这样就完成了报文数据的读取。
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 为什么 STM32 设计了两个 FIFO 呢? 其实类比现实也能明白,食堂打饭为什么要设置多个窗口呢?主要是为了分散人流吧,更重要的是可以按照不同身份的种类去进行排队,比如说学生排队学生窗口,老师排队老师窗口,由于学生人相对会多不少,因此到了饭店食堂挤进了大量的学生,导致学生队伍排一长条,此时肯定有人吃饭就会被耽误。而这时如果给老师另设窗口,那么就能保证老师准时吃到饭。 这里也是一样,通过过滤器的报文可以指定到FIFO0排队或者FIFO1排队,这个队伍也不算长,最多只能排三个报文。如果短时间收到了大量报文,而CPU没有及时读走的话,队伍就很容易排满,排满之后就肯定会有报文丢失。如果我们所有报文全部只进一个队伍进行排队,那一般来说不重要的报文数量都还很大,重要的报文数量比较少,这样队伍排满后,大概率排到的都是不重要的报文,而重要的报文因为排不上队,大概率就会丢失,这是我们不想看到的。 这时我们就可以利用两个队伍对报文进行分流,不重要的报文排一个队伍,重要的报文排另一个队伍,这样重要报文丢失的概率就大大降低了,这就是这里设计两个队伍的目的。当然官方并没有给FIFO0 和 FIFO1 区分优先级,即实际这俩是平级的。不过我们可以自己给他们区分一下优先级,比如重要的进FIFO0,不重要的进FIFO1,或者按照报文种类或者报文接收的频率来分流两个队伍,主要根据实际项目需求进行即可。 |
最后再看发送部分里面也有三个邮箱,其实跟接收一样,也是排队。但是接收只有先来后到这一种排队方案,所以接收就直接叫做接收FIFO。而发送可以配置先来后到的方案,也可以配置按照报文ID号优先级决定处理顺序的方案,相当于可以根据优先级进行插队,所以发送部分更灵活。
如果发送配置的是先来后到的方案,那么发送部分就也可以叫发送FIFO。但发送的排队方案毕竟是可以配置的,并且它的排队流程和接收FIFO也不太一样,所以发送部分直接称作发送FIFO不太合适,故这里就称呼为发送邮箱。

但是需要注意的是,本质上发送和接收一样都是排队,即在数据写入频率大于数据处理频率时提供一段缓冲区域。比如数据处理的频率远大于数据写入频率时,CPU刚写入一个报文,管理员就立刻发出去了;接收时FIFO刚排一个报文,CPU就立刻读走了,这种情况下队伍就不会排起来。反之,数据写入频率大于数据处理频率时,报文就会在发送邮箱中堆积排队;接收时FIFO中一直有报文进来排队,那么这个时候显然就都是排队了。
至此,STM32中CAN外设与外界的数据收发大致流程就差不多清楚了。
2.3****收发流程细节
接下来,我们再补充一下发送数据和接收数据流程的细节。
2.3.1****发送流程
对于发送流程,其基本流程为:选择一个空置邮箱 → 写入报文 → 请求发送。根据手册描述有下图所示状态转换图。

该图描述了从空置邮箱到数据发送结束的一个状态变化。其中每个状态中都带有几个标志位,这些都是CAN外设相关寄存器中的某些位,不同状态下这些位会硬件自动置位或清除,我们可以通过读取和配置某些位来判断发送状态。
从上到下来看,首先是选择了一个空置邮箱。其中RQCP=X、TXOK=X、TME=1,X表示任意值。我们查询寄存器找到这些位看看。

即CAN_TSR发送状态寄存器中的某些位,如上图所示。通过复位值即上电默认值可以看出,TME2、TME1、TME0默认为1,其余都是0。接着我们关注一下最初状态中出现的3个状态位描述,如下图所示。

首先是RQCP位,这是邮箱请求完成标志位,当数据发生完成或终止发送时为1,反之则是0。换句话说,默认为0就行,即没有发送的状态。

然后是TXOK,即邮箱发送成功标志位,当发送请求发送成功时,该位会被置1,否则即发送尝试失败了就会被置0。

最后是TME位,即发送邮箱空标志位,即邮箱没有报文时是空的,此时该位置1,反之邮箱有报文时会被置0,因此初始上电时默认肯定是1。
继续,如下图所示,当TXRQ被置1时,就会进入挂号状态,此时RQCP=0、TXOK=0、TME=0,根据前面介绍也就是挂号状态下,还未发送,且发送还没有成功,且邮箱中已经写入报文数据。

TXRQ位我们同样查询手册看看。

可见这是发送邮箱标识符寄存器中的第0位,看看其描述是什么。

TXRQ即发送数据请求位,主要用于请求发送邮箱的数据。即当想要发送数据时,将TXRQ置1,就会将数据放到发送邮箱中,准备发送。然后数据发送完成,邮箱空了,该位会自动清除。
接着,当发送数据频繁时,可能同时有多个发送邮箱需要去发送数据,所以需要判断一下邮箱发送优先级。当然,前面介绍过发送邮箱优先级可以根据先来后到规则进行发送、也可以根据ID优先级进行发送,当根据先来后到规则时,则不需要判断优先级了,直接来了就发,此时会从挂起状态进入预定状态;当根据ID号优先级时,则ID小的会先进入预定状态,ID大的若已经在预定状态则会返回挂号状态。如下图所示。

进入预定状态后,由于其邮箱报文还没动静,也没正式发送,因此RQCP、TXOK、TME仍为0。预定状态相当于已经进入等待发送了,只需当总线空闲(CAN总线=IDLE)下来,就可以马上进入发送状态。
进入发送状态后,会存在多种情况,如下图所示。

进入发送状态后,若发送失败了,则可以选择重试发送或者直接终止发送,由NART位控制。我们看看手册关于NART的描述。

首先NART位是CAN主控制寄存器中的第4位,看该寄存器复位值可推断,上电后该位默认为0。继续看看该位的描述。

可见,NART位是禁止报文自动重传位,当置1时,CAN报文只允许发送一次,即发送失败后终止发送;反之则会进入发送重传,直到发送成功。
因此,进入发送状态后的转换就清楚了。当发送失败后且NART是1时,会回到预定状态等待总线空闲,然后重新发送;当发送失败且NART为0时,则直接发送终止,进入空置状态,此时RQCP和TME都会被置1,表示发送终止了(RQCP=1),同时该发送邮箱被清空(TME=1),而TXOK=0表示发送失败了。
若发送成功了,则会进入另一个空置状态,此时RQCP变成1表示本次发送结束、TXOK=1表示本次发送时成功的、TME=1表示该发送邮箱已经清空了。
此外,还有两处状态转换逻辑,即当处于挂号状态或预定状态时,若ABRQ为1,则也会直接进入发送失败的空置状态中。

我们查手册看看ABRQ是什么东西。

可以看见,也是CAN发送状态寄存器中的位,三个发送邮箱各对应一位。看看其详细描述。

ABRQ即邮箱终止发送状态位,也就是该位置1时可以终止邮箱的发送请求,然后该邮箱中的报文被清除后硬件自动清0。
因此我们就清楚了,在产生发送请求后的挂号状态或预定状态下,若ABRQ为1则可以直接中止当前的发送,然后以发送中止而失败的状态结束。
至此,对于发送流程的细节我们就大致清楚了。
2.3.2****接收流程
接着我们再看看接收流程。接收的基本流程为接收到一个报文 → 匹配过滤器后进入 FIFO 0 或 FIFO 1→CPU 读取。我们同样对照手册给出的接受状态转移图来看,如下图所示。

接收时,默认初始状态接收FIFO都是空的,因此默认状态为空状态。该状态下有两个参数即FMP和FOVR,我们同样查手册看看都是什么。

可以发现,这俩是CAN接收FIFO寄存器中的内容,其中每一个接收FIFO各对应一个寄存器,即各有俩这个参数。继续看看关于这俩参数的详细描述。

可见,FMP即FIFO报文数目,当有新报文存入接收FIFO时,对应的FMP就会自动+1;反之,当CPU读取接收FIFO中的一个报文后,由编程者去-1。
FOVR即FIFO溢出标志位。当FIFO装满时,又收到新的符合过滤器的报文后FIFO会溢出,硬件自动将FOVR置1,此时必然出现接收报文丢失。
好,了解了这两位后,这个接受状态图就很容易理解了。

当收到有效的报文,也就是通过过滤器后的报文时,接收FIFO就会进入挂号1状态,此时FMP报文数目就会+1变成0x01,由于接收FIFO有3个位置,所以不会溢出,即FOVR为0。如果此时CPU读取了接收FIFO的报文数据,则会释放该邮箱,然后回到空状态,然后FMP又变成0。

接着,如果挂号1状态时,又收到了有效报文,则进入挂号2状态,此时FMP=0x02(注意手册图描述有误,0x10应该是10b)表示此时接收FIFO中有2个报文排队了,且还没有溢出。此时如果CPU读取了报文,则会释放邮箱且FROM=1,FMP-1,然后到挂号3状态也是同理。
这里又出现了新的标志位FROM,同样查手册看看这是啥。

可以看出,这也是CAN接收FIFO寄存器中的值,表示释放接收FIFO输出邮箱。将该位置1可以释放接收FIFO的邮箱。因为当接收FIFO中出现2个以上的报文时,若不释放邮箱,则无法访问第2个报文。
继续,当处于挂号3状态时,实际接收FIFO已经存了3个报文了,若再次有新的报文来,则会产生溢出,进入溢出状态,如下图所示。

而此时若还是一直收到有效报文的话,那么会反复出现溢出,且FOVR一直是1。如果此时CPU读取了报文,且RFOM变成1释放邮箱,则会回到挂号2状态,注意不是挂号3状态。因为溢出状态和挂号3状态其实都是FMP数目为3,如果读取后数目应该变成2,则会进入挂号2状态,因此这里手册描述可能有误哈,需要注意一下。

那么到这里,对于接收流程的细节就大概清楚了。
2.3.3****接收 / 发送配置位
最后,再介绍几个接收/发送时可以配置的寄存器位,灵活设置可以让收发更符合我们的实际需要。
- NART:置1,关闭自动重传,CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失);置0,自动重传,CAN硬件在发送报文失败时会一直自动重传直到发送成功。该位在前面已经介绍过,所以不展示手册描述了。
- TXFP:置1,优先级由发送请求的顺序来决定,先请求的先发送;置0,优先级由报文标识符来决定,标识符值小的先发送(标识符值相等时,邮箱号小的报文先发送)。手册中对于该位的描述如下图所示。


- RFLM:置1,接收FIFO锁定,FIFO溢出时,新收到的报文会被丢弃;置0,禁用FIFO锁定,FIFO溢出时,FIFO中最后收到的报文被新报文覆盖。这一位就在TXFP旁边,手册中对于该位的描述如下图所示。

2.4****标识符过滤器
接着介绍一下CAN外设的标识符过滤器。前面介绍基本结构时,只是简单讲述了一下过滤器的用法,并没有详细说明他具体是怎么配置的。同时该部分也是CAN外设中的一个重点和难点,因此这里再详细介绍一下。
2.4.1****核心寄存器概述
1、CAN外设的标识符过滤器由14个,每个过滤器的核心是由两个 32 位寄存器配置的,也就是如下图寄存器。

这两个寄存器分别是CAN_FiR1和CAN_FiR2,其中"i"表示对应哪一个过滤器。若我们需要配置过滤器1,则使用CAN_F1R1和CAN_F1R2进行配置;若我们需要配置过滤器2,则使用CAN_F2R1和CAN_F2R2进行配置;以此类推。
然后这两个寄存器配置如下两种参数。

一是标识符模式的配置,用于设置该过滤器期望通过的报文ID的各位电平,即ID某一位是隐性电平,则对应寄存器上那一位置1,反之同理。
二是屏蔽位模式,用于设置是否需要比较某一位使与过滤器设置保持一致,进而过滤不一致的报文。如果需要某一位是一致的,则把寄存器对应位置1,;如果不需要一致,则对应位置0就行,表示不关心,不需要比较该位。
注:不得不重复提醒的是,这里所介绍的是一个过滤器的两个寄存器,但是实际上有14个过滤器,即芯片电路中其实是存在14个与之相同的电路设计的,并非14个过滤器仅用这一个哈,这也是手册描述该寄存器时使用了"i"去表示多个的原因。
2、其次是设置过滤器位宽的寄存器,如下图所示。

也就是CAN过滤器位宽寄存器CAN_FS1R,该寄存器用于配置每一个过滤器的位宽。其中复位值为0,即过滤器位宽默认都是16位。然后FSCx(x=0~13)为1,位宽为16位;为0,位宽为32位。
3、接着是设置过滤器模式的寄存器,如下图所示。

也就是CAN过滤器模式寄存器CAN_FM1R,全是FBM位,用于设置过滤器模式。其中,置0,表示前面介绍的核心的两个32位寄存器工作在标识符屏蔽位模式;置1,表示工作在标识符列表模式。
4、紧接着是过滤器关联设置的寄存器,如下图所示。

也就是CAN过滤器FIFO关联寄存器CAN_FFA1R,作用是将对应的过滤器关联指定FIFO,让通过对应过滤器过滤后的报文存入指定的FIFO中。FFA位置0,表示对应过滤器关联到FIFO0,通过该过滤器的报文会存入FIFO0;FFA置1,表示对应过滤器关联到FIFO1,通过该过滤器的报文会存入FIFO1。因此,该寄存器就是用于配置过滤器到接收FIFO时的二选1通道的。
5、最后还有一个过滤器激活设置的寄存器,如下图所示。

也就是CAN过滤器激活寄存器CAN_FA1R,用于激活相应的过滤器,相当于过滤器的开关。FACT置1,过滤器被禁用;置0,过滤器被激活。因为CAN外设的过滤器很多,并不是全部都会用到,因此没必要都打开,所以通过该寄存器就可以进行设置了。同时对于FACT置0的方法除了直接清0外,还可以对CAN_FMR寄存器的FINIT写1去清零FACT。
2.4.2****过滤器设计规则
( 1 )四种模式及其场景
接下来,我们了解一下每一个过滤器内部的设计方法,如下图是手册对于单个过滤器的设计框图。

从右往左来看,首先,根据位宽寄存器和模式寄存器可以设置四种不同的过滤器配置。根据前面所述,FSC表示设置位宽、FBM表示设置模式。对照上图看,FSC=1时,即设置32位的位宽,也就是两个寄存器都使用32位去记录ID号和相关配置;FSC=0时,即设置16位的位宽,也就是两个寄存器分成4个16位去记录ID和相关配置。显然可以理解到,当设置FSC=1时,32位记录ID肯定可以放下标准ID和扩展ID,而FSC=0时,16位记录ID最多只能放下标准ID了。总而言之,32位位宽时一个过滤器可以存放两个ID(标准或者扩展)去进行过滤,16位位宽时一个过滤器可以存放4个标准ID去进行过滤,可以发现位宽的设计就是为了高效利用好寄存器的每一位,根据不同类型的ID去选择不同的位宽。
其次,对于不同的位宽,可以设置过滤器模式,即FBM=0时可设置成标识符屏蔽位模式,FBM=1时可设置成标识符列表模式。
简单来说当为标识符列表模式时,对于32位位宽的过滤器来说,两个32位寄存器分别可存放一个ID(标准或者扩展),然后过来的报文会经过过滤器判断每一位是否完全符合寄存器里面存放的ID,若符合则通过,反之不能通过;对于16位位宽的过滤器来说,由于分成了4个16位去记录ID,因此两个32位寄存器一共可以存放4个标准ID,然后同样是完整符合的报文通过该过滤器,反之不行。可以看出,列表模式下,过滤器可用于过滤ID每一位均符合要求的报文。

再看标识符屏蔽模式时,两个32位寄存器则具备不同的作用,R1用于记录需要过滤的ID号,R2用于设置屏蔽位,他决定了过来的报文的ID与存入的ID的哪些位必须一致。对于32位位宽的过滤器来说,R1寄存器可存放一个ID(标准或扩展),R2寄存器中将ID号里面我们希望一致的对应位号置1,这样当有报文过来时,就只会判断该报文的ID中与R2寄存器设置为1的位号一致的值是否与过滤器中R1寄存器中位号对应的值是否一致,如果一致则符合要求的这一类ID报文都可以通过,反之则均不能;对于16位位宽的过滤器来说,就是一个过滤器可以用于判断两组同样类型的报文是否符合了。总而言之,屏蔽模式下,每个过滤器可用于过滤一组具备相同位ID的报文,适用于相同功能有大量不同设备需要发送报文给某设备的场景。

比如有100条不同设备采集的温度数据和100条不同设备采集的湿度数据要给某一设备汇总,此时只需要将100条温度数据的某些位设置成一样的,然后其他位自己设定,然后利用屏蔽模式即可过滤通过这一组数据了,那么湿度数据也是同理。
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 到这里,这四种模式下的基本使用场景我们就清楚了,稍微再总结一下这四种模式下的过滤器的作用和场景。 FSC=1、FBM=0,即32位位宽的标识符屏蔽模式,ID的某些位一致即可通过,一个过滤器可过滤1组同一类数量较多的报文,常用于过滤扩展ID的报文; FSC=1、FBM=1,即32位位宽的标识符列表模式,仅ID逐位完全一致才能通过,且一个过滤器可过滤2种不同ID对应的报文,常用于过滤扩展ID的报文; FSC=0、FBM=0,即16位位宽的标识符屏蔽模式,ID的某些位一致即可通过,一个过滤器可过滤2组同一类数量较多的报文,常用于过滤标准ID的报文; FSC=0、FBM=1,即16位位宽的标识符列表模式,仅ID逐位完全一致才能通过,且一个过滤器可过滤4种不同ID对应的报文,常用于过滤标准ID的报文; |
( 2 )模式的寄存器位配置
接着,前面我们知道了可以过滤什么样的ID以及各种模式的功能和场景,接下来则进一步详细了解一下他32位各个部分都怎么设置,也就是了解一下寄存器映像。
那么最简单直观的就是32位标识符列表模式的过滤器,如下图所示。

可以看出,标识符列表模式下,高29位用于设置过滤的报文ID,第1位RTR设置这个ID是数据帧还是遥控帧,第2位IDE用于设置这个ID是标准格式还是扩展格式,第0位没有使用默认给0就行。
当我们存入寄存器的ID是标准ID时,则只需要使用寄存器高11位,然后中间扩展ID部分的位可以默认给0,同时第2位IDE位要对应设置成表示标准格式的状态即置显性电平0,然后如果是数据帧则第1位的RTR位需要设置成显性电平0,为遥控帧则设置成1。
同样地,当我们存入寄存器的ID是扩展ID时,则需要将高29位的ID全部用上,同时第2位IDE位要对应设置成表示扩展格式的状态即置隐形电平0,然后如果是数据帧则第1位的RTR位需要设置成显性电平0,为遥控帧则设置成1。
可以看出:1、32位位宽下,若用来过滤标准ID报文,则会浪费大量的寄存器位,因此32位位宽模式更适合用于过滤扩展ID的报文。2、存放不同格式的ID时,IDE位和RTR位一定要一一对应,避免出错。
接着,我们再看16位标识符列表模式的过滤器,如下图所示。

可以看出,16位位宽的标识符列表模式下,就是分成了4个ID,即可以存4个ID,然后切分后的各个高11位用于存放标准ID号,相邻的是RTR位,用于区分遥控帧和数据帧,电平设置与前面介绍的一致,然后是IDE位,用于区分标准格式和扩展格式,不过由于16位位宽下只能存放标准格式ID,因此只能为显性电平0。最后的EXID那几位不使用,默认给0就行。
可以看出:1、16位位宽下,可以充分利用寄存器位,实现单个过滤器同时过滤四种标准ID的报文,资源利用率提高。2、该模式下IDE位必须置0,否则可能配置出错。
紧接着看32位和16位位宽的标识符屏蔽模式下的过滤器,如下图所示。

可以发现,其实屏蔽模式下的两种位宽对应的配置位是和前面介绍列表模式时一模一样的,只不过判断报文是否通过的标准是根据置1的屏蔽位来看的,因为屏蔽位与ID各个位是一一对应的,对应的屏蔽位置1,说明只有ID对应的那些位的值一致才能通过过滤器,同时RTR、IDE位也是一样,如果置1说明过来的报文的格式必须与过滤器设置的ID的格式一致,置0则无所谓,然后RTR同理不再赘述。
主要需要注意的是:屏蔽模式下,不同位宽时负责ID和屏蔽位的设置都不相同。32位位宽时R1全部用于设置ID、R2全部用于设置屏蔽位;16位位宽时由于单个过滤器一次可以过滤出两组同类ID报文,所以是R1寄存器高16位用于设置屏蔽位、低16位用于设置标准ID,然后R2则是设置第二组的对应内容。
那么到这里,我们就清楚了四种模式下过滤器各个位需要如何配置。但是知道每一位如何配置了,可能也不太明白实际编程时如何去设置这些位,毕竟模式很多,拆分成几块了,将这么多内容成块设置到两个寄存器里面显然是需要思考的。
( 3 )配置实例展示
因此接下来,我们再介绍实际编程时应该如何去设置过滤器。这里使用一张表进行描述,如下图所示。

如上图所示,主要列举了常见的六大场景,分别对应了四种过滤器模式的配置以及全通或只通过数据帧或遥控帧的场景。
这些配置的逻辑就是对照前面我们看的单个过滤器的寄存器映像和位对应去一点点配置,使用移位运算去处理各个部分的内容。当然了,这里标准ID号为了方便描述,直接使用16进制的3位表示的,只不过最高位总是0,所以实际就是表示的11位ID部分。
可以自己对照手册的那张图去简单分析分析,这样对于过滤器部分的配置理解会更加深刻哈。
2.5****测试模式
接着,我们介绍几种测试模式。测试模式是CAN外设用于自我调试的模式,因为CAN总线会挂载多个设备,同时具备收发功能,想要测试的话就需要写完以后统一测试。如果这样测试出现了什么问题,其实是很难去判断的,因此CAN外设自身提供了三种测试模式,可用于在不外接设备时进行自测,没有问题了再去连接设备进行测试,这样能够减少很多未知麻烦。
2.5.1****静默模式
首先是静默模式,该模式用于分析CAN总线的活动,不会对总线造成影响,手册中对此模式的描述图如下。

如图,在正常工作的模式下,CAN外设的串口引脚应该都是与外部收发器连接,但是在静默模式下,CANTX引脚是常为1的状态,也就相当于没有发生数据。然后CANRX引脚则可以与外部相连,同时当CAN外设处于静默模式后,CAN外设内部电路会接通发送和接受引脚,在不影响总线的情况下进行自身发送报文进行接收,属于自发自收的模式。
该模式下,因为CANRX可以与外部连接,因此可用于接收外部报文然后分析CAN总线活动,同时可以完成对自身收发的情况进行调试。因为这种模式不影响总线,就默默看着不碰它,去观察总线的状态,所以叫做"静默"模式。
2.5.2****环回模式
然后是环回模式,主要用于自测试,同时发送的报文可以在CAN_TX引脚上检测到,手册对此模式的描述如下图所示。

如图,该模式下,CANTX可以与总线连接,但是CANRX与外部隔离了,此时CAN外设内部电路会将发送和接受连接,实现自发自收的效果。因为CANTX能连接外部CAN总线网络,因此还可以向总线上发送报文,即自身可以接受自己发送的报文,同时可以通过发送引脚检测到。
注意:这种内部电路自动将发送和接受连接形成的自己发送后可接收的效果,并非前面介绍CAN设备发送数据后的回读机制,因为前面介绍的回读机制属于报文层面的读取,但是这里属于底层的电路连接,存在一定区别。
2.5.3****环回静默模式
环回静默模式,即结合环回和静默后的一种,该模式主要用于热自测试,自测的同时不会影响CAN总线,手册中对此的描述如下图所示。

如图,该模式下,CAN外设的串口收发引脚均与总线隔离,即此时对于CAN外设的测试不会影响到外部连接的CAN总线系统,然后内部电路会自动将发送和接受连通,实现自测试的效果。
因为该模式下可以直接挂载到整个CAN总线网络上完成对自身的测试,不会影响总线,因此被称作"热自测试"。
2.6****工作模式
2.6.1****三种工作模式
接着介绍几种工作模式,也就是正常运行的模式
(1)初始化模式:用于配置CAN外设,禁止报文的接收和发送。
初始化模式下,主要用于CAN外设的配置,为了保证CAN设备的稳定性,配置过程中不能进行正常的收发工作,即该模式下禁止收发报文。
(2)正常模式:配置CAN外设后进入正常模式,以便正常接收和发送报文。
正常模式即CAN外设配置完成了,此时就会正式开始报文的收发状态。
(3)睡眠模式:低功耗,CAN外设时钟停止,可使用软件唤醒或者硬件自动唤醒。
此外,CAN外设还支持睡眠模式,该模式下CAN外设会进入低功耗,降低系统功耗。当需要正常工作时,可以通过软件或硬件进行唤醒。软件唤醒即利用程序去唤醒CAN外设,硬件唤醒则是检测到总线活动时自动唤醒CAN外设,也是很高级的功能。
(4)AWUM 位:置1,自动唤醒,一旦检测到CAN总线活动,硬件就自动清零SLEEP,唤醒CAN外设;置0,手动唤醒,软件清零SLEEP,唤醒CAN外设。
AWUM是CAN外设寄存器中的某一位,如下图所示。

也就是CAN主控制寄存器CAN_MCR中的第5位,其详细描述如下。

即该位置1,则硬件自动唤醒;置0,则软件手动唤醒。
2.6.2****状态转换分析
同时,手册中对于工作模式的描述有一状态转换图,如下所示。

然后我们对照状态转换图分析一下。
系统上电复位,默认处于睡眠模式,此时SLAK=1、INAK=0。其中SLAK和INAK也分别是寄存器中的某一位,手册中对此描述如下图所示。

即SLAK是睡眠模式确认位,当处于睡眠模式时,该位自动置1,反之则变成0;然后INAK是初始化确认位,当处于初始化模式时,该位自动置1,反之则变成0。
好,此时我们继续分析,当退出睡眠模式,同时产生了初始化请求时,若外设应答了,则会进入初始化模式,如下图所示。

这个状态的转移,需要满足的条件有三个,即退出睡眠模式(SLEEP置0)、检测到初始化请求(INRQ置1),同时收到外设应答(ACK)。进入初始化模式后,SLAK则会自动置0,因为退出睡眠模式了,同时INAK会置1,因为进入初始化模式了。
同时,在初始化模式下,也可以再次回到睡眠模式,也就是检测到睡眠模式请求(SLEEP置1)、无初始化请求(INRQ置0),同时接收到了回应(ACK),此时就会进入睡眠模式,同样SLAK被置1、INAK被置0。
继续,初始化模式后,可以进入正常模式,如下图所示。

如图,初始化模式下,如果检测到无初始化请求(INRQ置0),同时检测到总线处于空闲了(SYNC),并且也没有睡眠模式请求(SLEEP置0),则可以进入正常模式,也就是可以正常进行报文的发送和接受。此时SLAK=0、INAK=0,即既不是初始化模式也不是睡眠模式。
同时,正常模式也可以继续回到初始化模式,即出现初始化请求(INRQ置1),并收到了回应时,正常模式再次回到初始化模式进行CAN外设配置。
最后,正常模式还可以回到睡眠模式,同时睡眠模式下可以唤醒后进入正常模式,如下图所示。

前面分析了两次后,这里就容易理解了。即正常模式下,如果产生了睡眠模式请求(SLEEP被置1),同时收到了回应,则CAN外设可以从正常模式进入睡眠模式,接着SLAK变成1、INAK为0。然后睡眠模式下,如果未检测到睡眠模式请求(SLEEP置0)、同时检测到当前总线空闲,且没有收到初始化请求(INRQ置0),则会从睡眠模式回到正常模式下。
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 可能有人注意到,每次转换状态时,要么需要等待ACK 应答,要么需要等到总线空闲,为什么呢? 每一个模式的变换,不可能收到请求就立马转换,因为可能此时正常进行报文的收发处理或者相关配置,为避免出错,一般都需要等收到对应的应答,也就是请求后收到"我同意了"后才会进行模式切换,或者说等总线空闲了,说明此时没有报文传输了,然后进行模式转换才最安全。这是等待ACK或总线空闲后才进行转换的原因。 |
至此,三个工作模式的状态转换就分析完成了。
2.7****位时间特性
接着是位时间特性,实际就是前面介绍过的位时序,即CAN总线上发送的一个数据位的构成部分,手册描述如下图所示。

看见这个图可以发现,这个位时序其实和前面介绍CAN2.0时有点不一样,即这个位时序组成相比之前少了PTS段。可能原因是STM32设计者认为位时序中PTS段其实没有啥特别的东西要处理,所以为了简单干脆直接和BS1合并了,就形成了当前更大一块BS1段。除此之外就没有什么区别了。
其中,SS = 1Tq、BS1 = 1~16Tq、BS2 = 1~8Tq、SJW=1~4Tq。
由图可知,这里计算波特率的公式与之前是一样的,即正常一个数据位传输的时间。具体来说,就是SS段的时间Tq+BS1段的1时间+BS2段的时间。其中BS1的时间和BS2的时间可以通过寄存器配置,如下图所示。

也就是通过CAN位时序寄存器的TS1和TS2进行配置。TS1对应BS1段的时间,使用4位进行配置;TS2对应BS2段的时间,使用3位进行配置。其详细描述如下:

可见,通过配置TS1和TS2,就可以利用公式计算出BS1和BS2所需要的时间单元Tq了。
换句话说,要得出更具体的时间,还需要配置Tq的时间长度才行,而Tq是由BRP和PCLK决定。其中CAN外设挂载在APB1总线上,因此PCLK是指APB1总线时钟频率,最高36MHz,然后BRP也是位时序寄存器的某些位,如下图所示。

也就是BRP9:0,占了10位,定义时间单元Tq的时间长度,计算公式是Tq=(BRP+1)*PCLK。
到这里,我们就清楚了波特率设置的全部构成,即
波特率 = APB1时钟频率 / 分频系数 / 一位的Tq数量
假如我们配置的PCLK为36MHz,则
波特率 = 36MHz / (BRP9:0+1) / (1 + (TS13:0+1) + (TS22:0+1))
2.8****中断处理
CAN外设还可以产生中断,手册描述,CAN外设占用了4个专用的中断向量,分别是发送中断、FIFO0中断、FIFO1中断、状态改变中断这四个。
( 1 )发送中断:发送邮箱空时产生。
( 2 ) FIFO 0 中断:收到一个报文 /FIFO 0 满 /FIFO 0 溢出时产生。
( 3 ) FIFO 1 中断:收到一个报文 /FIFO 1 满 /FIFO 1 溢出时产生。
( 4 )状态改变错误中断:出错 / 唤醒 / 进入睡眠时产生。
这四种中断也比较好理解,这里就不在过多赘述了。
需要注意的是:FIFO0和FIFO1这两个中断他们分别占用了一个中断向量,即可以同时发生两种中断。
手册中对于CAN外设中断的设计框图如下图所示。

主要描述了相关中断的产生流程以及触发的条件等,可自行理解一下。
2.9****时间触发通信
初学不必掌握,暂时不深究。

2.10****错误处理与时间恢复

这部分在前面介绍CAN协议的错误处理时介绍过,在STM32设计的内置CAN外设中对此的设计也基本相同,只不过增加了一个类似开关的控制。
即在持续错误导致进入离线模式,也就是无法进行通信的状态时,CAN总线协议规定的是出现128次11个隐性位后恢复到错误主动状态。但在STM32中,增加了一个ABOM位,该位会控制离线模式到错误主动模式的转换。当ABOM置1时,与CAN总线协议规定的转换逻辑一致;当ABOM置0时,则不能自动判断出现128次11个隐性位去恢复错误主动状态,而需要软件请求进入再退出初始化模式,也就是对INRQ置1再清零,之后才会恢复正常的判断,进而恢复。
至此,STM32中的CAN外设模块就学到这里,关于详细内容,还可以自己参考芯片参考手册对应章节去自行研究。
以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名初学小白,愿大家共同努力,一起进步吧!
鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!