can1--can初探
updating
http://download.csdn.net/detail/songqqnew/4399668
http://download.csdn.net/detail/songqqnew/4399670
http://download.csdn.net/detail/songqqnew/4399684
mcp2515寄存器一览
几个寄存器名称及地址
TXBnCTRL——发送缓冲器n 控制寄存器(地址:30h, 40h, 50h)
TXBnSIDH——发送缓冲器n 标准标识符高位(地址:31h, 41h, 51h)
TXBnSIDL——发送缓冲器n 标准标识符低位(地址:32h, 42h, 52h)
TXBnEID8——发送缓冲器n 扩展标识符高位(地址:33h, 43h, 53h)
TXBnEID0——发送缓冲器n 扩展标识符低位(地址:34h, 44h, 54h)
TXBnDLC——发送缓冲器n 数据长度码(地址:35h, 45h, 55h)
TXBnDm——发送缓冲器n 数据字节m(地址:36h - 3Dh, 46h - 4Dh, 56h - 5Dh)
RXBnCTRL——接收缓冲器n 控制寄存器(地址:60h,70h)
RXBnSIDH——接收缓冲器n 标准标识符高位(地址:61h, 71h)
RXBnSIDL——接收缓冲器n 标准标识符低位(地址:62h, 72h)
RXBnEID8——接收缓冲器n 扩展标识符高位(地址:63h, 73h)
RXBnEID0——接收缓冲器n 扩展标识符低位(地址:64h, 74h)
RXBnDLC——接收缓冲器n 数据长度码(地址:65h, 75h)
RXBnDM——接收缓冲器n 数据字段字节M(地址:66h - 6Dh, 76h - 7Dh)
spi接口操作mcp2515使用的命令
can物理信号
can信号使用差分电压传送,两条信号线被称为CAN_H和CAN_L。静态时均是2.5v左右,此时状态表示为逻辑“1”,也可以叫做隐性。用CAN_H比CAN_L高表示逻辑“0”,称为显性,此时通常电压值为CAN_H=3.5V和CAN_L=1.5V。
![](http://my.csdn.net/uploads/201203/28/1332917255_7523.jpg)
1.标准帧结构--refer to mcp2515说明书
![](http://my.csdn.net/uploads/201205/14/1336969429_4973.jpg)
CAN 标准数据帧如图所示。与其他所有帧一样,帧以起始帧(SOF)位开始, SOF 为显性状态,允许所有节点的硬同步。SOF之后是仲裁字段,由12个位组成,分别为11个标识位和一个远程发送请求(Remote Transmission Request,RTR)位。RTR 位用于区分报文是数据帧(RTR 位为显性状态)还是远程帧(RTR 位为隐性状态)。仲裁字段之后是控制字段,由6 个位组成。控制字段的第一位为标识扩展(Identifier Extension,IDE)位,该位应是显性状态来指定标准帧。标识扩展位的下一位为零保留位(RB0),CAN 协议将其定义为显性位。控制字段的其余4 位为数据长度码(Data Length Code,DLC),用来指定报文中包含的数据字节数(0 到8 字节)。控制字段之后为数据字段,包含要发送的任何数据字节。数据字段长度由上述DLC 定义(0 到8 字节)。数据字段之后为循环冗余校验(CRC)字段,用来检测报文传输错误。CRC 字段包含一个15 位的CRC 序列,之后是隐性的CRC 定界位。最后一个字段是确认字段(ACK),由2 个位组成。在确认时隙(ACK Slot)位执行期间,发送节点发出一个隐性位。任何收到无错误帧的节点会发回一个显性位(无论该节点是否配置为接受该报文与否)来确认帧收到无误。确认字段以隐性确认定界符结束,该定界符可能不允许被改写为显性位。
标准帧和mcp2515的寄存器对应关系一览:详见mcp2515手册
对于接受操作:
![](http://my.csdn.net/uploads/201207/14/1342249491_6916.jpg)
对于发送操作:
![](http://my.csdn.net/uploads/201207/14/1342264351_9394.jpg)
2.扩展帧结构
![](http://my.csdn.net/uploads/201205/14/1336969536_4070.jpg)
在扩展CAN 数据帧中(如图2-2 所示),紧随SOF 位的是32 位的仲裁字段。仲裁字段的前11 位为29 位标识符的最高有效位(Most Significant bit,MSb)(基本lD) 。紧随这11 位的是替代远程请求(Substitute Remote Request, SRR)位,定义为隐性状态。SRR位之后是lDE 位,该位为隐性状态时表示这是扩展的CAN 帧。应该注意的是,如果发送完扩展帧标识符的前11 位后,总线仲裁无果,而此时其中一个等待仲裁的节点发出标准CAN 数据帧(11 位标识符),那么,由于节点发出了显性lDE 位而使标准CAN 帧赢得总线仲裁。另外,扩展CAN 帧的SRR 位应为隐性,以允许正在发送标准CAN 远程帧的节点发出显性RTR 位。SRR和lDE位之后是标识符的其余18位(扩展lD)及一
个远程发送请求位。为使标准帧和扩展帧都能在共享网络上发送,应将29位扩展报文标识符拆成高11 位和低18 位两部分。拆分后可确保lDE 位在标准数据帧和扩展数据帧中的位置保持一致。仲裁字段之后是6 位控制字段。控制字段前两位为保留位,必须定义为显性位。其余4 位为DLC,用来指定报文中包含的数据字节数。扩展数据帧的其他部分(数据字段、CRC 字段、确认字段、帧结尾和间断)与标准数据帧的结构相同(见第2.1 节“标准数据帧”)。
扩展帧和mcp2515的寄存器对应关系一览:详见mcp2515手册
对于接受操作:接收时,若得到IDE位为1,表示接收到的是扩展帧。
![](http://my.csdn.net/uploads/201207/14/1342250235_7546.jpg)
对于发送操作:发送时,置IDE位为1,表示发送的是扩展帧。
![](http://my.csdn.net/uploads/201207/14/1342264394_1362.jpg)
can的无地址编码与485的有地址编码
比如485的modbus帧
发出:01 03 00 00 00 03 05 CB //01站地址,03功能号,00 00 起始地址,00 03要读的数据个数
接收:01 03 06 00 00 00 01 00 02 F1 74 //01站地址,03功能号,06返回的字节数,00 00 00 01 00 02 对应6个字节3个数
(03读取保持寄存器,保持寄存器为可读可写,http://blog.csdn.net/songqqnew/article/details/6938039)
主机发出的帧中的第一个字节是目的地址即01。
所有的设备都可以收到这个帧,只有地址是01的设备才需要响应这个帧,响应帧的第一个字节规定必须是本机地址即01.
而can的帧
/* * Controller Area Network Identifier structure * * bit 0-28 : CAN identifier (11/29 bit) * bit 29 : error frame flag (0 = data frame, 1 = error frame) * bit 30 : remote transmission request flag (1 = rtr frame) * bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit) */ typedef __u32 canid_t; /** * struct can_frame - basic CAN frame structure * @can_id: the CAN ID of the frame and CAN_*_FLAG flags, see above. * @can_dlc: the data length field of the CAN frame * @data: the CAN frame payload. */ struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 can_dlc; /* data length code: 0 .. 8 */ __u8 data[8] __attribute__((aligned(8))); };
主机向总线发出如下帧,帧的内容是hello,并设置标示符为123,这样总线上123号站应当对此帧有反应。
由于都可以作为主机而主动向总线发数据,所以就没必要向modbus那样非得要主机发命令让从机干嘛从机才可以干嘛。
比如1号站有可用数据了,那么他直接将数据发送can总线,希望得到哪个站的处理就设置标示符为哪个站比如为123。在硬件层和驱动层,can总线上的所有非123号站也会收到站1发来的数据。但只有123号站应该对其处理--在应用层可以设置是只将驱动接收到的指定can标示符的can_frame上报给应用层,如下
struct can_filter rfilter;//过滤
rfilter.can_id = 0x123;//选择监听can_frame中标示符是0x123的can帧,不过滤则监听所有。
rfilter.can_mask = CAN_SFF_MASK;
setsockopt(m_can, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
站123处理完了之后,根据需要要么回复一下(要不不回复),回复的时候也会使用相同的帧结构,回复的时候身份就变成了主机。看来can总线上流动的数据都是某个站主动发出的。而modbus总线上仅可以有一个主机,通信必须采用一问一答的形式,由于主机问的问题有好几种,所以从机针对每个问题回复的modbus帧也些差别。不像can的帧,仅有一种(仅讨论标注帧),每帧最大限制为8个字节。
DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[1]=24//TXBnSIDH--? DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[2]=60//TXBnSIDL--? DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[3]=1//TXBnEID8--? DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[4]=23//TXBnEID0--? DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[5]=5//TXBnDLC DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[6]=68//TXBnD0 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[7]=65//TXBnD1 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[8]=6c//TXBnD2 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[9]=6c//TXBnD3 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[10]=6f//TXBnD4 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[11]=0//TXBnD5 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[12]=0//TXBnD6 DBG(drivers/net/can/mcp251x.c, mcp251x_hw_tx(), 482): buf[13]=0//TXBnD7
can的多主与485的单主
Can总线本身就是为多主系统设计的,可以在一根总线上有多个主站。而485本身只能是单主的,只能通过其他的办法(如令牌)来变成一个多主系统。这是由硬件特点决定的。485总线上如果有两个节点同时都发送了信号,总线状态无法不确定的,即发送的报文可能已经被破坏了,为了解决这个问题,在某一时刻只能有一个站点主动发起通讯,其他站点都可看成从站。而Can的对比的主要优点在于可以实现非破坏仲裁,为此在硬件上进行了特殊设计,从总线可以看成是一个线与的结构,如果两个或以上节点发送信号电平不一致,总线电平显示为显性,这意味着至少有一个站点的报文没有被破坏。为了仲裁节点在发送信号的同时还在监测总线,如果发送和检测不一致则认为本节点发送报文已经被破坏。节点会自动退出发送状态等待发送结束以后开始下一次发送。而报文始终正确的站点最终取得总线控制权。
有一个问题哦,can是多主的总线,spi是单主的总线,那么6410的spi和mcp2515连起来之后怎么就变成了多主了呢?以图说明
![](http://my.csdn.net/uploads/201207/14/1342274011_3345.jpg)
每个6410下只挂一个mcp2515。
6410的cs引脚配置为输出,用于选中从机。
当6410.1有数据要发送时,6410.1作为spi主机向mcp2515.1发送数据,然后mcp2515.1作为主机,向总线发送数据。
当mcp2515.2从can总线上接收到数据时,它会向6410.2产生一个中断,此时6410.2会作为spi主机从mcp2515.2中主动读到数据。
看来是多亏了那根中断线,使得6410都可以作为spi主机主动从与之相连的mcp2515读数据。
can的错误检测