STM32F10x之CAN

1 概述

1.1 简介

bxCAN是基本扩展CAN(Basic Extended CAN)的缩写,它支持CAN协议2.0A和2.0B。它的设计目标是,以最小的CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用, bxCAN提供所有支持时间触发通信模式所需的硬件功能。

1.2 特点

  • 支持CAN协议2.0A和2.0B主动模式
  • 波特率最高可达1Mbps
  • 支持时间出发通信功能

发送

  • 3个发送邮箱
  • 发送报文的优先级可软件配置
  • 记录发送SOF时刻的时间戳

接收

  • 3级深度的2个接收FIFO
  • 可变的过滤组:可达14个过滤器组
  • 标识符列表
  • FIFO溢出处理方式可配置
  • 记录接收SOF时刻的时间戳

时间触发通信方式

  • 禁止自动重传模式
  • 16位只有运行定时器
  • 可在最后2个数据字节发送时间戳

管理

  • 中断可屏蔽
  • 邮箱占用单独1块地址空间以便提高

1.3 拓扑图

STM32F10x之CAN_第1张图片
图1 CAN网络拓扑结构

2 工作模式

bxCAN有3种主要的工作模式:初始化、正常和睡眠模式。在硬件复位后,bxCAN工作在睡眠模式以节省电能。

2.1 初始化模式

设置CAN_MCR寄存器的INRQ位为1,请求bxCAN进入初始化模式,然后等待硬件对CAN_MSR寄存器的INAK位置1来进行确认。清除CAN_MCR寄存器的INRQ位为0,请求bxCAN退出初始化模式,当硬件对CAN_MSR寄存器的INAK位清0就确认了初始化模式的退出。当bxCAN处于初始化模式时,禁止报文的接收和发送,并且CANTX引脚输出隐性位(高电平)。初始化模式的进入,不会改变配置寄存器。

在对bxCAN的过滤器组(模式、位宽、 FIFO关联、激活和过滤器值)进行初始化前,软件要对CAN_FMR寄存器的FINIT位设置1,对过滤器的初始化可以在非初始化模式下进行。

备注: 当FINIT=1时,报文的接收被禁止,可以先对过滤器激活位清0,然后修改相应过滤器的值。如果过滤器组没有使用,那么就应该让它处于非激活状态。

2.2 正常模式

在初始化完成后,软件应该让硬件进入正常模式,以便正常接收和发送报文。软件可以通过对CAN_MCR寄存器的INRQ位清0,来请求从初始化模式进入正常模式,然后要等待硬件对CAN_MSR寄存器的INAK位置1的确认。只有在跟CAN总线取得同步,即在CANRX引脚上监测到11个连续的隐性位(等效于总线空闲)后, bxCAN才能正常接收和发送报文。不需要在初始化模式下进行过滤器初值的设置,但必须在它处在非激活状态下完成(相应的FACT位为0),而过滤器的位宽和模式的设置,则必须在初始化模式中进入正常模式前完成。

2.3 睡眠模式(低功耗)

bxCAN可工作在低功耗的睡眠模式。软件通过对CAN_MCR寄存器的SLEEP位置1,来请求进入这一模式,在该模式下, bxCAN的时钟停止了,但软件仍然可以访问邮箱寄存器。当bxCAN处于睡眠模式,软件必须对CAN_MCR寄存器的INRQ位置1并且同时对SLEEP位清0,才能进入初始化模式。有2种方式可以唤醒(退出睡眠模式)bxCAN:* 通过软件对SLEEP位置1或硬件检测到CAN总线的活动。如果CAN_MCR寄存器的AWUM位为1,一旦检测到CAN总线的活动,硬件就自动对SLEEP位清0来唤醒bxCAN;如果CAN_MCR寄存器的AWUM位为0,软件必须在唤醒中断里对SLEEP位清0才能退出睡眠状态。

注: 如果唤醒中断被允许(CAN_IER寄存器的WKUIE位置1),那么一旦检测到CAN总线活动就会产生唤醒中断,而不管硬件是否会自动唤醒bxCAN。在对SLEEP位清0后,睡眠模式的退出必须与CAN总线同步,当硬件对SLAK位清0时,就确认了睡眠模式的退出。

2.4 工作模式转换图

STM32F10x之CAN_第2张图片
bxCAN工作模式转换图

注:
1.ACK = 硬件响应睡眠或初始化请求,而对CAN_MSR寄存器的INAK或SLAK位置1的状态
2.SYNC = bxCAN等待CAN线变为空闲的状态,即在CANRX引脚上检测到连续的11个隐性位

3 测试模式

bxCAN支持3种测试模式:静默模式、环回模式、环回静默模式。

3.1 静默模式

通过对CAN_BTR寄存器的SILM位置1来选择静默模式。在静默模式下, bxCAN可以正常地接收数据帧和远程帧,但只能发出隐性位,而不能真正发送报文。如果bxCAN需要发出显性位(确认位、过载标志、主动错误标志),那么这样的显性位在内部被接回来从而可以被CAN内核检测到,同时CAN总线不会受到影响而仍然维持在隐性位状态。因此,静默模式通常用于分析CAN总线的活动,而不会对总线造成影响-显性位(确认位、错误帧)不会真正发送到总线上。

3.2 环回模式

通过对CAN_BTR寄存器的LBKM位置1来选择环回模式。在环回模式下, bxCAN把发送的报文当作接收的报文并保存在接收邮箱里(如果可以通过接收过滤)。环回模式可用于自测试,为了避免外部的影响,在环回模式下CAN内核忽略确认错误(在数据/远程帧的确认位时刻,不检测是否有显性位)。在环回模式下, bxCAN在内部把Tx输出回馈到Rx输入上,而完全忽略CANRX引脚的实际状态。发送的报文可以在CANTX引脚上检测到。

3.3 环回静默模式

通过对CAN_BTR寄存器的LBKM和SILM位同时置1可以选择环回静默模式。该模式可用于“热自测试”,即可以像环回模式那样测试bxCAN,但却不会影响CANTX和CANRX所连接的整个CAN系统。在环回静默模式下, CANRX引脚与CAN总线断开,同时CANTX引脚被驱动到隐性位状态。

4 功能介绍

4.1 发送处理

4.1.1 报文的发送流程

1.应用程序选择1个空置的发送邮箱;
2.设置标识符,数据长度和待发送数据;
3.对CAN_TIxR寄存器的TXRQ位置1以请求发送。 TXRQ位置1后,邮箱就不再是空邮箱,而一旦邮箱不再为空置,软件对该邮箱寄存器就不再有写的权限,邮箱就进入挂号状态并等待成为最高优先级的邮箱,当邮箱成为最高优先级的邮箱,其状态就变为预定发送状态,一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。如果邮箱中的报文被成功发送则变为空置邮箱,此时硬件对CAN_TSR寄存器的RQCP和TXOK位置1,来表明此次发送成功;如果发送失败,由于仲裁引起的就对CAN_TSR寄存器的ALST位置1,如果由于发送错误引起的就对TERR位置1。

STM32F10x之CAN_第3张图片
图2 发送状态转换图

4.1.2 发送优先级

1.由标识符决定: 当不止1个发送邮箱在挂号时,发送顺序由邮箱中报文的标识符决定,根据CAN协议,标识符数值最低的报文具有最高的优先级。
2.由邮箱号决定: 如果邮箱中报文的标识符的值相等,那么邮箱号小的报文先被发送。
3.有发送请求次序决定: 通过对CAN_MCR寄存器的TXFP位置1,可以把发送邮箱配置为发送FIFO,在该模式下,发送的优先级由发送请求次序决定。注:该模式对分段发送特别有用。

4.1.3 发送终止

通过对CAN_TSR寄存器的ABRQ位置1,可以终止发送请求。如果邮箱处于挂号或预定状态,发送请求马上就被中止了。如果邮箱处于发送状态,那么中止请求可能导致2种结果:如果邮箱中的报文被成功发送,那么邮箱变为空置邮箱,并且CAN_TSR寄存器的TXOK位被硬件置’1’;如果邮箱中的报文发送失败了,那么邮箱变为预定状态,然后发送请求被终止,邮箱变为空置邮箱且TXOK位被硬件清0。因此如果邮箱处于发送状态,那么在发送操作结束后,邮箱都会变为空置邮箱。

4.1.4 禁止自动重传模式

该模式主要用于满足CAN标准中时间触发通信选项的需求。通过对CAN_MCR寄存器的NART位置1来让硬件工作在该模式。在该模式下,发送操作只会执行一次,如果发送操作失败了,不管是由于仲裁丢失或出错,硬件都不会再自动发送该报文。在一次发送操作结束后,硬件认为发送请求已经完成,从而对CAN_TSR寄存器的RQCP位置1,同时发送的结果反映在TXOK、 ALST和TERR位上。

4.2 时间触发通信模式

在该模式下, CAN硬件的内部定时器被激活,并且被用于产生发送与接收邮箱的时间戳,分别存储在CAN_RDTxR/CAN_TDTxR寄存器中。内部定时器在每个CAN位时间累加。内部定时器在接收和发送的帧起始位的采样点位置被采样,并生成时间戳。在长度为8的报文中,时间戳TIME[15:0]是最后2个发送的字节:TIME[7:0]作为第7个字节, TIME[15:8]为第8个字节,它们替换了写入CAN_TDHxR[31:16]的数据(DATA6[7:0]和DATA7[7:0])。为了把时间戳的2个字节发送出去, DLC必须编程为8。

4.3 接收管理

接收到的报文,被存储在3级邮箱深度的FIFO中,FIFO完全由硬件来管理,从而节省了CPU的处理负荷,简化了软件并保证了数据的一致性,应用程序只能通过读取FIFO输出邮箱,来读取FIFO中最先收到的报文。

4.3.1 有效报文

根据CAN协议, 当报文被正确接收(直到EOF域的最后一位都没有错误), 且通过了标识符过滤,那么该报文被认为是有效报文。

4.3.2 FIFO管理

STM32F10x之CAN_第4张图片
图3 接收FIFO状态转换图

FIFO从空状态开始,在接收到第一个有效的报文后, FIFO状态变为挂号_1(pending_1),硬件相应地把CAN_RFR寄存器的FMP[1:0]设置为01b。软件可以读取FIFO输出邮箱来读出邮箱中的报文,然后通过对CAN_RFR寄存器的RFOM位置1来释放邮箱,这样FIFO又变为空状态了。如果在释放邮箱的同时,又收到了一个有效的报文,那么FIFO仍然保留在挂号_1状态,软件可以读取FIFO输出邮箱来读出新收到的报文;如果应用程序不释放邮箱,在接收到下一个有效的报文后, FIFO状态变为挂号_2(pending_2),硬件相应地把FMP[1:0]设置为10b,重复上面的过程,第三个有效的报文把FIFO变为挂号_3状态(FMP[1:0]=11b),此时,软件必须对RFOM位置1来释放邮箱,以便FIFO可以有空间来存放下一个有效的报文,否则,下一个有效的报文到来时就会导致一个报文的丢失。

4.3.3 溢出

当FIFO处于挂号_3状态(即FIFO的3个邮箱都是满的),下一个有效的报文就会导致溢出,并且一个报文会丢失,此时,硬件对CAN_RFR寄存器的FOVR位进行置1来表明溢出情况,至于哪个报文会被丢弃,取决于对FIFO的设置:

  • 如果禁用了FIFO锁定功能(CAN_MCR寄存器的RFLM位被清0),那么FIFO中最后收到的报文就被新报文所覆盖。这样,最新收到的报文不会被丢弃掉。
  • 如果启用了FIFO锁定功能(CAN_MCR寄存器的RFLM位被置1),那么新收到的报文就被丢弃,软件可以读到FIFO中最早收到的3个报文。

4.3.4 接收中断

一旦接收FIFO存入一个报文,硬件就会更新FMP[1:0]位,并且如果CAN_IER寄存器的FMPIE位为1,那么就会产生一个挂号中断请求。当FIFO 变 满 时( 即 第3 个 报 文 被 存 入) , CAN_RFR 寄 存 器 的FULL 位 就 被 置1 , 并 且 如 果CAN_IER寄存器的FFIE位为1,那么就会产生一个满中断请求。在溢出的情况下, FOVR位被置1,并且如果CAN_IER寄存器的FOVIE位为1,那么就会产生一个溢出中断请求。

4.4 标识符过滤

在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。发送者以广播的形式把报文发送给所有的接收者,节点在接收报文时,根据标识符的值决定软件是否需要该报文:如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。为满足这一需求,在互联型产品中, bxCAN控制器为应用程序提供了28个位宽可变的、可配置的过滤器组(27~0);在其它产品中, bxCAN控制器为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。每个过滤器组x由2个32位寄存器, CAN_FxR0和CAN_FxR1组成。

4.4.1 可变位宽

每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:

  • 1个32位过滤器,包括: STDID[10:0]、 EXTID[17:0]、 IDE和RTR位
  • 2个16位过滤器,包括: STDID[10:0]、 IDE、 RTR和EXTID[17:15]位

此外过滤器可配置为,屏蔽位模式和标识符列表模式。

4.4.2 屏蔽位模式

在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起指定报文标识符的任何一位,应该按照“必须匹配”(屏蔽位为1)或“不用关心”(屏蔽位为0)处理。

4.4.3 标识符列表模式

在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用,因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器,接收报文标识符的每一位都必须跟过滤器标识符相同。

4.4.4 过滤器组位宽和模式的设置

过滤器组可以通过相应的CAN_FMR寄存器配置。在配置一个过滤器组前,必须通过清除CAN_FAR寄存器的FACT位,把它设置为禁用状态。通过设置CAN_FS1R的相应FSCx位,可以配置一个过滤器组的位宽。通过CAN_FMR的FBMx位,可以配置对应的屏蔽/标识符寄存器的标识符列表模式或屏蔽位模式。

  • 为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。
  • 为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。
  • 应用程序不用的过滤器组,应该保持在禁用状态。

过滤器组中的每个过滤器,都被编号(可以称作过滤器号)从0开始,到某个最大数值,这个值取决于过滤器组的模式和位宽的设置。关于过滤器的配置如图4所示:

STM32F10x之CAN_第5张图片
图4 过滤器组配置

4.4.5 过滤器匹配序号

一旦收到的报文被存入FIFO,就可被应用程序访问,通常情况下,报文中的数据被拷贝到SRAM中。为了把数据拷贝到合适的位置,应用程序需要根据报文的标识符来辨别不同的数据, bxCAN提供了过滤器匹配序号以简化这一辨别过程:根据过滤器优先级规则,过滤器匹配序号和报文一起被存入邮箱中,因此每个收到的报文,都有与它相关联的过滤器匹配序号。过滤器匹配序号可以通过下面两种方式来使用:

  • 把过滤器匹配序号跟一系列所期望的值进行比较
  • 把过滤器匹配序号当作一个索引来访问目标地址
    对于标识符列表模式下的过滤器(非屏蔽方式的过滤器),软件不需要直接跟标识符进行比较。对于屏蔽位模式下的过滤器,软件只须对需要的那些屏蔽位(必须匹配的位)进行比较即可。

编号规则:
1.未初始化的过滤器组编号时归为FIFO0且为32位标识符列表模式即占用两个序号;
2.已初始化的过滤器组(不管是否激活)按图4所示规则编号;
3.每个FIFO各自对其关联的过滤器进行编号;
4.FIFO2仅对分配到此FIFO上的过滤器组编号。

请参考下图的示例:

STM32F10x之CAN_第6张图片
图5 过滤器编号示例

备注:
1.过滤器组0、1、3、5、6、9和13被分配给FIFO0而过滤器组2、4、7、8、10、11和12被分配给FIFO1
2.过滤器组0配置为32位标识符列表模式则拥有2个过滤器分别为0和1,过滤器组1配置为32位标识符屏蔽位模式则拥有1个过滤器按顺序编为2,过滤器3配置为16位列表模式则可达4个过滤器按顺序编为3~6,其它依此类推
3.过滤器组2属于FIFO1,应重新标号,因此过滤器组2配置为16位屏蔽位模式则有2个过滤器,编号为0和1,其他依次按序编码

4.4.6 过滤器优先级规则

根据过滤器的不同配置,有可能一个报文标识符能通过多个过滤器的过滤,在这种情况下,存放在接收邮箱中的过滤器匹配序号,根据下列优先级规则来确定:
1.位宽为32位的过滤器,优先级高于位宽为16位的过滤器
2.对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式
3.位宽和屏蔽模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高

STM32F10x之CAN_第7张图片
图6 过滤器机制示例

上面的例子说明了bxCAN的过滤器规则:在接收一个报文时,其标识符首先与配置在标识符列表模式下的过滤器相比较,如果匹配上,报文就被存放到相关联的FIFO中,并且所匹配的过滤器的序号被存入过滤器匹配序号中,如同例子中所显示,报文标识符跟过滤器编号4的过滤器标识符匹配,因此报文内容和过滤器序号4被存入FIFO。如果没有匹配,报文标识符接着与配置在屏蔽位模式下的过滤器进行比较。如果报文标识符没有跟过滤器中的任何标识符相匹配,那么硬件就丢弃该报文,且不会对软件有任何打扰。

4.5 报文存储

邮箱是软件和硬件之间传递报文的接口,邮箱包含了所有跟报文有关的信息:标识符、数据、控制、状态和时间戳信息。

4.5.1 发送邮箱

软件需要选择一个空的发送邮箱,把待发送报文的各种信息设置好,然后再发出发送的请求,发送的状态可通过查询CAN_TSR寄存器获知。

4.5.2 接收邮箱

报文接收存储规则:
1.按照过滤器优先级规则将报文存储在符合过滤器分配的FIFO中;
2.如果位宽、屏蔽模式和过滤器号都相同,报文存储在过滤器组序号小分配的FIFO中。

在接收到一个报文后,软件就可以访问接收FIFO的输出邮箱来读取它,一旦软件处理了报文(如把它读出来),软件就应该对CAN_RFxR寄存器的RFOM位进行置1,来释放该报文,以便为后面收到的报文留出存储空间。过滤器匹配序号存放在CAN_RDTxR寄存器的FMI域中,16位的时间戳存放在CAN_RDTxR寄存器的TIME[15:0]域中。
注意: STM32F10x标准外设库CAN模块接口并没有提供接收时间戳的,如果应用需要,应先从CAN_RDTxR寄存器的TIME域(位31~16)读取时间戳,在调用接收接口函数获取报文信息。

4.6 出错处理

CAN协议描述的出错管理,完全由硬件通过发送错误计数器(CAN_ESR寄存器里的TEC域)和接收错误计数器(CAN_ESR寄存器里的REC域)来实现,其值根据错误的情况而增加或减少,软件可以读出它们的值来判断CAN网络的稳定性。此外, CAN_ESR寄存器提供了当前错误状态的详细信息,通过设置CAN_IER寄存器(比如ERRIE位),当检测到出错时软件可以灵活地控制中断的产生。
离线恢复
当TEC大于255时, bxCAN就进入离线状态,同时CAN_ESR寄存器的BOFF位被置1,在离线状态下, bxCAN无法接收和发送报文,根据CAN_MCR寄存器中ABOM位的设置, bxCAN可以自动或在软件的请求下,从离线状态恢复(变为错误主动状态)。在这两种情况下, bxCAN都必须等待一个CAN标准所描述的恢复过程(CAN RX引脚上检测到128次11个连续的隐性位)。
1.如果ABOM位为1,bxCAN进入离线状态后,就自动开启恢复过程。
2.如果ABOM位为0,软件必须先请求bxCAN进入再退出初始化模式,随后恢复过程才被开启。
**注意: ** 在初始化模式下, bxCAN不会监视CAN RX引脚的状态,这样就不能完成恢复过程, 为了完成恢复过程, bxCAN必须工作在正常模式。

4.7 位时间特性

位时间特性逻辑通过采样来监视串行的CAN总线,并且通过与帧起始位的边沿进行同步及通过与后面的边沿进行重新同步,来调整其采样点。它的操作可以简单解释为,如下所述把名义上的每位时间分为3段:

  • 同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元。
  • 时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
  • ** 时间段2(BS2)**:定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。

重新同步跳跃宽度(SJW)定义了在每位中可以延长或缩短多少个时间单元的上限。其值可以编程为1到4个时间单元。有效跳变被定义为,当bxCAN自己没有发送隐性位时,从显性位到隐性位的第1次转变。如果在时间段1(BS1)而不是在同步段(SYNC_SEG)检测到有效跳变,那么BS1的时间就被延长最多SJW那么长,从而采样点被延迟了。相反如果在时间段2(BS2)而不是在SYNC_SEG检测到有效跳变,那么BS2的时间就被缩短最多SJW那么长,从而采样点被提前了。为了避免软件的编程错误,对位时间特性寄存器(CAN_BTR)的设置,只能在bxCAN处于初始化状态下进行。

STM32F10x之CAN_第8张图片
图7 位时序

波特率=APBCLK/BRP(1+BS1+BS2)
采样点=((1+BS1)/(1+BS1+BS2))
100%
采样点建议:

  • 当波特率>800k,采样点建议75%
  • 当波特率>500k,采样点建议80%
  • 当波特率<=500k,采样点建议87.5%

4.8 中断

bxCAN占用4个专用的中断向量。通过设置CAN中断允许寄存器(CAN_IER),每个中断源都可以单独允许和禁用。

STM32F10x之CAN_第9张图片
图8 事件标志和中断产生

发送中断(USB_HP_CAN1_TX_IRQn)可由下列事件产生:

  • 发送邮箱0变为空, CAN_TSR寄存器的RQCP0位被置1。
  • 发送邮箱1变为空, CAN_TSR寄存器的RQCP1位被置1。
  • 发送邮箱2变为空, CAN_TSR寄存器的RQCP2位被置1。

FIFO0中断(USB_LP_CAN1_RX0_IRQn)可由下列事件产生:

  • FIFO0接收到一个新报文, CAN_RF0R寄存器的FMP0位不再是00b。
  • FIFO0变为满的情况, CAN_RF0R寄存器的FULL0位被置1。
  • FIFO0发生溢出的情况, CAN_RF0R寄存器的FOVR0位被置1。

FIFO1中断(CAN1_RX1_IRQn)可由下列事件产生:

  • FIFO1接收到一个新报文, CAN_RF1R寄存器的FMP1位不再是00b。
  • FIFO1变为满的情况, CAN_RF1R寄存器的FULL1位被置1。
  • FIFO1发生溢出的情况, CAN_RF1R寄存器的FOVR1位被置1。

错误和状态变化中断(CAN1_SCE_IRQn)可由下列事件产生:

  • 出错情况,关于出错情况的详细信息请参考CAN错误状态寄存器(CAN_ESR)。
  • 唤醒情况,在CAN接收引脚上监视到帧起始位(SOF)。
  • CAN进入睡眠模式。

5 函数库

5.1 数据结构

/** 
  * @brief  CAN 初始化结构定义
  */
typedef struct
{
  uint16_t CAN_Prescaler;   /*!< 指定时间单元的长度,范围:1~1024. */
  uint8_t CAN_Mode;         /*!< 指定操作模式 */
  uint8_t CAN_SJW;          /*!< 指定再同步跳跃宽度时间单元数 */
  uint8_t CAN_BS1;          /*!< 指定BS1段时间单元数 */
  uint8_t CAN_BS2;          /*!< 指定BS2段时间单元数 */
  FunctionalState CAN_TTCM; /*!< 使能或禁止时间触发. */
  FunctionalState CAN_ABOM;  /*!< 使能或禁止自动离线恢复. */
  FunctionalState CAN_AWUM;  /*!< 使能或禁止自动唤醒. */
  FunctionalState CAN_NART;  /*!< 使能或禁止不自动重传. */
  FunctionalState CAN_RFLM;  /*!< 使能或禁止接收FIFO锁模式. */
  FunctionalState CAN_TXFP;  /*!< 使能或禁止发送FIFO优先级. */
} CAN_InitTypeDef;

/** 
  * @brief  CAN 过滤器初始化结构定义
  */
typedef struct
{
 uint16_t CAN_FilterIdHigh;         /*!< 指定过滤器标识符高16位 */
 uint16_t CAN_FilterIdLow;          /*!< 指定过滤器标识符低16位 */
 uint16_t CAN_FilterMaskIdHigh;     /*!< 指定过滤器掩码高16位 */
 uint16_t CAN_FilterMaskIdLow;      /*!< 指定过滤器掩码低16位 */
 uint16_t CAN_FilterFIFOAssignment; /*!< 指定过滤器组FIFO分配 */
 uint8_t CAN_FilterNumber;          /*!< 指定过滤器组序号,范围:0~13. */
 uint8_t CAN_FilterMode;            /*!< 指定过滤器模式 */
 uint8_t CAN_FilterScale;           /*!< 指定过滤器宽度 */
 FunctionalState CAN_FilterActivation; /*!< 使能或禁止过滤器组. */
} CAN_FilterInitTypeDef;

/** 
  * @brief  CAN Tx message structure definition  
  */
typedef struct
{
  uint32_t StdId;  /*!< 指定标准帧ID,范围: 0 to 0x7FF. */
  uint32_t ExtId;  /*!< 指定扩展帧ID,范围:0 to 0x1FFFFFFF. */
  uint8_t IDE;     /*!< 指定标识符类型: 标准帧或扩展帧 */
  uint8_t RTR;     /*!< 指定帧类型: 数据帧或远程帧*/
  uint8_t DLC;     /*!< 指定帧数据长度,0~8 */
  uint8_t Data[8]; /*!< 待传输数据,数据范围:0 ~ 0xFF. */
} CanTxMsg;

/** 
  * @brief  CAN Rx message structure definition  
  */
typedef struct
{
  uint32_t StdId;  /*!< 指定标准帧ID,范围: 0 to 0x7FF. */
  uint32_t ExtId;  /*!< 指定扩展帧ID,范围:0 to 0x1FFFFFFF. */
  uint8_t IDE;     /*!< 指定标识符类型: 标准帧或扩展帧 */
  uint8_t RTR;     /*!< 指定帧类型: 数据帧或远程帧*/
  uint8_t DLC;     /*!< 指定帧数据长度,0~8 */
  uint8_t Data[8]; /*!< 待传输数据,数据范围:0 ~ 0xFF. */
  uint8_t FMI;     /*!< 指定帧的过滤器号 */
} CanRxMsg;

5.2 库函数

函数名 描述
CAN_DeInit 将外设CAN 的全部寄存器重设为缺省值
CAN_Init 根据 CAN_InitStruct 中指定的参数初始化外设 CAN 的寄存器
CAN_FilterInit 根据 CAN_FilterInitStruct 中指定的参数初始化外设 CAN 的寄存器
CAN_StructInit 把 CAN_InitStruct 中的每一个参数按缺省值填入
CAN_TTComModeCmd 使能或失能时间触发模式
CAN_ITConfig 使能或者失能指定的 CAN 中断
CAN_Transmit 开始一个消息的传输
CAN_TransmitStatus 检查消息传输的状态
CAN_CancelTransmit 取消一个传输请求
CAN_FIFORelease 释放一个FIFO
CAN_MessagePending 返回挂号的信息数量
CAN_Receive 接收一个消息
CAN_Sleep 使 CAN 进入低功耗模式
CAN_WakeUp 将 CAN 唤醒
CAN_GetFlagStatus 检查指定的 CAN 标志位被设置与否
CAN_ClearFlag 清除 CAN 的待处理标志位
CAN_GetITStatus 检查指定的 CAN 中断发生与否
CAN_ClearITPendingBit 清除 CAN 的中断待处理标志位

6 示例

/* 使能时钟 */
void RCC_Configuration(void)
{ 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
}

/* 配置GPIO */
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* CAN1 RX*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    /* CAN1 TX*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/* 配置中断 */
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;/* FIFO0接收中断 */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure); 
    
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;/* FIFO1接收中断 */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure); 
}

/* 配置CAN1 */
void CAN_Configuration(void)
{
    CAN_InitTypeDef        CAN_InitStructure;
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;

    CAN_DeInit(CAN1);

    CAN_StructInit(&CAN_InitStructure);

    /* CAN初始化 */
    CAN_InitStructure.CAN_TTCM=DISABLE; /* 禁止时间触发 */
    CAN_InitStructure.CAN_ABOM=ENABLE;  /* 使能离线自动恢复 */
    CAN_InitStructure.CAN_AWUM=ENABLE;  /* 使能自动唤醒 */
    CAN_InitStructure.CAN_NART=DISABLE; /* 自动重传 */
    CAN_InitStructure.CAN_RFLM=DISABLE; /* 禁止接收FIFO锁定模式 */
    CAN_InitStructure.CAN_TXFP=DISABLE; /* 禁止发送FIFO优先级 */
    CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; /* 正常工作模式 */

    /* 波特率为1000kbps*/
    CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1=CAN_BS1_5tq;
    CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;
    CAN_InitStructure.CAN_Prescaler=4;
    CAN_Init(CAN1, &CAN_InitStructure);

    /* CAN过滤器组0初始化 */
    CAN_FilterInitStructure.CAN_FilterNumber=0; /* 使用过滤器组0 */
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;/* 标识符屏蔽位模式 */
    CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;/* 位宽32位 */
    /* 接受标准帧标识符满足0~0x0x7和扩展帧标识符满足0~0x1FFFFF的报文 */
    CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
    CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;  
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;/* 分配FIFO0 */
    CAN_FilterInitStructure.CAN_FilterActivation=DISABLE;/* 激活滤器组0 */
    CAN_FilterInit(&CAN_FilterInitStructure);   /* 初始化过滤器 */

    /* CAN过滤器组1初始化 */
    CAN_FilterInitStructure.CAN_FilterNumber=1; /* 使用过滤器组1 */
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;/* 标识符列表模式 */
    CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;/* 位宽32位 */
    /* 接受标识符满足0x80、0x100、0x180和0x200的标准数据帧*/
    CAN_FilterInitStructure.CAN_FilterIdHigh=0x1000;
    CAN_FilterInitStructure.CAN_FilterIdLow=0x2000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x3000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x4000;  
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO1;/* 分配FIFO1 */
    CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;/* 激活过滤器组1 */
    CAN_FilterInit(&CAN_FilterInitStructure);/* 初始化过滤器 */
    
    /* 使能FIFO0和FIFO1消息挂起中断 */
    CAN_ITConfig(CAN1, CAN_IT_FMP0 | CAN_IT_FMP1, ENABLE);
}

你可能感兴趣的:(STM32F10x之CAN)