事先声明,下面所说的很多有关CAN的知识,是我自己的学习和理解,而且不会按照教科书教的那样来学习,可能不见得正确,懂的人,可以纠正哈。
一直以来,我都是很头疼学习各种协议的,因为协议太多了。从串口通讯协议开始,通讯协议就是一直在不断增长。可只要是你在学习硬件开发,就不得不学。这不像纯软件开发,基本不会触及底层的东西,你只需要在应用层面做好自己应用,关注业务上的东西就行。这也是很无奈的事情。
CAN有关的器件和模块也买了一些,估计落在上面的灰尘已经达到7nm的程度了吧?不知道这个想法能不能像棒子那样去申遗?哈哈哈哈。说笑了,下面开始正是学习CAN有关的东西,先从CAN的物理构成学起吧。这里我就不学习CAN的发展史了,只说我想要了解的知识点。
首先刨去协议及有关的处理芯片,CAN的总线只需要两根线,线少,可以节省资源。CAN总线是用来传递数字信息的,它的总线上不是简单的高低电平信号,而是通过两条线上的电压差来呈现高低电平信息的。两条线的电压差等于0V时,表示传递的是高电平,逻辑1,这是隐性电平;电压差等于2V,表示传递的是低电平,逻辑0,这是显性电平。这就是差分信号。这个压差的实现,是由控制器实现,没必要深入学,嘿嘿。选择差分信号方式传递信息的好处是,很容易排除外来噪音干扰,延长传递距离。
注1:低电平信号在CAN总线上的表现
注2:高电平信号在CAN总线上的表现
现在我已经知道了CAN总线是如何传递数字信号的了,那么假如我想通过CAN总线传递一个字符,比如0(十六进制的0x30,二级制的0011 0000),总线是如何传递的呢?我知道在SPI总线传递数据时,有时钟脉冲这个信号用来帮助解析二进制信号,在时钟的某个脉冲沿获得正确的电平信号,从得到正确的结果。但在CAN总线上没有这种机制。那么利用CAN总线传递这个0字符的时候,肯定要按照二进制的数值位来传递的,加入高位在前方式传递,在CAN总线上就应该是以下变化的信号:
1、总线压差=2V ,传递Bit7的0
2、总线压差=2V,传递Bit6的0
3、总线压差=0V ,传递Bit5的1
4、总线压差=0V ,传递Bit4的1
5、总线压差=2V,传递Bit3的0
6、总线压差=2V,传递Bit2的0
7、总线压差=2V,传递Bit1的0
8、总线压差=2V,传递Bit0的0
但在接收的时候在什么时机解析这种电压变化就很重要了,否则一定会得到错误的结果。因此我想,是不是CAN总线也需要在发收的时候要统一某个协议,类似串口通讯中的统一的波特率,来确认正确的通讯呢?带着这个疑问,我继续学习。
在CAN总线上,每一个节点,都如下形式的构成:
CAN控制器有自己的工作时钟(CAN时钟),一个完整周期的时钟,视为Tq。利用这个Tq和一套复杂的通讯协议,CAN控制器可以实现数据的同步。因为协议也比较复杂,我瞬间失去了深入学习的兴趣,决定放弃了。反正这个同步是由控制器实现的,不需要程序参与。好吧,接下来,和通讯有关的东西,我只关注和程序处理有关的部分。
CAN总线报文类型
CAN总线上传输的信息称为报文,当总线空闲时任何连接的单元都可以开始发送新的报文。CAN通信是通过以下5种类型的帧进行的:数据帧,遥控帧,错误帧,过载帧,帧间隔。
1、数据帧
是节点想要发送数据时使用的额帧。由帧起始、仲裁段、控制段、数据段、CRC段、ACK段、帧结束这几部分构成。
2、遥控帧
又叫远程帧,用于接收单元具有相同ID的发送单元请求数据的帧。帧格式与数据帧相似,只是RTR位为隐性状态,而且没有数据段。
3、错误帧
当节点在收发数据检查到有错误的时候,会以错误帧的形式,通知参与通讯的其他节点。
4、过载帧
当某个节点没有做好接收下一帧数据时,会发出过载帧。一个节点最多可产生两条连续的过载帧来延迟下一条保温发送。其帧格式,与主动错误帧格式相同。
5、帧间隔
用来分隔前面任意类型的帧与下一个数据帧或者远程帧。
CAN总线数据收发过程
我们以下面两个单元之间的通讯过程,来说明CAN收发数据的处理过程。
1、当A想要发送数据的时候,要检查A的RXD,如果RXD=1,表示总线处于空闲状态,可以实施发送处理。数据可以通过TXD发送给A的CAN控制器。
2、B单元通过RXD接收来自A单元的数据后,马上使B的RXD=0,B的CAN控制器会将这个信息通过TXD反映到CAN总线上。
3、A单元在收到来自B单元的反应RXD=0的信号时,表示收到B单元已经收到数据的应答。
好了,看到这个过程,终于到了我能顺畅理解的部分了。我可以把这个过程简单理解为以下步骤:
对A方:
1、总线忙不?
2、总线不忙,发送我要发的数据
3、对方收到没?
4、对方收到了,好,通讯结束。
对B方:
1、收到发给我的数据
2、数据都接收完了?
3、是,都接收收完了,告知对方。
看,就这么简单,哈哈哈。可是有个问题哈,
1、对A方,数据要发给谁,在哪里体现呢?
2、对B方,怎么知道这个数据是给我的?
这就涉及到数据的构成了,我以前学习单片机的串口的多机通讯时,在通讯数据包中,是包含了子机编号的,这个编号决定了数据是想要发给谁的。我自己在做RF2401的无线通讯时,也在数据包中设置了来源设备号和目标设备号,从而确定数据是来自哪里和发向哪里的。
CAN总线其实没有主从的概念,每个设备都是一个节点,节点之间是可以相互通讯的。CAN总线上的每个节点不需要设置节点的地址,而是通过消息的标识符(也就是前面说的ID段)来区别信息。因为CAN总线的消息是广播的(就是大家都可以收到消息),比如总线上有节点A,节点B,节点C,那么节点A发消息,节点B和节点C都会收到消息;
当一个节点要向其它节点发送数据时,该节点的CPU将要发送的数据和自己的标识符传送给本节点的CAN控制芯片,并处于准备状态;当它发现总线可用时,转为发送报文状态。CAN控制芯片将数据根据协议组织成一定的报文格式发出,这时CAN总线上的其它节点处于接收状态。每个节点通过控制器中过滤码(Filter Code )和掩码(Mask Code),再检验总线上消息的标识符(标准模式下有11个标识符位,扩展模式下有29个标识符位),来判断是否接收这个消息(Message Filtering)。而过滤码和掩码是可以自行设置的。
简单地说,CAN的报文中是不包含地址信息的,接收方根据需要,决定是否接收报文信息。虽然没有,但我们可以在某些标识位或者数据段人为加进去指明目标的信息。
现在,我只是对CAN通讯有了初步的了解。要深入学习的知识还很多,慢慢学,慢慢积累吧。