ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【硬件通信协议】4. 详细解析CAN总线通信协议

2019-03-22 20:54:15  阅读:523  来源: 互联网

标签:控制器 同步 通信协议 报文 总线 发送 解析 节点


基于对CAN总线的耳闻,但是从未在项目中使用过。为了扫盲,故借此机会将CAN总线整理与理解一遍。感谢其他作者(文末的参考链接)对CAN总线的一些详细介绍,鉴于个人的理解,从新整理一番,以备不时之需。

1. CAN总线概要

        上世纪八十年代以来,汽车ECU越来越多,如ABS,电控门窗,电子燃油喷射装置。如果仍然采用常规的点对点布线方式,即电线一段与开关相接,另一端与用电设备相通,将会导致车上电线数目的急剧增加,从而带来线束的冗余及维修成本的提高。这就对汽车的线束分布及信息通讯提出了更高的要求。总线技术可以实现信息的实时共享,解决了传统布线方式中线束多,布线难,成本高等问题,CAN(Controller Area Network 控制器局域网络)总线技术应运而生。

        CAN总线是由德国研发和生产汽车电子产品著称的BOSCH公司开发的,并最终成为国际标准(ISO11519),是国际上应用最广泛的现场总线之一。CAN总线是一种多主控(Multi-Master)的总线系统。传统总线系统如USB或以太网等是在总线控制器的协调下,实现从A节点到B节点大量数据的传输。CAN网络的消息是广播式的,即在同一时刻网络上所有节点侦测的数据是一致的,它是一种基于消息广播模式的串行通信总线。

CAN总线的很多优点,使得它得到了广泛的应用,如传输速度最高到1Mbps, 通信距离最远到10km,无损位仲裁机制,多主结构。

2. CAN总线标准

        CAN总线标准之规定了物理层和数据链路层,至于应用层需要用户自定义。不同的CAN标准仅物理层不同。物理层和数据链路层:ISO11898;应用层:不同的应用领域使用不同的应用层标准。

3. CAN总线物理层

3.1 CAN拓扑结构

        连接在CAN总线上的设备叫做节点设备(CAN Node),CAN网络的拓扑一般为线型。线束最常用的是双绞线,线上传输为对称的差分电平信号。下图为CAN总线网络示意图,节点主要包括Host、控制器和收发器。Host常集成有CAN控制器,CAN控制器负责处理协议相关功能,以减轻Host的负担。CAN收发器将控制器连接到传输媒介。通常控制器和总线收发器通过光耦或磁耦隔离,这样即使总线上过压损坏收发器,控制器和Host设备也可以得到保护。

        在发送数据时,CAN控制器把要发送的二进制编码通过CAN_Tx线发送到CAN收发器,然后由收发器把这个普通的逻辑电平信号转化成差分信号,通过差分线CAN_High和CAN_Low输出到CAN总线网络。接收数据过程,相反。采用差分信号,可以取得更好的电磁兼容效果。因此,CAN总线物理传输媒介只需要两根线。

       高速CAN总线最高信号传输速率为1Mbps,支持最长距离40m。ISO11898-2要求在高速CAN总线两段安装端接电阻RL(端接电阻一般为120Ω,因为电缆的特性阻抗为120 Ω,为了模拟无限远的传输线。)以消除反射。低速CAN最高速度只有125Kbps,所以ISO11898-3没有端接要求。

        因为传输距离越大,信号时延也越大,为了保证消息的正确采样,总线上的信号速率相应也要下降。下图是推荐的信号速率与距离的关系。

3.2 CAN收发器

        CAN总线分高速CAN和低速CAN,收发器也分为高速CAN收发器(1Mbps)和低速CAN收发器(125Kbps)。低速CAN也叫Fault Tolerance CAN,指的是即使总线上一根线失效,总线依然可以通信。如同串口中的MAX3232用作电平转换,CAN收发器的作用则是把逻辑信号转换为差分信号。

3.3 差分信号

        CAN总线采用差分信号传输,通常情况下只需要两根信号线就可以进行正常的通信。在差分信号中,逻辑0和逻辑1是用两根差分信号线的电压差来表示。当处于逻辑1,CAN_High和CAN_Low的电压差小于0.5V时,称为隐性电平(Recessive);当处于逻辑0,CAN_High和CAN_Low的电压差大于0.9V,称为显性电平(Dominant)。

高速CAN

低速容错CAN (Fault Tolerance CAN):

CAN总线遵从“线与”机制:“显性”位可以覆 盖“隐性”位;只有所有节点都发 送“隐性”位, 总线才处于“隐性” 状态。这种“线与”机制使CAN总线呈现显性优先的特性。

3.4 CAN总线连接器

4. CAN总线数据链路层

        在SPI通信中,片选、时钟信号、数据输入及数据输出这四个信号都有单独的信号线。而CAN使用的是两条差分信号线,只能表达一个信号。简洁的物理层决定了CAN必然要配上一套更为复杂的协议。如何用一个信号通道实现同样甚至更强大的功能,答案就是对数据或操作命令进行打包。

4.1 通信机制

多主机(Multi-Master)

        安全敏感的应用(如汽车动力)对通信系统的可靠性要求很高。将总线能否正常工作归结到单一节点是非常危险的,比较合理的方案是对总线接入的去中心化,即每个节点都有接入总线的能力。这也是CAN总线采用多主控(Multi-Master)线性拓扑结构的原因。

        在CAN总线上,每个节点都有往总线上发送消息的能力,而消息的发送不必遵从任何预先设定的时序,通信是事件驱动的。只有当有新的信息传递时,CAN总线才处于忙碌的状态,这使得节点接入总线速度非常快。CAN总线理论最高数据传输速率为1Mbps,对于异步事件反应迅速,基本对于ms级别的实时应用没有任何问题。

寻址机制

        不同于其它类型的总线,CAN总线不设定节点的地址,而是通过消息的标识符(Identifier)来区别消息。这种机制虽然会增加消息的复杂度(增加标识符),但是节点在此情况下可以无需了解其他节点的状况,而相互间独立工作。在总线上增加节点时仅需关注消息类型,而非系统上其他节点的状况。这种以消息标识符寻址的方式,让总线上增加节点变得更加灵活。

总线访问CSMA/CD+AMP

CAN总线通信原理可简单描述为多路载波侦听+基于消息优先级的冲突检测和非破坏性的仲裁机制(CSMA/CD+AMP)。CSMA(Carrie Sense Multiple Access)指的是所有节点必须都等到总线处于空闲状态时才能往总线上发送消息;CD+AMP(Collision Detection + Arbitration on Message Priority)指的是如果多个节点往总线上发送消息时,具备最高优先级的消息获得总线。

  • 多路载波侦听:网络上所有节点以多点接入的方式连接在同一根总线上,且发送数据是广播式的。网络上各个节点在发送数据前都要检测总线上是否有数据传输:若网络上有数据,暂时不发送数据,等待网络空闲时再发;若网络上无数据,立即发送已经准备好的数据。
  • 冲突检测:节点在发送数据时,要不停的检测发送的数据,确定是否与其他节点数据发送冲突,如果有冲突,则保证优先级高的报文先发送。
  • 非破坏性仲裁机制:通过ID仲裁,ID数值越小,报文优先级越高。

发送低优先级报文的节点退出仲裁后,在下次总线空闲时自动重发报文。

高优先级的报文不能中断低优先级报文的发送。

报文接收过滤

        CAN控制器大多具有根据ID过滤报文的功能,即只接收某些ID的报文。节点对接收到的报文进行过滤:比较消息ID与选择器(Accepter)中和接受过滤相关位是否相同。如果相同,接收;如果不相同,则过滤。

5. CAN的报文种类及结构

5.1 报文的种类

        在原始数据段的前面加上传输起始标签、片选(识别)标签、控制标签,在数据的尾段加上CRC校验标签、应答标签和传输结束标签。把这些内容按特定的格式打包好,就可以用一个通道表达各种信号了。各种各样的标签,起到了协同传输的作用。当整个数据包被传输到其他设备时,只要这些设备按格式去解读,就能还原出原始数据。类似这样的数据包就被称为CAN的数据帧。为了更有效的控制通信,CAN一共规定了5中类型的帧,帧也称为报文。

5.2 数据帧

        数据帧在CAN通信中最主要,也最复杂。数据帧以一个显性位(逻辑0)开始,以7个连续的隐性位(逻辑1)结束。CAN总线的数据帧有标准格式(Standard Format)和扩展格式(Extended Format)的区分。

数据帧可以分为七段:

  • 帧起始(SOF)

标识一个数据帧的开始,固定一个显性位。

用于同步, 总线空闲期间的任何隐性到显性的跳变都将引起节点进行 硬同步。只有总线在空闲期间节点才能够发送SOF。

  • 仲裁段(Arbitration Field)

仲裁段的内容主要为本数据帧的ID信息。数据帧分为标准格式和扩展格式两种,区别就在于ID信息的长度:标准格式的ID为11位;扩展格式为29位。在CAN协议中,ID决定着数据帧发送的优先级,也决定着其他设备是否会接收这个数据帧。

仲裁段除了报文ID外,还有RTR, IDE, SRR位。

  • 控制段

在控制段,r1(reserved1)和r0(reserved0)为保留位,默认设置为显性位。最主要的是DLC(Data Length Code)段,它是用二进制编码表示本报文中的数据段包含多少个字节。DLC段由4位组成,DLC3−DLC0,表示的数字为0-8.

  • 数据段

数据帧的核心内容,有0-8个字节长度,由DLC确定。

  • CRC段

        为了保证报文的正确传输,CAN的报文包含了一段15位的CRC校验码,一旦接收端计算出的CRC码跟接收到的CRC码不同,就会向发送端反馈出错信息以及重新发送。CRC部分的计算和出错处理一般由CAN控制器硬件完成,或由软件控制最大重发数。在CRC校验码之后,有一个CRC界定符,它为隐性位,主要作用是把CRC校验码与后面的ACK段隔开。

  • ACK段

包含确认位(ACK slot)和界定符(Delimiter,
DEL)。ACK在发送节点发送时,为隐性位。当接收节点正确接收到报文时,对其用显性位覆盖。DEL界定符同样为隐性位,用于隔开。

 

  • 帧结束段(End-of-Frame, EOF)

帧结束段由发送端发送7个隐性位表示结束。

6. 同步

        CAN总线使用位同步的方式来确保通信时序,以及对总线的电平进行正确采样。

6.1 位时序

在讲位时序之前,先介绍几个基本概念。

Time Quantum 时间份额tQ :CAN控制器工作的最小时间单位,通常对系统时钟分频得到。

波特率:单位时间内(1s)传输的数据位,公式:1/位时间。举个栗子,系统时钟频率36MHz,预分频因子为4,则CAN时钟频率9MHz,则Tq=1/9M。假设一个CAN位包含10个Tq,则一个位周期T=10Tq,从而波特率为1/T=0.9MHz.

为了实现位同步,CAN协议把每一位的时序分解成下图所示的四段。这四段的长度加起来即为一个CAN数据位的长度。一个完整的位由8-25个Tq组成。

  • 同步端(SS,Synchronization Segment)

一个位的输出从同步段开始。若总线的跳变沿被包含在SS段的范围之内,则表示节点与总线的时序同步。节点与总线同步时,采样点采集到的总线电平即可被确定为该电平的电位。SS段的大小为1Tq.

  • 传播段(PTS,Propagation Time Segment)

用于补偿信号在网络和节点传播的物理延时时间,是总线上输入比较器延时和输出驱动器延时总和的两倍。通常1-8Tq

  • 相位缓冲段1(PBS1, Phase Buffer Segment 1)

主要用于补偿边沿阶段的误差,其时间长度在重新同步时可以加长。初始大小1-8Tq.

  • 相位缓冲段2(PBS2,Phase Buffer Segment 2)

也是用于补偿边沿阶段的误差,其时间长度在重新同步时可以缩短。初始大小2-8Tq.

 

CAN同步分为硬同步和重新同步。

同步规则:

  • 一个位时间内只允许一种同步方式
  • 任何一个“隐性”到“显性”的跳变都可用于同步
  • 硬同步发生在SOF阶段,所有接收节点调整各自当前位的同步段,使其位于发送的SOF位内。
  • ·重新同步发生在一个帧的其他阶段,即当跳变沿落在同步段之外。

硬同步

当总线上出现帧起始信号(SOF,即隐性到显性的边沿)时,其他节点的控制器根据总线上的这个下降沿对自己的位时序进行调整,把该下降沿包含到SS段内。这样根据起始帧来进行的同步称为硬同步。

可以看到在总线出现帧起始信号时,该节点原来的位时序与总线时序不同步,因而这个状态的采样点采集到的数据是不正确的。所以节点以硬同步的方式调整,把自己的位时序中的SS段平移至总线出现下降沿的部分,获得同步,这时采样点采集到的数据是正确数据。

重新同步

        因为硬同步时只是在有帧起始信号时起作用,无法确保后续一连串的位时序都是同步的,所以CAN引入了重新同步的方式。在检测到总线上的时序与节点使用的时序有相位差时(即总线上的跳变沿不在节点时序的SS段范围),通过延长PBS1段或缩短PBS2段来获得同步,这样的方式称为重新同步。

        分两种情况:第一种, 节点从总线的边沿跳变中,检测到它的时序比总线的时序相对滞后2个Tq,这是控制器在下一个时序中的PBS1段增加2Tq的时间长度,使得节点与总线时序重新同步。

第二种,节点从总线的边沿跳变中,检测到它的时序相对超前2Tq,这时控制器在前一个位时序中的PBS2段减少2Tq的时间长度,获得同步。

        在重新同步的时候,PBS1和PBS2段的允许加长或缩短的时间长度定义为,重新同步补偿宽度(SJW,reSynchronization Jump Width)。这里设置的PBS1和PBS2能够增减的最大时间长度SJW=2Tq,若SJW设置的太小则重新同步的调整速度慢,若太大,则影响传输速率。

以上材料参考:https://zhuanlan.zhihu.com/c_147522390

7.  CAN总线实际应用实例

7.1 构建CAN节点

构建节点,实现相应控制,由底向上分为四个部分:CAN节点电路、CAN控制器驱动、CAN应用层协议、CAN节点应用程序。

虽然不同节点完成的功能不同,但是都有相同的硬件和软件结构。

CAN收发器和控制器分别对应CAN的物理层和数据链路层,完成CAN报文的收发;功能电路,完成特定的功能,如信号采集或控制外设等;主控制器与应用软件按照CAN报文格式解析报文,完成相应控制。

CAN硬件驱动是运行在主控制器(如P89V51)上的程序,它主要完成以下工作:基于寄存器的操作,初始化CAN控制器、发送CAN报文、接收CAN报文;

如果直接使用CAN硬件驱动,当更换控制器时,需要修改上层应用程序,移植性差。在应用层和硬件驱动层加入虚拟驱动层,能够屏蔽不同CAN控制器的差异。

一个CAN节点除了完成通信的功能,还包括一些特定的硬件功能电路,功能电路驱动向下直接控制功能电路,向上为应用层提供控制功能电路函数接口。特定功能包括信号采集、人机显示等。

CAN收发器是实现CAN控制器逻辑电平与CAN总线上差分电平的互换。实现CAN收发器的方案有两种,一是使用CAN收发IC(需要加电源隔离和电气隔离),另一种是使用CAN隔离收发模块。推荐使用第二种。

CAN控制器是CAN的核心元件,它实现了CAN协议中数据链路层的全部功能,能够自动完成CAN协议的解析。CAN控制器一般有两种,一种是控制器IC(SJA1000),另一种是集成CAN控制器的MCU(LPC11C00)。

MCU负责实现对功能电路和CAN控制器的控制:在节点启动时,初始化CAN控制器参数;通过CAN控制器读取和发送CAN帧;在CAN控制器发生中断时,处理CAN控制器的中断异常;根据接收到的数据输出控制信号;

接口管理逻辑:解释MCU指令,寻址CAN控制器中的各功能模块的寄存器单元,向主控制器提供中断信息和状态信息。

发送缓冲区和接收缓冲区能够存储CAN总线网络上的完整信息。

验收滤波是将存储的验证码与CAN报文识别码进行比较,跟验证码匹配的CAN帧才会存储到接收缓冲区。

CAN内核实现了数据链路的全部协议。

7.2 CAN协议应用层概述

CAN总线只提供可靠的传输服务,所以节点接收报文时,要通过应用层协议来判断是谁发来的数据、数据代表了什么含义。常见的CAN应用层协议有: CANOpen、DeviceNet、J1939、iCAN等。

CAN应用层协议驱动是运行在主控制器(如P89V51)上的程序,它按照应用层协议来对CAN报文进行定义、完成CAN报文的解析与拼装。例如,我们将帧ID用来表示节点地址,当接收到的帧ID与自身节点ID不通过时,就直接丢弃,否则交给上层处理;发送时,将帧ID设置为接收节点的地址。

7.3 CAN收发器

SJA1000的输出模式有很多,使用最多的是正常输出模式,输入模式通常不选择比较器模式,可以增大通信距离,并且减少休眠下的电流。

收发器按照通信速度分为高速CAN收发器和容错CAN收发器。

同一网络中要使用相同的CAN收发器。

CAN连接线上会有很多干扰信号,需要在硬件上添加滤波器和抗干扰电路

也可以使用CAN隔离收发器(集成滤波器和抗干扰电路)

CAN控制器与MCU的连接方式

SJA1000可被视为外扩RAM,地址宽度8位,最多支持256个寄存器

  1. #define REG_BASE_ADDR 0xA000 // 寄存器基址
  2. unsigned char *SJA_CS_Point = (unsigned char *) REG_BASE_ADDR ;
  3. // 写SJA1000寄存器
  4. void WriteSJAReg(unsigned char RegAddr, unsigned char Value)
  5. {
  6. *(SJA_CS_Point + RegAddr) = Value;
  7. return;
  8. }
  9. // 读SJA1000寄存器
  10. unsigned char ReadSJAReg(unsigned char RegAddr)
  11. {
  12. return (*(SJA_CS_Point + RegAddr));
  13. }

将缓存区的数据连续写入寄存器

  1. //……
  2. for (i=0;i<len;i++)
  3. {
  4. WriteSJAReg(RegAdr+i,ValueBuf[i]);
  5. }
  6. //……

将连续多个寄存器连续读入缓存区

  1. //……
  2. for (i=0;i<len;i++)
  3. {
  4. ReadSJAReg(RegAdr+i,ValueBuf[i]);
  5. }
  6. //……

头文件包含方案:

  1. 每个程序包含用到的头文件

  2. 每个程序包含一个公用头文件,公用头文件包含所有其他头文件

  1. #ifndef __CONFIG_H__ // 防止头文件被重复包含
  2. #define __CONFIG_H__
  3. #include <8051.h> // 包含80C51寄存器定义头文件
  4. #include "SJA1000REG.h" // 包含SJA1000寄存器定义头文件
  5. // 定义取字节运算
  6. #define LOW_BYTE(x) (unsigned char)(x)
  7. #define HIGH_BYTE(x) (unsigned char)((unsigned int)(x) >> 8)
  8. // 定义振荡器时钟和处理器时钟频率(用户可以根据实际情况作出调整)
  9. #define OSCCLK 11059200UL
  10. // 宏定义MCU的时钟频率
  11. #define CPUCLK (OSCCLK / 12)
  12. #endif // __CONFIG_H__

SJA1000上电后处于复位状态,必须初始化后才能工作。

(1)置位模式寄存器Bit0位进入复位模式;

(2)设置时钟分频寄存器选择时钟频率、CAN模式;

(3)设置验收滤波,设定验证码和屏蔽码;

(4)设置总线定时器寄存器0、1设定CAN波特率;

(5)设置输出模式;

(6)清零模式寄存器Bit0位退出复位模式;

模式寄存器:

只检测模式:SJA1000发送CAN帧时不检查应答位;

只听模式:此模式下SJA1000不会发送错误帧,用于自动检测波特率;SJA1000以不同的波特率接收CAN帧,当收到CAN帧时,表明当前波特率与总线波特率相同。

7.4 波特率设置

CAN总线无时钟,使用异步串行传输;波特率是1秒发送的数据位;

7.5 CAN帧发送

发送CAN帧的步骤:

  • 检测状态寄存器,等待发送缓冲区可用;
  • 填充报文到发送缓冲区;
  • 启动发送。

SJA1000具有一个12字节的缓冲区,要发送的报文可以通过寄存器16-28写入,也可通过寄存器96-108写入或读出

设置发送模式:

  1. char SetSJASendCmd(unsigned char cmd)
  2. {
  3. unsigned char ret;
  4. switch (cmd) {
  5. default:
  6. case 0:
  7. ret = SetBitMask(REG_CAN_CMR, TR_BIT); //正常发送
  8. break;
  9. case 1:
  10. ret = SetBitMask(REG_CAN_CMR, TR_BIT|AT_BIT); //单次发送
  11. break;
  12. case 2:
  13. ret = SetBitMask(REG_CAN_CMR, TR_BIT|SRR_BIT);//自收自发
  14. break;
  15. case 0xff:
  16. ret = SetBitMask(REG_CAN_CMR, AT_BIT);//终止发送
  17. break;
  18. }
  19. return ret;
  20. }

发送函数:

  1. unsigned char SJA_CAN_Filter[8] = { // 定义验收滤波器的参数,接收所有帧
  2. 0x00, 0x00, 0x00, 0x00,
  3. // ACR0~ACR3
  4. 0xff, 0xff, 0xff, 0xff
  5. // AMR0~AMR3
  6. };
  7. unsigned char STD_SEND_BUFFER[11] = { // CAN 发送报文缓冲区
  8. 0x08, // 帧信息,标准数据帧,数据长度 = 8
  9. 0xEA, 0x60, // 帧ID = 0x753
  10. 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa // 帧数据
  11. };
  12. void main(void) // 主函数,程序入口
  13. {
  14. timerInit();// 初始化
  15. D1 = 0;
  16. SJA1000_RST = 1; // 硬件复位SJA1000
  17. timerDelay(50); // 延时500ms
  18. SJA1000_RST = 0;
  19. SJA1000_Init(0x00, 0x14, SJA_CAN_Filter); // 初始化SJA1000,设置波特率为1Mbps
  20. // 无限循环,main()函数不允许返回
  21. for(;;) {
  22. SJASendData(STD_SEND_BUFFER, 0x0);
  23. timerDelay(100); // 延时1000ms
  24. }
  25. }

为什么帧ID是0x753,这与CAN帧在缓冲区的存储格式有关。

终端电阻非常重要,当波特率较高而且没加终端电阻时,信号过冲非常严重。

SJA1000有64个字节的接收缓冲区(FIFO),这可以降低对MCU的要求。MCU可以通过查询或中断的方式确定SJA1000接收到报文后读取报文。

参考资料:《项目驱动-CAN-bus现场总线基础教程》 广州周立功单片机科技有限公司

参考链接:http://www.cnblogs.com/jacklu/p/4729638.html

标签:控制器,同步,通信协议,报文,总线,发送,解析,节点
来源: https://blog.csdn.net/qq_42384937/article/details/88750052

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有