STM32单片机/小谈CAN通信

2023-04-24  

我认为CAN通信大概是所学通信里比较高级的了,说难也难,说不难也不难。本文只是结合stm32单片机来小谈一下,以此来帮助大家理解CAN通信。对于CAN通信的理论,原子哥的视频或者那本PDF《can入门教程》已经很详细全面了,我不能更好的给大家讲一遍了。如果你看了不懂,只能说看的遍数不够多。

CAN通信基本介绍

在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个 LAN,进行大量数据的高速通信”的需要, 1986 年德国电气商博世公司开发出面向汽车的 CAN 通信协议。此后, CAN 通过 ISO11898 及 ISO11519 进行了标准化,现在在欧洲已是汽车网络的标准协议。 现在, CAN 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设备、工业设备等方面。

所以由此可见CAN通信是一种应用场景很广且可靠的通信方式。

CAN通信协议有如下几个特性:

1:多主控制。总线空闲时,所有单元都可发送消息,而两个以上的单元同时开始发送消息时,根据标识符(ID,非地址)决定优先级。两个以上的单元同时开始发送消息时,对各消息ID 的每个位进行逐个仲裁比较。仲裁获胜(优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。

2:系统柔软性。连接总线的单元,没有类似“地址”的信息,因此,在总线上添加单元时,已连接的其他单元的软硬件和应用层都不需要做改变。

3:速度快,距离远。最高1Mbps(距离<40M),最远可达10KM(速率<5Kbps)。

4:具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。


根据前面学习的各种类型的通信方法:

【通信专栏】一:STM32串口通信(usart)

【通信专栏】STM32单片机/I2C通信(上篇)

【通信专栏】STM32单片机/SPI通信

【通信专栏】STM32单片机/485通信详解

我们可以提几个问题:

问题一:CAN通信的数据是如何打包的?

我们知道,不论是对设备发送指令还是传输数据,都需要按照一定的协议来将数据进行打包发送。

can通信对数据也是按照一定协议进行打包的,打包好的数据包称作""。按照打包的不同格式,数据帧可以分为五种:

而各个数据帧的打包格式是需要重点了解的,希望大家好好研究《can入门教程》,上面五个帧中,比较常用且重要的就是数据帧遥控帧了,

看名字我们便知道,数据帧用于向某一设备发送数据;遥控帧则是某一设备向另一设备发送遥控帧后,另一设备会返回该设备所想要的值。而数据帧与遥控帧除了一些打包时的细节之处,最大的区别便在于数据帧有数据段,而遥控帧没有(特殊的数据帧也可以没有数据段,即数据段为空)。

STM32如何打包数据帧呢?正点原子的库函数里为我们定义了一个结构体:

该结构体为CAN通信发送数据结构体,我们只需要用此结构体定义一个结构体变量,并初始化结构体的各个成员,然后就可以通过一个32的一个库函数CAN_Transmit(CAN1, &TxMessage);进行发送了。

对于上面结构体的各个成员的意义,我们便不多解释了,只要看过一遍CAN通信相关协议介绍的,都可以大致明白。

具体如何发送的呢?在原子哥的例程里给了我们这样一个用户自定义函数:

1处:该函数定义了一个变量,其实是用来存储发送数据的邮箱号的,在STM32的配置中,一个CAN接口配备了三个邮箱,发送数据时,4处的发送库函数会自动选择一个空的邮箱进行发送数据并返回该邮箱的邮箱号,而变量mbox就是用来存放发送数据的邮箱号的,方便5处进行标志位的判断。

2处:定义了一个发送数据包的结构体变量。

3处:对该数据包的内容进行了初始化,其内容可以由我们自行设置。

4处:调用库函数将该数据帧(或者遥控帧)发送出去。

5处:进行标志位的判断,等待发送结束。

而在实际应用中,我们CAN总线上会挂载很多设备,我们可以定义很多个类似上图函数一样的自定义函数,来实现我们对不同设备的数据发送。当然也可以写一个通用的发送数据函数,而把结构体的定义,初始化部分提出来单独定义。总之可以根据需要灵活变通了。

问题二:CAN通信如何初始化配置?

CAN通信的初始化分为四个部分:

步骤一:初始化GPIO

这步就不多说了,通过查找CAN接口对应的引脚然后进行初始化,都是常规操作。

步骤二:配置CAN中断

CAN的中断由发送中断,接收FIFO中断和错误中断构成。发送中断由三个发送邮箱任意一个为空的事件构成。接收FIFO中断分为FIFO0和FIFO1的中断,接收FIFO收到心得报文或报文溢出的事件可以引起中断。原子哥的例程使用的是RX0中断通道即FIFO0中断通道,当FIFO0收到新报文时,引起中断。我们就在相应的中断函数中读取这个新报文。中断函数如下:

原子哥的这个程序仅将接收到的函数存入到一个结构体变量中,并将该结构体变量中的数据部分进行打印。但实际应用中,我们可以对ID号或者数据部分进行判断,进而执行相应的操作,如下图程序:

步骤三:配置CAN模式

关于CAN模式配置,这里就不多说了,下图来自《STM32库函数开发指南》,实际应用中,其实复制粘贴原子哥例程中的那一段配置源码大部分时候就可以了。

步骤四:CAN过滤器的配置

根据前文,我们在发送数据帧时,总需要将ID号打包进去。在CAN通信协议中,ID号的作用有以下几点:

  • 作为数据发送的优先级判断,优先级高的先发送

  • 作为接收报文的筛选,也就是此处的CAN过滤器的配置

  • 用作标识符的识别,如果系统中的所有ID号设置都不一样的话,我们便可以将ID号当作一种标识符进行识别判断

  • 变相的识别"设备地址",该作用在下个问题中解释。

STM32的ID过滤方式有两种。一种为标识符列表模式。一种为标识符屏蔽模式。

配置结构体:

问题三:CAN通信如何确定接收数据对象的地址?

在485通信中,我们需要自己软件定义一个虚拟地址;SPI通信中我们靠片选信号线来选中从设备;I2C通信中我们从机有固定的硬件地址。那CAN通信如何实现地址的确定呢?

其实CAN通信不存在设备地址这个概念,它通过我们上个问题中数据帧初始化的ID号进行辨别。在总线上每个设备都会有一个ID过滤器(上个问题步骤四),每当发送一个数据帧后,该数据帧经过每个设备的ID过滤器过滤后,只能传入某几个或一个设备内,然后该设备将会根据数据帧的内容进行一定的反应。从而实现精准的数据传输。

问题四:CAN通信如何解决的时序问题?

在我们之前学过的通信中都会有一个时钟线来同步信息的发送,但CAN只有两个差分信号线。那它如何解决时序问题呢? CAN通信采用的是一种位时序的分解的方法,这对我们使用CAN通信并没有太大的影响,所以大家可以去研读《can入门教程》,这里便一笔带过了。

CAN通信硬件连接

从CAN的通信网络图可以看到,它的通信节点是由一个CAN控制器,一个CAN收发器组成,STM32的CAN接口即为CAN控制器,为构成完整的节点,还要给它外接一个CAN收发器。

在发送数据时,CAN控制器把要发送的二进制编码通过CAN_TX线发送到CAN收发器,然后由收发器把这个普通的逻辑电平信号转化成差分信号,通过差分线CAN_High和CAN_Low线输出到CAN总线网络。在接收数据时,与这个过程相反。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。