CAN从原理到应用

1.简介

CAN(Controller Area Network)是一种常用于实时通信的串行总线标准,广泛应用于汽车、工业控制、航空航天等领域。它提供了可靠的数据传输和高级别的错误检测和纠正功能。

下面是对CAN接口的简要介绍:

  1. 物理层接口

    • CAN接口采用差分信号传输,使用两根线(CAN_H和CAN_L)传输数据和同步信号。
    • 物理层接口使用标准的DB9或者DB25连接器,或者采用D-SUB形状的插头。
  2. 数据帧格式

    • CAN数据帧由标识符(ID)、数据和其他控制字段组成。
    • 标准CAN帧(CAN 2.0A)包含11位ID,扩展CAN帧(CAN 2.0B)包含29位ID。
    • CAN帧还包括数据长度码(DLC)字段,指定了数据域的字节数。
  3. 通信方式

    • CAN总线使用CSMA/CD(Carrier Sense Multiple Access with Collision Detection)策略,即多路访问冲突检测。
    • 在CAN总线上传输的多个节点可以同时发送消息,如果发生冲突,将根据优先级进行冲突解决。
  4. 错误检测和纠正

    • CAN接口通过使用循环冗余校验(CRC)来检测传输错误,并可以做到自动纠正数据错误。
    • 当错误发生时,CAN控制器会发出错误报告,例如错误传送计数器增加、误码率超过阈值等。
  5. 数据传输速率

    • CAN接口支持多种数据传输速率,如1 Mbps、500 kbps、250 kbps、125 kbps等。
    • 不同的应用要求可以选择合适的数据传输速率。

总结而言,CAN(Controller Area Network)是一种广泛应用于实时通信的串行总线标准。它采用差分信号传输,具备高级别的错误检测和纠正功能,能够在多个节点之间实现可靠的数据传输。CAN接口在许多领域中被使用,特别是汽车和工业控制等领域中,为系统提供了快速、可靠的通信方式。

2.什么是差分信号?

  • 差分信号由一对电平互补的信号线组成,通常被称为正差分线(Positive)和负差分线(Negative)。
  • 正差分线携带的信号电平高时,负差分线的信号电平低;反之,正差分线的信号电平低时,负差分线的信号电平高。
  • 通过在接收端计算正差分线和负差分线之间的差值,可以还原出原始信号。

3.CAN传输流程 

  1. 发送节点准备数据帧

    • 发送节点准备要发送的数据,并将数据放入CAN帧的数据域中。
    • 发送节点为CAN帧设置标识符(ID),标识发送的消息类型和优先级等。
  2. 发送节点发送数据帧

    • 发送节点将准备好的CAN帧发送到总线上。
    • 在发送之前,发送节点会监听总线上是否有其他节点发送数据,以避免发生冲突。
  3. 所有节点接收数据帧

    • 所有节点通过CAN接收器监听总线上的数据帧。
    • 当一个节点在总线上检测到有CAN帧到达时,它会读取CAN帧的内容。
  4. 接收节点过滤和判定

    • 接收节点检查接收到的CAN帧的ID是否与自身要接收的ID匹配。
    • 如果匹配,接收节点将接收到的CAN帧存储到接收缓冲区中,供后续处理使用。
  5. 接收节点处理数据帧

    • 接收节点处理接收到的CAN帧,执行相应的操作,例如读取数据、响应、发送回复等。
  6. 错误检测和纠正

    • CAN总线上的所有节点都能进行错误检测,并在发现错误时进行相应处理。
    • 发送节点和接收节点都可以检测到传输错误,如位错误、格式错误、冲突等。
  7. 重复发送和确认

    • 如果发送节点未收到发送的CAN帧的确认信息,它会重新发送CAN帧,直到收到确认或达到最大重试次数。

4.gpio模拟CAN

不可行

5.liunx下使用socketCAN

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define CAN_INTERFACE "can0"  // CAN接口名称

int main(void) 
{
    struct sockaddr_can addr;
    struct ifreq ifr;
    int sockfd;

    // 创建SocketCAN套接字
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (sockfd < 0) 
    {
        perror("Failed to open CAN socket");
        return -1;
    }

    // 绑定SocketCAN套接字到CAN接口
    strcpy(ifr.ifr_name, CAN_INTERFACE);
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
    {
        perror("Failed to bind CAN socket to interface");
        close(sockfd);
        return -1;
    }

    // 准备CAN帧数据
    struct can_frame frame;
    frame.can_id = 0x123;  // CAN帧ID
    frame.can_dlc = 3;     // 数据长度
    frame.data[0] = 0x01;  // 数据字节1
    frame.data[1] = 0x02;  // 数据字节2
    frame.data[2] = 0x03;  // 数据字节3

    // 发送CAN帧
    if (write(sockfd, &frame, sizeof(frame)) != sizeof(frame)) 
    {
        perror("Failed to write CAN frame");
        close(sockfd);
        return -1;
    }

    // 接收CAN帧
    struct can_frame recv_frame;
    while (1) 
    {
        ssize_t bytes_read = read(sockfd, &recv_frame, sizeof(recv_frame));
        if (bytes_read > 0) 
        {
            printf("Received CAN frame: ID=0x%03X, DLC=%d, Data=", recv_frame.can_id, recv_frame.can_dlc);
            for (int i = 0; i < recv_frame.can_dlc; i++) 
            {
                printf("0x%02X ", recv_frame.data[i]);
            }
            printf("\n");
        }
    }

    close(sockfd);
    return 0;
}

你可能感兴趣的:(LINUX,can总线)