CAN Bus

1、 History

1.1 CAN总线发展历史

控制器局域网(Controller Area Network)最早由Bosch公司于1985年研发,用于搭建车内网络。在此之前,汽车生产商使用点对点布线系统连接车内电子设备。但随着车内电子设备的增多,这种布线系统需要的连线也越来越多,使系统变得既笨重又昂贵。于是,生产商开始使用车内网络来替代点对点布线系统,以降低布线的成本、复杂度,以及系统重量。在此背景下,CAN作为一种构建智能设备网络的高集成度串行总线系统应运而生,成为车内网络的标准。由此,CAN在汽车业界迅速普及,于1993年成为国际标准(ISO 11898)。1994年后,数个CAN的高层协议标准形成,如CANopen和DeviceNet。这些新增协议也为其他市场广泛接受,现已成为工业通信标准的一部分。

1.2 从业经历中接触到的CAN总线的历史

1、aa 的分子诊断仪的加样针(Tecan)的通信
2、bb 的仪器里使用的优爱宝步进电机控制器
3、cc 的输液管理系统的通信

2、 CAN应用

  • CAN最初是在汽车领域诞生的,因此最常见的应用就是车内电子网络。然而在过去的二十年,越来越多的行业认识了CAN的可靠性和优势,将CAN总线应用在许多其他场合。例如有轨电车、地铁、轻轨及长途列车等都应用了CAN网络。在这些车辆中,均可发现发现多种CAN构建的网络,如连接车门单元、刹车控制器、客流计数单元等。在航空领域亦可发现CAN的应用,如飞行状态传感器、导航系统以及座舱中的计算机。此外,在航天应用中也能看到CAN总线的身影,如飞行数据分析和飞行器引擎控制系统(燃料系统、泵、线性执行器等)。

  • 医疗设备制造商使用CAN构建医疗设备的嵌入式网络。部分医院已经使用CAN来管理整个手术室。医院通过基于CAN的系统管理手术室的各个部分,如灯光、手术台、X光机和病患床铺。升降电梯和电扶梯也采用CAN网络,通过CANopen协议连接电梯设备,如面板、控制器、电梯门和挡光器,并进行控制操作。

3、 CAN术语

3.1 隐性与显性电平

CAN控制器通过组成总线的2根线(CAN-H和CAN-L)的电位差来确定总线的电平,在任一时刻,总线上有2种电平:显性电平和隐性电平。
“显性”具有“优先”的意味,只要有一个单元输出显性电平,总线上即为显性电平,并且,“隐性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。
总线上执行逻辑上的线“与”时,显性电平的逻辑值为“0”,隐性电平为“1”。

3.2 帧类型

类型 使用 备注
数据帧 发送方通过此帧向接收方传送信息 用户发送
远程帧 接收方通过此帧向具有相同ID的发关方请示数据 用户发送
错误帧 当检测到错误时,向其它单元通知检测到错误 控制器发送
过载帧 接收方用来通知还末准备好接收一帧 控制器发送
帧间隙 用来将数据帧或远程帧与前面的帧隔开 控制器发送

3.3 数据帧格式

数据帧在结构上由7个段组成:

这里写图片描述
其中根据仲裁段ID码长度的不同,分为标准帧(CAN2.0A)和扩展帧(CAN2.0B)
这里写图片描述

3.4 远程帧格式

远程帧在结构上由6个段组成:
这里写图片描述
这里写图片描述

对于错误帧、过载帧、帧间隙攻城狮不需要知道太多的细节。

4、 Linux CAN

这里以IMX6Q,linux3.0.35为例,参考《i.MX 6Dual/6Quad Linux Reference Manual》文档中的 Chapter 32 FlexCAN Driver
首先在内核配置时,要把CAN给配置好,具体可以参考上述文档。

内核参考文档:
linux-3.0.35/Documentation/networking/can.txt

驱动源码:
linux-3.0.35/drivers/net/can/flexcan.c

4.1 主要的数据结构:

The basic CAN frame structure and the sockaddr structure are defined
in include/linux/can.h:

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)));
};

The sockaddr_can structure has an interface index like the
PF_PACKET socket, that also binds to a specific interface:

struct sockaddr_can {
        sa_family_t can_family;
        int         can_ifindex;
        union {
                /* transport protocol class address info (e.g. ISOTP) */
                struct { canid_t rx_id, tx_id; } tp;

                /* reserved for future CAN protocols address information */
        } can_addr;
};

4.2 第一步:

初始化CAN

ifconfig canX down
ip link set canX type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
ip link set canX type can bitrate 500000
ip link set canX type can restart-ms 100
ifconfig canX up

4.3 第二步:

建立socket连接

struct  ifreq ifr;
sockaddr_can  addr;

fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
ret = ioctl(fd, SIOCGIFINDEX, &ifr);

addr.can_family = PF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(fd,(struct sockaddr *)&addr,sizeof(addr));

4.4 第三步:

接收

    fd_set                  fdRead;
    struct  can_frame       frame;
    int                     nbytes;
    struct  timeval         tv;
    memset(&frame,0,sizeof(frame));

    FD_ZERO(&fdRead);
    FD_SET(fd, &fdRead);

    tv.tv_sec   = 0;
    tv.tv_usec  = 5;   //  5us  wait time
    ret = select(fd+1, &fdRead, NULL, NULL, &tv);
    if (ret <= 0)
    {
        return ;
    }

    bool selectForRead  = FD_ISSET(fd, &fdRead);

    if (selectForRead)
    {
        socklen_t len = sizeof(addr);
        nbytes = recvfrom(fd, &frame, sizeof(struct can_frame), 0,
                          (struct sockaddr*)&addr, &len);

        if( frame.can_dlc != 0)
        {
            // get one frame
        }   
    }

发送

   struct can_frame    frame;

   FD_ZERO(&fdWrite);
   FD_SET(fd, &fdWrite);

   tv.tv_sec   = 0;
   tv.tv_usec  = 5;   //  5us  wait time
   ret = select(fd+1, NULL, &fdWrite, NULL, &tv);
   if (ret <= 0)
   {
       return;
   }
   bool selectForWrite = FD_ISSET(fd, &fdWrite);

   if (selectForWrite)
   {
        sendto(fd, &frame, sizeof(struct can_frame), 0,
                           (struct sockaddr*)&addr, sizeof(addr));
   }

文件系统

#ls /sys/class/net/can0/            
addr_assign_type  dormant           link_mode         statistics
addr_len          duplex            mtu               subsystem
address           features          netdev_group      tx_queue_len
broadcast         flags             operstate         type
carrier           ifalias           power             uevent
dev_id            ifindex           queues
device            iflink            speed

5、Tips

  1. 半双工通信,差分信号
  2. 终端电阻 100 欧姆
  3. ID越小发送优先级越高
  4. 速率越高传送距离越短,最高1Mbps
  5. 最多一帧能传8个字节
  6. 多主模式

6、 参考

https://en.wikipedia.org/wiki/CAN_bus
http://blog.csdn.net/maifansnet/article/details/48950615
http://www.cnblogs.com/pejoicen/p/3986587.html
http://blog.csdn.net/shanghaiqianlun/article/details/17794427
https://lwn.net/Articles/253425/
CAN2.0A/B 文档

猜你喜欢

转载自blog.csdn.net/amwha/article/details/78203679
CAN