23.1关于 CAN
23.1.1 CAN 电气特性与协议
控制器局域网(Controller Area Network,CAN),是由德国BOSCH(博世)公司开发,是目前国际上应用最为广泛的现场总线之一。其特点是可拓展性好,可承受大量数据的高速通信,高度稳定可靠,因此常应用于汽车电子领域、工业自动化、医疗设备等高要求环境。
CAN总线有两个ISO国际标准:ISO11519 和ISO11898。
ISO11519定义了通信速率为10~125Kbps的低速CAN通信标准,属于开环总线,传输速率为40Kbps时,总线长度可达1000米;
ISO11898定义了通信速率为125Kbps~1 Mbps的高速CAN通信标准,属于闭环总线,传输速率可达1Mbps,总线长度≤40米;
高速CAN主要应用在发动机、变速箱等对实时性、传输速度要求高的场景。低速CAN主要应用在车身控制系统等可靠性要求高的场景,低速CAN在断掉其任一导线后,仍可以继续接收数据,因此在汽车发生交通事故时,使用低速CAN能更大提高设备正常接收数据工作的可能性,提高安全性。
如图 23.1.1 所示,是低速CAN的拓扑结构图,如图 23.1.2 是高速CAN的拓扑结构图。低速CAN总线为开环,高速CAN总线为闭环,总线由CAN_H和CAN_L两根线组成,总线上可以挂多个节点设备。每个节点设备由CAN控制器和CAN收发器组成,CAN控制器通常作为外设集成在MPU/MCU上,而CAN收发器则需要外围添加芯片威廉希尔官方网站
。
从两个网络拓扑结构可以看出,基于ISO11519标准的低速CAN,是一个“开环网络”,每根总线上个串联一个2.2KΩ的电阻;基于ISO11898标准的高速CAN,是一个“闭环网络”,总线的两端各需串联一个120Ω的电阻用于阻抗匹配,以减少回波反射。
类似RS485,CAN也使用差分信号传输数据。CAN总线使用CAN_H和CAN_L的电位差来表示数据电平。电位差分为显性电平和隐性电平,分别表示逻辑0和1。如图 23.1.3 所示,是低速CAN(ISO11519标准)的电平定义,如图 23.1.4 是高速CAN(ISO11898标准)的电平定义,两者物理层电气特性不一样,因此不能将它们连接在一起。可以看到当CAN_H和CAN_L电压相近,则表示隐性电平,对应逻辑1,当两个电压相差较大,表示显性电平,对应逻辑0。
CAN是一种基于消息广播模式的串行通信总线,即在同一时刻网络上所有节点监测到的数据是一致的,各节点根据报文ID来甄别是否是发给自己的报文。
CAN总线以“帧”(Frame)的形式进行通信。CAN 总线协议规定了5种帧,分别是数据帧、远程帧、错误帧、超载帧以及帧间隔,其中数据帧最常用,表 23.1.2 是各个帧的用途。
数据帧由七段组成,如图 23.1.5 所示。数据帧又分为标准帧(CAN2.0A)和扩展帧(CAN2.0B),主要体现在在仲裁段和控制段上。
帧起始(Start Of Frame-SOF):1bit,显性信号,表示数据帧(或远程帧)的开始;
仲裁段(Arbitration Field):包括标识符位(Identifier field-ID)和远程发送请求位(Remote Transfer Request,RTR);
标准帧的ID位是11位,即范围是0x000~0x7FF,而扩展帧的ID是11+18=29位;在CAN协议中,ID决定报文的优先级高低,也决定这拓扑结构的节点是否接收此ID的帧数据;
远程发送请求位,用于区分该帧是数据帧还是远程帧,显性信号(0)代表数据帧(Data Frame),隐性信号(1)代表远程帧(Remote Frame);
控制段(Control Field):标准帧中由扩展标识符位(Identifier Extension bit-IDE,1 bit)、保留位0(Reseved bit0-r0,1 bit)、数据长度编码位(Data Length Code-DLC,4 bits)组成;扩展帧用由两个保留位(Reseved bit,2 bit)、数据长度编码位(Data Length Code-DLC,4 bits)组成;
数据段(Data Field):发送数据的内容,最多8个字节(64bit),它的实际长度会写到前面的数据长度编码位DLC里。
循环校验段(CRC Field):包括循环校验序列(CRC Sequence)和界定符(Delimiter,DEL);循环校验序列用于校验传输是否正确;界定符用于表示循环校验序列是否结束;
确认段(ACK Field):包括确认位(ACK SLOT)和界定符(Delimiter,DEL);确认位在节点收到正确的CRC序列时,发送端的ACK位被置位;界定符表示确认是否正常接收;
帧结束(End of Frame-EOF):7位长度,隐性信号,表示帧的结束;
当CAN总线网络中有多个CAN节点设备时,某一CAN设备发出数据帧,总线上所有设备(无过滤时)都获取该数据帧中仲裁段中的ID,如果是自己关注ID的数据,则获取数据段的内容,完成数据的传输。
23.1.2 CAN 控制器
STM32F103系列的CAN控制器(Basic Extended CAN,bxCAN),支持CAN 2.0A和CAN 2.0B Active版本协议。CAN 2.0A只能处理标准数据帧,扩展帧的内容会识别为错误;CAN 2.0B Active可以处理标准数据帧和扩展数据帧;CAN 2.0B Passive只能处理标准数据帧,扩展帧的内容会忽略。
STM32F103系列只有一个CAN控制器,STM32F105/STM32F107互联型有两个CAN控制器,互联型内部CAN控制器结构如图 23.1.6 所示,⑤是CAN2,STM32F103系列没有,先忽略。
①CAN1内核:包含各种控制、状态、配置寄存器。其中比较重要的是主控制寄存器(CAN_MCR)和位时序寄存器(CAN_BTR)。主控制寄存器主要控制CAN的工作模式,在后面设置CAN协议初始化时,实现对该寄存器的修改。位时序寄存器主要涉及CAN的工作速率,由于CAN是异步信号,同串口类似,需要收发双方提前统一通信速率。除此之外,为保证通信稳定,CAN采用“位同步”机制,实现对电平的正确采样。传输中的每位数据由四段组成:同步段(Synchronization Segment,SS)、传播时间段(Propagation TimeSegment,PTS)、相位缓冲段1(Phase Buffer Segment 1,PBS1)和相位缓冲段2(Phase Buffer Segment 2, PBS2)。每段又由多个位时序(Time Quantum,Tq)组成,如图 23.1.6 所示,为各段组成示意图。
假设CAN对应逻辑电平持续的时间为9Tq,即一位数据持续的时间为9Tq。其中SS段长度为1Tq(只能为1Tq),PTS段长度为2Tq(范围为18Tq),PSB1段长度为3Tq(范围为18Tq),PSB2段长度为3Tq(范围为2~8Tq)。采样点在PSB1和PSB2之间,调整各段的长度,即可对采样点位置进行调整,实现补偿准确采样。
如图 23.1.8 所示,为STM32F103系列的CAN控制器位时序,和标准CAN协议的位时序略有不同。STM32只有三段,同步段长度为1Tq(只能为1Tq),标准CAN协议中的PTS段和PSB1合并为位段1(范围为1-16Tq),标准CAN协议中的PSB2段对应位段2(范围为1-8Tq)。
当知道CAN控制器的工作时钟频率、tBS1和tBS2的长度时,即可计算出CAN传输的波特率,关系如下:
Tq=(BRP[9:0]+1) x tPCLK,BRP[9:0]为Tq长度,tPCLK为APB时钟周期;
tBS1=Tq x (TS1[3:0] + 1),TS1[3:0]位于CAN_BTR寄存器中;
tBS2=Tq x (TS2[2:0] + 1),TS2[2:0]位于CAN_BTR寄存器中;由图 6.1.2 可知,bxCAN挂在APB1总线上,当系统时钟为最高72MHz时,APB1时钟最高为36MHz。此时若BRP[9:0]+1为8,TS1[3:0] + 1为6,TS2[2:0] + 1为2,则波特率为:
② 发送邮箱:STM32F103的CAN控制器有三个发送邮箱,可最多缓存三个待发送的报文。由传输调度负责决定邮箱报文的发送顺序。
③接收FIFO:STM32F103的CAN控制器有两个个接收FIFO来存储传入的数据,每个FIFO由三个邮箱存储三个接收到报文。
④:验收筛选器:STM32F105/STM32F107互联型有28个筛选器,STM32F103系列只有14个筛选器(编号0~13)。前面介绍CAN协议介绍到,在CAN总线网络中,总线上的所有设备都获取总线数据帧中ID,如果是自己关注的ID,则继续获取数据段的内容。当总线上报文过多时,每个CAN设备将频繁获取报文,消耗比较大。因此,提供筛选器实现选择性的获取报文,降低系统负担。
每个筛选器组由两个32位寄存器CAN_FxR1和CAN_FxR2组成。根据不同的实际需求,筛选器支持设置筛选范围和筛选模式。
筛选范围可设置为32位和16位,两种方式筛选的范围有所差异:
32位方式:筛选报文的STDID[10:0]、EXTID[17:0]、IDE、RTR;
16位方式:筛选报文的STDID[10:0]、EXTID[17:15]、IDE、RTR;筛选模式可设置为列表模式和掩码模式,前者常用于筛选单个标识符,后者常用于筛选单组标识符:
列表模式:此时两个寄存器都作为标识符寄存器,这两个标识符寄存器组成一个表,只有在此列表中的ID,才能通过筛选器,存入FIFO;
掩码模式:此时两个寄存器作为标识符寄存器和掩码寄存器,根据掩码寄存器指定的哪些位与标识符寄存器匹配的ID,才能通过筛选器,存入FIFO;
举个例子,如表 23.1.3 所示,ID为0xF,掩码为0x7FC。掩码位为1表示必须与ID一致,掩码位为0表示可不与ID一致,因此结果bit[1:0]为任意值,其它都需要与ID一致,则最后结果为11XX,即0xC~0xF之间的ID都可经过筛选器存入FIFO,其它则无法通过;
如图 23.1.9 所示,通过设置筛选范围和筛选模式进行组合,每个筛选器有四种情况。
①FSCx=1,FBMx=0:处于32位掩码模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,一个存放ID,一个存放掩码;
②FSCx=1,FBMx=1:处于32位列表模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,两个都存放ID,组成列表;
③FSCx=0,FBMx=0:处于16位掩码模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,它们各自低16位存放ID,高16位存放掩码;
②FSCx=0,FBMx=1:处于16位列表模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,它们各自低16位和高16位都存放ID,组成列表;
举个例子,假设CAN总线上有ID为0至99的100个报文,现在只需要ID为0-5的报文,筛选器该如何设置?首先设置筛选器组0处于32位掩码模式,ID为0x0,掩码为0x7FC,结果将筛选出0x0-0x3。接着设置筛选器组1处于32位列表模式,列表两个ID分别设为0x04和0x05。最后ID为0x0~0x05的报文将通过筛
关于CAN的基础介绍就到这里,读者重点理解CAN电气特性、数据帧结构、STM32的CAN控制器波特率和筛选器。
23.2 硬件设计
如图 23.2.1 为开发板CAN部分的原理图。U17为CAN收发器TJA1042芯片,该芯片将MCU的CAN控制器的逻辑电平转换成差分信号,发送到CAN总线中。
U17的1脚接MCU的CAN发送引脚(PB9),2脚接MCU的CAN接收引脚(PB8), 7脚、8脚为CAN输出引脚,上面挂了一个120欧的终端电阻,工作在高速CAN模式。
另外,CAN和RS485都是半双工的差分信号,需要两个设备连接测试。百问网制作了一个CAN/RS485互转模块,可以直接连接到100ASK系列开发板上,实现RS485的CAN的透传,同时验证、学习两个接口,该模块外形如图 23.2.2 所示。
该模块左边是RS485接口(波特率9600bps,无校验,8位数据位,1位停止位),右边是CAN接口(波特率500Kbps,屏蔽位模式,允许所有帧接收),中间是转换芯片,实现协议转换。由于CAN协议中包含有ID, 而RS485不存在ID。因此,当RS485转CAN时,模块会自动加上0x00的ID,当CAN转RS485时,RS485只会收到数据部分,扔掉ID部分。
23.3 软件设计
23.3.1 软件设计思路
实验目的:本实验通过RS485_CAN互转模块,实现RS485和CAN互传数据,让读者熟悉如何使用CAN。开发板的RS485首先发送数据,经过RS485_CAN互转模块变为CAN信号,传入开发板CAN接口;开发板CAN接口接到数据后,CAN再发送数据,经过RS485_CAN互转模块变为RS485信号,传入开发板R485接口。
初始化CAN协议相关参数和筛选器:设置预分频、位段长度等实现需要的500Kbps波特率;
初始化CAN硬件相关参数:CAN时钟使能、GPIO端口时钟使能、引脚重映射、中断优先级等;
使用HAL提供的CAN收发函数,收发数据;
主函数编写控制逻辑:按下按键KEY1(KEY_U),RS485发送数据,经过RS485_CAN互转模块传入CAN接口并打印,随后CAN接口发送数据,经过RS485_CAN互转模块传入RS485接口并打印;本实验配套代码位于“5_程序源码15_通信—CAN”。
23.3.2 软件设计讲解
初始化CAN
CAN的初始化,包含两部分:协议部分和硬件部分。
协议部分初始化如代码段 23.3.1 所示。
代码段 23.3.1 CAN 协议初始化(driver_can.c)
12~25行:设置CAN协议参数;
12行:设置哪一个CAN控制器,STM32F103ZET6只有一个CAN控制器;
15行:设置时钟的预分频,与后面的位段时间长度组合,实现需要的500Kbps,这里先设置为8分频;
16行:设置CAN工作模式,CAN控制有四种模式:正常模式、静默模式、回环模式及静默回环模式,通常设置为正常模式即可;
17行:设置再次同步补偿宽度,因时钟频率偏差、传送延迟等,各单元有同步误差,这里设置补偿此误差的最大值,范围为1~4Tq;
18行:设置位段1(BS1)的长度为6Tq;
19行:设置位段2(BS2)的长度为2Tq,由前面的波特率计算公式可得:36M/(1+6+2)/8 = 500Kbps;
20行:设置间触发通信模式,禁止时间触发通信模式;
21行:禁止总线自动关闭,控制CAN在退出总线关闭状态时的行为;
22行:禁止自动唤醒,控制CAN在眠模式下接收到消息时的行为;
23行:开启自动重传,CAN将自动重发消息,直到CAN消息发送成功;关闭后,无论成功、错误或仲裁丢失,都只发送一次;
24行:禁止接收FIFO锁定,当接收FIFO装满后,下一条传入消息将覆盖前一条消息;使能后,接收FIFO装满后,下一条传入消息将被丢弃;
25行:禁止传输FIFO优先级,则优先级由消息标识符决定;使能后,由请求顺序(时间顺序)决定;
27~30行:初始化前面设置的CAN参数,同时会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”;
32~41行:设置CAN筛选器;
33行:设置哪一个CAN筛选器组,设置设置筛选器组0,STM32F103ZET6共有14个筛选器组;
34行:“CAN_FILTERMODE_IDMASK”设置为掩码模式,“CAN_FILTERMODE_IDLIST”设置为列表模式;
35行:设置筛选范围可设置为32位;
36~37行:设置ID的高低字节,这里设置ID为0;
38~39行:设置掩码的高低字节,这里设置掩码为0,则没有做任何过滤;
40行:设置本筛选器的消息存储在哪个FIFO(接收FIFO共有两个);
41行:使能本筛选器;
43~46行:配置前面设置的筛选器;
48~52行:启动CAN;
54~58行:使能CAN接收FIFO0的中断;注意这里使能的是FIFO0,需要和前面设置筛选器的FIFO保持一致;这里可以设置三种类型FIFO中断,分别为“CAN_IT_RX_FIFO0_MSG_PENDING”FIFO接收到数据就
产生中断、“CAN_IT_RX_FIFO0_FULL”FIFO接收满后产生中断“CAN_IT_RX_FIFO0_OVERRUN”FIFO溢出产生中断;
前面“HAL_CAN_Init()”会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”,该函数需要我们自己完善,如代码段 23.3.2 所示。
代码段 23.3.2 CAN 硬件初始化(driver_can.c)
需要注意,PB8、PB9如果用于CAN引脚,不是引脚典型复用,而是需要引脚复用重映射,如图 23.3.1所示为《数据手册》部分引脚描述截图。因此代码段 23.3.2 中14~15行需要先使能重映射时钟,再重映射CAN功能。
封装CAN发送函数和接收回调函数
初始化完CAN后,便可以调用HAL库提供的“HAL_CAN_AddTxMessage()”将报文放入发送信箱,供CAN控制器发送。在这之前,需要准备好报文,如代码段 23.3.3 所示。
代码段 23.3.3 CAN 发送函数(driver_can.c)
12~23行:准备发送报文;
初始化CAN
CAN的初始化,包含两部分:协议部分和硬件部分。
协议部分初始化如代码段 23.3.1 所示。
代码段 23.3.1 CAN 协议初始化(driver_can.c)
12~25行:设置CAN协议参数;
12行:设置哪一个CAN控制器,STM32F103ZET6只有一个CAN控制器;
15行:设置时钟的预分频,与后面的位段时间长度组合,实现需要的500Kbps,这里先设置为8分频;
16行:设置CAN工作模式,CAN控制有四种模式:正常模式、静默模式、回环模式及静默回环模式,通常设置为正常模式即可;
17行:设置再次同步补偿宽度,因时钟频率偏差、传送延迟等,各单元有同步误差,这里设置补偿此误差的最大值,范围为1~4Tq;
18行:设置位段1(BS1)的长度为6Tq;
19行:设置位段2(BS2)的长度为2Tq,由前面的波特率计算公式可得:36M/(1+6+2)/8 = 500Kbps;
20行:设置间触发通信模式,禁止时间触发通信模式;
21行:禁止总线自动关闭,控制CAN在退出总线关闭状态时的行为;
22行:禁止自动唤醒,控制CAN在眠模式下接收到消息时的行为;
23行:开启自动重传,CAN将自动重发消息,直到CAN消息发送成功;关闭后,无论成功、错误或仲裁丢失,都只发送一次;
24行:禁止接收FIFO锁定,当接收FIFO装满后,下一条传入消息将覆盖前一条消息;使能后,接收FIFO装满后,下一条传入消息将被丢弃;
25行:禁止传输FIFO优先级,则优先级由消息标识符决定;使能后,由请求顺序(时间顺序)决定;
27~30行:初始化前面设置的CAN参数,同时会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”;
32~41行:设置CAN筛选器;
33行:设置哪一个CAN筛选器组,设置设置筛选器组0,STM32F103ZET6共有14个筛选器组;
34行:“CAN_FILTERMODE_IDMASK”设置为掩码模式,“CAN_FILTERMODE_IDLIST”设置为列表模式;
35行:设置筛选范围可设置为32位;
36~37行:设置ID的高低字节,这里设置ID为0;
38~39行:设置掩码的高低字节,这里设置掩码为0,则没有做任何过滤;
40行:设置本筛选器的消息存储在哪个FIFO(接收FIFO共有两个);
41行:使能本筛选器;
43~46行:配置前面设置的筛选器;
48~52行:启动CAN;
54~58行:使能CAN接收FIFO0的中断;注意这里使能的是FIFO0,需要和前面设置筛选器的FIFO保持一致;这里可以设置三种类型FIFO中断,分别为:“CAN_IT_RX_FIFO0_MSG_PENDING”FIFO接收到数据就产生中断、“CAN_IT_RX_FIFO0_FULL”FIFO接收满后产生中断、“CAN_IT_RX_FIFO0_OVERRUN”FIFO溢出产生中断;
前面“HAL_CAN_Init()”会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”,该函数需要我们自己完善,如代码段 23.3.2 所示。
代码段 23.3.2 CAN 硬件初始化(driver_can.c)
需要注意,PB8、PB9如果用于CAN引脚,不是引脚典型复用,而是需要引脚复用重映射,如图 23.3.1所示为《数据手册》部分引脚描述截图。因此代码段 23.3.2 中14~15行需要先使能重映射时钟,再重映射CAN功能。
封装CAN发送函数和接收回调函数
初始化完CAN后,便可以调用HAL库提供的“HAL_CAN_AddTxMessage()”将报文放入发送信箱,供CAN控制器发送。在这之前,需要准备好报文,如代码段 23.3.3 所示。
代码段 23.3.3 CAN 发送函数(driver_can.c)
12~23行:准备发送报文;
12行:定义变量“tx_mailbox”,保存返回的邮箱编号;
13~16行:限制每次报文,数据最多8字节;
18行:设置报文的标准标识符;
19行:设置报文的扩展标识符;
20行:设置帧模式,这里设置为标准帧;
21行:设置帧类型,这里设置为数据帧;
22行:设置数据长度;
23行:设置帧传输时是否获取时间标记,通常关闭;
25~28行:调用“HAL_CAN_AddTxMessage()”发送报文;
前面设置了CAN中断和中断优先级,当CAN控制器,发送完成或接收完成时,都将跳转到中断向量表的对应位置,执行中断处理函数,如代码段 23.3.4 所示。
代码段 23.3.4 CAN 中断处理函数(driver_can.c)
1~5行:CAN1发送完成时,将进入中断向量“CAN1_TX0_IRQHandler”。这里发送完成后,不需要任何操作,因此没有编写发送完成的中断函数;
7~11行:CAN1接收完成时,将进入中断向量“CAN1_RX0_IRQHandler”。这里接收完成后,会调用一系列中断函数,其中“HAL_CAN_RxFifo0MsgPendingCallback()”为接收FIFO0消息等待回调函数;
13~30行:编写接收FIFO0消息等待回调函数,使用“HAL_CAN_GetRxMessage()”获取报文,随后修改接收标志位,以便其它函数查询是否接收到数据;
本实验中涉及的RS485、串口打印、按键等实现,参考之前相关章节的讲解。
主函数控制逻辑
在主函数里,每按一下按键,先构造RS485要发送的数据,然后调用“RS485_Tx()”发送数据。随后查询CAN是否收到数据,如果收到数据,打印CAN收到的数据。接着,构造CAN要发送的ID和数据,调用“CAN_Transmit()”发送报文,然后使用“RS485_Rx()”接收数据,并打印,如代码段 23.3.5 所示。
代码段 23.3.5 主函数控制逻辑(main.c)
23.4 实验效果
本实验对应配套资料的“5_程序源码15_通信—CAN”。打开工程后,编译,下载。按图 23.4.1 所示,将开发板、RS485_CAN互转模块连接,开发板的CAN接模块的CAN,开发板的RS485接模块的RS485,且线都不交叉,注意此时的J11(蓝色拨码开关)的1脚拨为ON。
按下按键KEY1(KEY_U),即可看到串口如图 23.4.2 所示。首先RS485发送数据,CAN接收到相同的数据,RS485_CAN互换模块为CAN添加了0x0的ID。随便CAN发送数据,RS485接收到相同的数据,CAN报文的ID被RS485_CAN互换模块省略。
23.1关于 CAN
23.1.1 CAN 电气特性与协议
控制器局域网(Controller Area Network,CAN),是由德国BOSCH(博世)公司开发,是目前国际上应用最为广泛的现场总线之一。其特点是可拓展性好,可承受大量数据的高速通信,高度稳定可靠,因此常应用于汽车电子领域、工业自动化、医疗设备等高要求环境。
CAN总线有两个ISO国际标准:ISO11519 和ISO11898。
ISO11519定义了通信速率为10~125Kbps的低速CAN通信标准,属于开环总线,传输速率为40Kbps时,总线长度可达1000米;
ISO11898定义了通信速率为125Kbps~1 Mbps的高速CAN通信标准,属于闭环总线,传输速率可达1Mbps,总线长度≤40米;
高速CAN主要应用在发动机、变速箱等对实时性、传输速度要求高的场景。低速CAN主要应用在车身控制系统等可靠性要求高的场景,低速CAN在断掉其任一导线后,仍可以继续接收数据,因此在汽车发生交通事故时,使用低速CAN能更大提高设备正常接收数据工作的可能性,提高安全性。
如图 23.1.1 所示,是低速CAN的拓扑结构图,如图 23.1.2 是高速CAN的拓扑结构图。低速CAN总线为开环,高速CAN总线为闭环,总线由CAN_H和CAN_L两根线组成,总线上可以挂多个节点设备。每个节点设备由CAN控制器和CAN收发器组成,CAN控制器通常作为外设集成在MPU/MCU上,而CAN收发器则需要外围添加芯片威廉希尔官方网站
。
从两个网络拓扑结构可以看出,基于ISO11519标准的低速CAN,是一个“开环网络”,每根总线上个串联一个2.2KΩ的电阻;基于ISO11898标准的高速CAN,是一个“闭环网络”,总线的两端各需串联一个120Ω的电阻用于阻抗匹配,以减少回波反射。
类似RS485,CAN也使用差分信号传输数据。CAN总线使用CAN_H和CAN_L的电位差来表示数据电平。电位差分为显性电平和隐性电平,分别表示逻辑0和1。如图 23.1.3 所示,是低速CAN(ISO11519标准)的电平定义,如图 23.1.4 是高速CAN(ISO11898标准)的电平定义,两者物理层电气特性不一样,因此不能将它们连接在一起。可以看到当CAN_H和CAN_L电压相近,则表示隐性电平,对应逻辑1,当两个电压相差较大,表示显性电平,对应逻辑0。
CAN是一种基于消息广播模式的串行通信总线,即在同一时刻网络上所有节点监测到的数据是一致的,各节点根据报文ID来甄别是否是发给自己的报文。
CAN总线以“帧”(Frame)的形式进行通信。CAN 总线协议规定了5种帧,分别是数据帧、远程帧、错误帧、超载帧以及帧间隔,其中数据帧最常用,表 23.1.2 是各个帧的用途。
数据帧由七段组成,如图 23.1.5 所示。数据帧又分为标准帧(CAN2.0A)和扩展帧(CAN2.0B),主要体现在在仲裁段和控制段上。
帧起始(Start Of Frame-SOF):1bit,显性信号,表示数据帧(或远程帧)的开始;
仲裁段(Arbitration Field):包括标识符位(Identifier field-ID)和远程发送请求位(Remote Transfer Request,RTR);
标准帧的ID位是11位,即范围是0x000~0x7FF,而扩展帧的ID是11+18=29位;在CAN协议中,ID决定报文的优先级高低,也决定这拓扑结构的节点是否接收此ID的帧数据;
远程发送请求位,用于区分该帧是数据帧还是远程帧,显性信号(0)代表数据帧(Data Frame),隐性信号(1)代表远程帧(Remote Frame);
控制段(Control Field):标准帧中由扩展标识符位(Identifier Extension bit-IDE,1 bit)、保留位0(Reseved bit0-r0,1 bit)、数据长度编码位(Data Length Code-DLC,4 bits)组成;扩展帧用由两个保留位(Reseved bit,2 bit)、数据长度编码位(Data Length Code-DLC,4 bits)组成;
数据段(Data Field):发送数据的内容,最多8个字节(64bit),它的实际长度会写到前面的数据长度编码位DLC里。
循环校验段(CRC Field):包括循环校验序列(CRC Sequence)和界定符(Delimiter,DEL);循环校验序列用于校验传输是否正确;界定符用于表示循环校验序列是否结束;
确认段(ACK Field):包括确认位(ACK SLOT)和界定符(Delimiter,DEL);确认位在节点收到正确的CRC序列时,发送端的ACK位被置位;界定符表示确认是否正常接收;
帧结束(End of Frame-EOF):7位长度,隐性信号,表示帧的结束;
当CAN总线网络中有多个CAN节点设备时,某一CAN设备发出数据帧,总线上所有设备(无过滤时)都获取该数据帧中仲裁段中的ID,如果是自己关注ID的数据,则获取数据段的内容,完成数据的传输。
23.1.2 CAN 控制器
STM32F103系列的CAN控制器(Basic Extended CAN,bxCAN),支持CAN 2.0A和CAN 2.0B Active版本协议。CAN 2.0A只能处理标准数据帧,扩展帧的内容会识别为错误;CAN 2.0B Active可以处理标准数据帧和扩展数据帧;CAN 2.0B Passive只能处理标准数据帧,扩展帧的内容会忽略。
STM32F103系列只有一个CAN控制器,STM32F105/STM32F107互联型有两个CAN控制器,互联型内部CAN控制器结构如图 23.1.6 所示,⑤是CAN2,STM32F103系列没有,先忽略。
①CAN1内核:包含各种控制、状态、配置寄存器。其中比较重要的是主控制寄存器(CAN_MCR)和位时序寄存器(CAN_BTR)。主控制寄存器主要控制CAN的工作模式,在后面设置CAN协议初始化时,实现对该寄存器的修改。位时序寄存器主要涉及CAN的工作速率,由于CAN是异步信号,同串口类似,需要收发双方提前统一通信速率。除此之外,为保证通信稳定,CAN采用“位同步”机制,实现对电平的正确采样。传输中的每位数据由四段组成:同步段(Synchronization Segment,SS)、传播时间段(Propagation TimeSegment,PTS)、相位缓冲段1(Phase Buffer Segment 1,PBS1)和相位缓冲段2(Phase Buffer Segment 2, PBS2)。每段又由多个位时序(Time Quantum,Tq)组成,如图 23.1.6 所示,为各段组成示意图。
假设CAN对应逻辑电平持续的时间为9Tq,即一位数据持续的时间为9Tq。其中SS段长度为1Tq(只能为1Tq),PTS段长度为2Tq(范围为18Tq),PSB1段长度为3Tq(范围为18Tq),PSB2段长度为3Tq(范围为2~8Tq)。采样点在PSB1和PSB2之间,调整各段的长度,即可对采样点位置进行调整,实现补偿准确采样。
如图 23.1.8 所示,为STM32F103系列的CAN控制器位时序,和标准CAN协议的位时序略有不同。STM32只有三段,同步段长度为1Tq(只能为1Tq),标准CAN协议中的PTS段和PSB1合并为位段1(范围为1-16Tq),标准CAN协议中的PSB2段对应位段2(范围为1-8Tq)。
当知道CAN控制器的工作时钟频率、tBS1和tBS2的长度时,即可计算出CAN传输的波特率,关系如下:
Tq=(BRP[9:0]+1) x tPCLK,BRP[9:0]为Tq长度,tPCLK为APB时钟周期;
tBS1=Tq x (TS1[3:0] + 1),TS1[3:0]位于CAN_BTR寄存器中;
tBS2=Tq x (TS2[2:0] + 1),TS2[2:0]位于CAN_BTR寄存器中;由图 6.1.2 可知,bxCAN挂在APB1总线上,当系统时钟为最高72MHz时,APB1时钟最高为36MHz。此时若BRP[9:0]+1为8,TS1[3:0] + 1为6,TS2[2:0] + 1为2,则波特率为:
② 发送邮箱:STM32F103的CAN控制器有三个发送邮箱,可最多缓存三个待发送的报文。由传输调度负责决定邮箱报文的发送顺序。
③接收FIFO:STM32F103的CAN控制器有两个个接收FIFO来存储传入的数据,每个FIFO由三个邮箱存储三个接收到报文。
④:验收筛选器:STM32F105/STM32F107互联型有28个筛选器,STM32F103系列只有14个筛选器(编号0~13)。前面介绍CAN协议介绍到,在CAN总线网络中,总线上的所有设备都获取总线数据帧中ID,如果是自己关注的ID,则继续获取数据段的内容。当总线上报文过多时,每个CAN设备将频繁获取报文,消耗比较大。因此,提供筛选器实现选择性的获取报文,降低系统负担。
每个筛选器组由两个32位寄存器CAN_FxR1和CAN_FxR2组成。根据不同的实际需求,筛选器支持设置筛选范围和筛选模式。
筛选范围可设置为32位和16位,两种方式筛选的范围有所差异:
32位方式:筛选报文的STDID[10:0]、EXTID[17:0]、IDE、RTR;
16位方式:筛选报文的STDID[10:0]、EXTID[17:15]、IDE、RTR;筛选模式可设置为列表模式和掩码模式,前者常用于筛选单个标识符,后者常用于筛选单组标识符:
列表模式:此时两个寄存器都作为标识符寄存器,这两个标识符寄存器组成一个表,只有在此列表中的ID,才能通过筛选器,存入FIFO;
掩码模式:此时两个寄存器作为标识符寄存器和掩码寄存器,根据掩码寄存器指定的哪些位与标识符寄存器匹配的ID,才能通过筛选器,存入FIFO;
举个例子,如表 23.1.3 所示,ID为0xF,掩码为0x7FC。掩码位为1表示必须与ID一致,掩码位为0表示可不与ID一致,因此结果bit[1:0]为任意值,其它都需要与ID一致,则最后结果为11XX,即0xC~0xF之间的ID都可经过筛选器存入FIFO,其它则无法通过;
如图 23.1.9 所示,通过设置筛选范围和筛选模式进行组合,每个筛选器有四种情况。
①FSCx=1,FBMx=0:处于32位掩码模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,一个存放ID,一个存放掩码;
②FSCx=1,FBMx=1:处于32位列表模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,两个都存放ID,组成列表;
③FSCx=0,FBMx=0:处于16位掩码模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,它们各自低16位存放ID,高16位存放掩码;
②FSCx=0,FBMx=1:处于16位列表模式,此时两个32位寄存器CAN_FxR1和CAN_FxR2,它们各自低16位和高16位都存放ID,组成列表;
举个例子,假设CAN总线上有ID为0至99的100个报文,现在只需要ID为0-5的报文,筛选器该如何设置?首先设置筛选器组0处于32位掩码模式,ID为0x0,掩码为0x7FC,结果将筛选出0x0-0x3。接着设置筛选器组1处于32位列表模式,列表两个ID分别设为0x04和0x05。最后ID为0x0~0x05的报文将通过筛
关于CAN的基础介绍就到这里,读者重点理解CAN电气特性、数据帧结构、STM32的CAN控制器波特率和筛选器。
23.2 硬件设计
如图 23.2.1 为开发板CAN部分的原理图。U17为CAN收发器TJA1042芯片,该芯片将MCU的CAN控制器的逻辑电平转换成差分信号,发送到CAN总线中。
U17的1脚接MCU的CAN发送引脚(PB9),2脚接MCU的CAN接收引脚(PB8), 7脚、8脚为CAN输出引脚,上面挂了一个120欧的终端电阻,工作在高速CAN模式。
另外,CAN和RS485都是半双工的差分信号,需要两个设备连接测试。百问网制作了一个CAN/RS485互转模块,可以直接连接到100ASK系列开发板上,实现RS485的CAN的透传,同时验证、学习两个接口,该模块外形如图 23.2.2 所示。
该模块左边是RS485接口(波特率9600bps,无校验,8位数据位,1位停止位),右边是CAN接口(波特率500Kbps,屏蔽位模式,允许所有帧接收),中间是转换芯片,实现协议转换。由于CAN协议中包含有ID, 而RS485不存在ID。因此,当RS485转CAN时,模块会自动加上0x00的ID,当CAN转RS485时,RS485只会收到数据部分,扔掉ID部分。
23.3 软件设计
23.3.1 软件设计思路
实验目的:本实验通过RS485_CAN互转模块,实现RS485和CAN互传数据,让读者熟悉如何使用CAN。开发板的RS485首先发送数据,经过RS485_CAN互转模块变为CAN信号,传入开发板CAN接口;开发板CAN接口接到数据后,CAN再发送数据,经过RS485_CAN互转模块变为RS485信号,传入开发板R485接口。
初始化CAN协议相关参数和筛选器:设置预分频、位段长度等实现需要的500Kbps波特率;
初始化CAN硬件相关参数:CAN时钟使能、GPIO端口时钟使能、引脚重映射、中断优先级等;
使用HAL提供的CAN收发函数,收发数据;
主函数编写控制逻辑:按下按键KEY1(KEY_U),RS485发送数据,经过RS485_CAN互转模块传入CAN接口并打印,随后CAN接口发送数据,经过RS485_CAN互转模块传入RS485接口并打印;本实验配套代码位于“5_程序源码15_通信—CAN”。
23.3.2 软件设计讲解
初始化CAN
CAN的初始化,包含两部分:协议部分和硬件部分。
协议部分初始化如代码段 23.3.1 所示。
代码段 23.3.1 CAN 协议初始化(driver_can.c)
12~25行:设置CAN协议参数;
12行:设置哪一个CAN控制器,STM32F103ZET6只有一个CAN控制器;
15行:设置时钟的预分频,与后面的位段时间长度组合,实现需要的500Kbps,这里先设置为8分频;
16行:设置CAN工作模式,CAN控制有四种模式:正常模式、静默模式、回环模式及静默回环模式,通常设置为正常模式即可;
17行:设置再次同步补偿宽度,因时钟频率偏差、传送延迟等,各单元有同步误差,这里设置补偿此误差的最大值,范围为1~4Tq;
18行:设置位段1(BS1)的长度为6Tq;
19行:设置位段2(BS2)的长度为2Tq,由前面的波特率计算公式可得:36M/(1+6+2)/8 = 500Kbps;
20行:设置间触发通信模式,禁止时间触发通信模式;
21行:禁止总线自动关闭,控制CAN在退出总线关闭状态时的行为;
22行:禁止自动唤醒,控制CAN在眠模式下接收到消息时的行为;
23行:开启自动重传,CAN将自动重发消息,直到CAN消息发送成功;关闭后,无论成功、错误或仲裁丢失,都只发送一次;
24行:禁止接收FIFO锁定,当接收FIFO装满后,下一条传入消息将覆盖前一条消息;使能后,接收FIFO装满后,下一条传入消息将被丢弃;
25行:禁止传输FIFO优先级,则优先级由消息标识符决定;使能后,由请求顺序(时间顺序)决定;
27~30行:初始化前面设置的CAN参数,同时会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”;
32~41行:设置CAN筛选器;
33行:设置哪一个CAN筛选器组,设置设置筛选器组0,STM32F103ZET6共有14个筛选器组;
34行:“CAN_FILTERMODE_IDMASK”设置为掩码模式,“CAN_FILTERMODE_IDLIST”设置为列表模式;
35行:设置筛选范围可设置为32位;
36~37行:设置ID的高低字节,这里设置ID为0;
38~39行:设置掩码的高低字节,这里设置掩码为0,则没有做任何过滤;
40行:设置本筛选器的消息存储在哪个FIFO(接收FIFO共有两个);
41行:使能本筛选器;
43~46行:配置前面设置的筛选器;
48~52行:启动CAN;
54~58行:使能CAN接收FIFO0的中断;注意这里使能的是FIFO0,需要和前面设置筛选器的FIFO保持一致;这里可以设置三种类型FIFO中断,分别为“CAN_IT_RX_FIFO0_MSG_PENDING”FIFO接收到数据就
产生中断、“CAN_IT_RX_FIFO0_FULL”FIFO接收满后产生中断“CAN_IT_RX_FIFO0_OVERRUN”FIFO溢出产生中断;
前面“HAL_CAN_Init()”会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”,该函数需要我们自己完善,如代码段 23.3.2 所示。
代码段 23.3.2 CAN 硬件初始化(driver_can.c)
需要注意,PB8、PB9如果用于CAN引脚,不是引脚典型复用,而是需要引脚复用重映射,如图 23.3.1所示为《数据手册》部分引脚描述截图。因此代码段 23.3.2 中14~15行需要先使能重映射时钟,再重映射CAN功能。
封装CAN发送函数和接收回调函数
初始化完CAN后,便可以调用HAL库提供的“HAL_CAN_AddTxMessage()”将报文放入发送信箱,供CAN控制器发送。在这之前,需要准备好报文,如代码段 23.3.3 所示。
代码段 23.3.3 CAN 发送函数(driver_can.c)
12~23行:准备发送报文;
初始化CAN
CAN的初始化,包含两部分:协议部分和硬件部分。
协议部分初始化如代码段 23.3.1 所示。
代码段 23.3.1 CAN 协议初始化(driver_can.c)
12~25行:设置CAN协议参数;
12行:设置哪一个CAN控制器,STM32F103ZET6只有一个CAN控制器;
15行:设置时钟的预分频,与后面的位段时间长度组合,实现需要的500Kbps,这里先设置为8分频;
16行:设置CAN工作模式,CAN控制有四种模式:正常模式、静默模式、回环模式及静默回环模式,通常设置为正常模式即可;
17行:设置再次同步补偿宽度,因时钟频率偏差、传送延迟等,各单元有同步误差,这里设置补偿此误差的最大值,范围为1~4Tq;
18行:设置位段1(BS1)的长度为6Tq;
19行:设置位段2(BS2)的长度为2Tq,由前面的波特率计算公式可得:36M/(1+6+2)/8 = 500Kbps;
20行:设置间触发通信模式,禁止时间触发通信模式;
21行:禁止总线自动关闭,控制CAN在退出总线关闭状态时的行为;
22行:禁止自动唤醒,控制CAN在眠模式下接收到消息时的行为;
23行:开启自动重传,CAN将自动重发消息,直到CAN消息发送成功;关闭后,无论成功、错误或仲裁丢失,都只发送一次;
24行:禁止接收FIFO锁定,当接收FIFO装满后,下一条传入消息将覆盖前一条消息;使能后,接收FIFO装满后,下一条传入消息将被丢弃;
25行:禁止传输FIFO优先级,则优先级由消息标识符决定;使能后,由请求顺序(时间顺序)决定;
27~30行:初始化前面设置的CAN参数,同时会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”;
32~41行:设置CAN筛选器;
33行:设置哪一个CAN筛选器组,设置设置筛选器组0,STM32F103ZET6共有14个筛选器组;
34行:“CAN_FILTERMODE_IDMASK”设置为掩码模式,“CAN_FILTERMODE_IDLIST”设置为列表模式;
35行:设置筛选范围可设置为32位;
36~37行:设置ID的高低字节,这里设置ID为0;
38~39行:设置掩码的高低字节,这里设置掩码为0,则没有做任何过滤;
40行:设置本筛选器的消息存储在哪个FIFO(接收FIFO共有两个);
41行:使能本筛选器;
43~46行:配置前面设置的筛选器;
48~52行:启动CAN;
54~58行:使能CAN接收FIFO0的中断;注意这里使能的是FIFO0,需要和前面设置筛选器的FIFO保持一致;这里可以设置三种类型FIFO中断,分别为:“CAN_IT_RX_FIFO0_MSG_PENDING”FIFO接收到数据就产生中断、“CAN_IT_RX_FIFO0_FULL”FIFO接收满后产生中断、“CAN_IT_RX_FIFO0_OVERRUN”FIFO溢出产生中断;
前面“HAL_CAN_Init()”会调用CAN硬件相关初始化函数“HAL_CAN_MspInit()”,该函数需要我们自己完善,如代码段 23.3.2 所示。
代码段 23.3.2 CAN 硬件初始化(driver_can.c)
需要注意,PB8、PB9如果用于CAN引脚,不是引脚典型复用,而是需要引脚复用重映射,如图 23.3.1所示为《数据手册》部分引脚描述截图。因此代码段 23.3.2 中14~15行需要先使能重映射时钟,再重映射CAN功能。
封装CAN发送函数和接收回调函数
初始化完CAN后,便可以调用HAL库提供的“HAL_CAN_AddTxMessage()”将报文放入发送信箱,供CAN控制器发送。在这之前,需要准备好报文,如代码段 23.3.3 所示。
代码段 23.3.3 CAN 发送函数(driver_can.c)
12~23行:准备发送报文;
12行:定义变量“tx_mailbox”,保存返回的邮箱编号;
13~16行:限制每次报文,数据最多8字节;
18行:设置报文的标准标识符;
19行:设置报文的扩展标识符;
20行:设置帧模式,这里设置为标准帧;
21行:设置帧类型,这里设置为数据帧;
22行:设置数据长度;
23行:设置帧传输时是否获取时间标记,通常关闭;
25~28行:调用“HAL_CAN_AddTxMessage()”发送报文;
前面设置了CAN中断和中断优先级,当CAN控制器,发送完成或接收完成时,都将跳转到中断向量表的对应位置,执行中断处理函数,如代码段 23.3.4 所示。
代码段 23.3.4 CAN 中断处理函数(driver_can.c)
1~5行:CAN1发送完成时,将进入中断向量“CAN1_TX0_IRQHandler”。这里发送完成后,不需要任何操作,因此没有编写发送完成的中断函数;
7~11行:CAN1接收完成时,将进入中断向量“CAN1_RX0_IRQHandler”。这里接收完成后,会调用一系列中断函数,其中“HAL_CAN_RxFifo0MsgPendingCallback()”为接收FIFO0消息等待回调函数;
13~30行:编写接收FIFO0消息等待回调函数,使用“HAL_CAN_GetRxMessage()”获取报文,随后修改接收标志位,以便其它函数查询是否接收到数据;
本实验中涉及的RS485、串口打印、按键等实现,参考之前相关章节的讲解。
主函数控制逻辑
在主函数里,每按一下按键,先构造RS485要发送的数据,然后调用“RS485_Tx()”发送数据。随后查询CAN是否收到数据,如果收到数据,打印CAN收到的数据。接着,构造CAN要发送的ID和数据,调用“CAN_Transmit()”发送报文,然后使用“RS485_Rx()”接收数据,并打印,如代码段 23.3.5 所示。
代码段 23.3.5 主函数控制逻辑(main.c)
23.4 实验效果
本实验对应配套资料的“5_程序源码15_通信—CAN”。打开工程后,编译,下载。按图 23.4.1 所示,将开发板、RS485_CAN互转模块连接,开发板的CAN接模块的CAN,开发板的RS485接模块的RS485,且线都不交叉,注意此时的J11(蓝色拨码开关)的1脚拨为ON。
按下按键KEY1(KEY_U),即可看到串口如图 23.4.2 所示。首先RS485发送数据,CAN接收到相同的数据,RS485_CAN互换模块为CAN添加了0x0的ID。随便CAN发送数据,RS485接收到相同的数据,CAN报文的ID被RS485_CAN互换模块省略。
举报