gogoWebsite

CAN communication

Updated to 16 days ago

CAN (Controller Area Network) communication is a serial communication protocol specially designed for high-speed real-time data transmission.

Features and advantages

Real-time and high-speed:The CAN bus can communicate at rates up to 1 Mbps, supporting real-time data transmission requirements.
reliability:The CAN protocol designs a variety of error detection and recovery mechanisms, such as CRC (cyclic redundancy verification), ACK (answer confirmation), retransmission mechanism, etc., to ensure the reliability and stability of communication.
Multi-host network:The CAN bus adopts a distributed multi-host network structure, and each node can send or receive messages independently without a central controller.
Anti-interference ability:The CAN bus has designed a differential signal line, making it highly resistant to electromagnetic interference (EMI), and is suitable for use in noise environments such as vehicles.
Low cost and simple implementation:The CAN bus hardware is relatively low, and the protocol itself is simpler, easy to implement and integrate into different devices.

Some common CAN libraries include:
SocketCAN: An open source CAN protocol stack under Linux, which can be accessed through the socket interface.
PCAN: A set of CAN interface libraries under Windows, supporting multiple CAN hardware devices.
Kvaser CANlib SDK: a cross-platform CAN library that supports multiple operating systems and hardware devices.

1. socketCAN realizes CAN communication

Use the SocketCAN interface on the Linux platform to implement CAN communication and receive and send CAN frames.

Create steps

  1. Socket creation and binding

    • usesocket()Creates a raw SocketCAN socket.
    • useioctl()andSIOCGIFINDEXGets the index of the CAN interface.
    • usebind()Bind the SocketCAN socket to the CAN interface.
  2. CAN frame preparation and sending

    • set upcan_frameStructuralcan_id(frame identifier) ​​anddata(Data) field.
    • usewrite()Send CAN frames to the CAN bus.
  3. CAN frame reception

    • useread()Receive CAN frames from the CAN bus.
    • Parses the received CAN frame and prints out its ID and data.
  4. Socket Close

    • useclose()Close the SocketCAN socket.

Sample code description

Used to send and receive CAN frames using the SocketCAN interface on Linux.

#include <iostream>
#include <cstring>
#include <sys/>
#include <sys/>
#include <net/>
#include <linux/>
#include <linux/can/>
#include <>

int main() {
    int s; // Socket descriptor
    struct sockaddr_can addr;
    struct ifreq ifr;

    const char *ifname = "can0"; // CAN interface name

    // Create a raw SocketCAN socket
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("Socket creation failed");
        return 1;
    }

    // Set the CAN interface name
    strcpy(ifr.ifr_name, ifname);
    ioctl(s, SIOCGIFINDEX, &ifr);

    // Bind to CAN interface
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("Binding to interface failed");
        close(s);
        return 1;
    }

    // Prepare a CAN frame
    struct can_frame frame;
    frame.can_id = 0x123; // CAN frame ID
    frame.can_dlc = 2;    // Data length
    frame.data[0] = 0x11;
    frame.data[1] = 0x22;

    // Send CAN frames
    if (write(s, &frame, sizeof(frame)) != sizeof(frame)) {
        perror("Write to CAN bus failed");
        close(s);
        return 1;
    }

    std::cout << "Message sent to CAN bus" << std::endl;

    // Receive CAN frames
    struct can_frame recv_frame;
    ssize_t nbytes = read(s, &recv_frame, sizeof(recv_frame));
    if (nbytes < 0) {
        perror("Read from CAN bus failed");
    } else if (nbytes < sizeof(struct can_frame)) {
        perror("Incomplete CAN frame received");
    } else {
        std::cout << "Received CAN frame: ID = 0x" << std::hex << recv_frame.can_id << ", Data = ";
        for (int i = 0; i < recv_frame.can_dlc; ++i) {
            std::cout << std::hex << static_cast<int>(recv_frame.data[i]) << " ";
        }
        std::cout << std::dec << std::endl;
    }

    // Close SocketCAN socket
    close(s);

    return 0;
}

2. PCAN realizes CAN communication

The following is a simple sample code that demonstrates how to use the PCAN-Basic API to communicate on a Windows platform via a PCAN-USB interface card.
Using the PCAN-Basic API requires first installing PEAK's PCAN-Basic driver and related software.

Create steps

  1. Initialize PCAN device:
    Initialize the PCAN device using the CAN_Initialize function, specifying the channel and baud rate used (500 kbps here).

  2. Send a CAN message:
    Use the CAN_Write function to send a simple CAN message, setting the message's identifier, length, and data content.

  3. Read CAN message:
    Use the CAN_Read function to read messages received from the CAN bus in a loop. If a message is received, print it out; if no message is received, it will wait and continue to read.

  4. Close PCAN channel:
    Finally, use the CAN_Uninitialize function to close the PCAN device.

Code example:

#include <>
#include <>
#include <>
#include ""

void main()
{
    // Initialize PCAN device
    TPCANHandle hnd;
    TPCANStatus status;
    TPCANMsg msg;
    DWORD iBuffer;

    // Open PCAN channel
    hnd = PCAN_USBBUS1;  //Use PCAN-USB Channel 1
    status = CAN_Initialize(hnd, PCAN_BAUD_500K, 0, 0, 0);
    if (status != PCAN_ERROR_OK) {
        printf("Error: CAN_Initialize failed. Status: 0x%x\n", status);
        return;
    }

    // Send CAN message
    msg.ID = 0x123;     // CAN identifier
    msg.LEN = 2;        // Message length
    msg.MSGTYPE = PCAN_MESSAGE_STANDARD;  // Standard CAN message
    msg.DATA[0] = 0x01; // Data byte 1
    msg.DATA[1] = 0x02; // Data byte 2

    status = CAN_Write(hnd, &msg);
    if (status != PCAN_ERROR_OK) {
        printf("Error: CAN_Write failed. Status: 0x%x\n", status);
        CAN_Uninitialize(hnd);
        return;
    }

    // Read CAN message
    while (!_kbhit()) {
        status = CAN_Read(hnd, &msg, NULL);
        if (status == PCAN_ERROR_OK) {
            printf("Received message. ID: 0x%x, Length: %d, Data: %02x %02x\n",
                   msg.ID, msg.LEN, msg.DATA[0], msg.DATA[1]);
        }
        else if (status != PCAN_ERROR_QRCVEMPTY) {
            printf("Error: CAN_Read failed. Status: 0x%x\n", status);
            break;
        }
        Sleep(100);  // Wait for 100 milliseconds
    }

    // Close PCAN channel
    CAN_Uninitialize(hnd);
}

3. Kvaser CANlib SDK implements CAN

The Kvaser CANlib SDK is a software development toolkit for Kvaser CAN interface cards, which allows the development of CAN bus communications under a variety of operating systems, including Windows and Linux.
canOPEN_ACCEPT_VIRTUAL

Create steps

  1. Initialize CANlib
    Initialize the Kvaser CANlib SDK using the canInitializeLibrary() function.
  2. Open the channel:
    Use the canOpenChannel() function to open the first available CAN channel and specify the canOPEN_ACCEPT_VIRTUAL flag to accept the virtual channel.
  3. Set channel parameters:
    Use the canSetBusParams() function to set the baud rate of the channel.
    Set to canBITRATE_500K, i.e. 500 kbps.
  4. Start the CAN channel:
    Use the canBusOn() function to start the CAN channel so that it can send and receive CAN messages.
  5. Construct and send CAN messages:
    Construct a canMessage structure to represent the CAN message to be sent and send the message to the CAN bus using the canWrite() function.
  6. Receive CAN message:
    In a while loop, use the canRead() function to receive messages received from the CAN bus. If the message is received successfully, print it out.
  7. Close the CAN channel:
    Use the canBusOff() function to close the CAN channel and stop CAN communication.
    Use the canClose() function to close the open CAN channel.
  8. Uninstall CANlib:
    Uninstall the Kvaser CANlib SDK using the canUnloadLibrary() function.

Code example:

#include <iostream>
#include <>

int main() {
    // Initialize CANlib
    canInitializeLibrary();

    // Open the first available channel
    int channel = canOpenChannel(0, canOPEN_ACCEPT_VIRTUAL);
    if (channel < 0) {
        std::cerr << "Error: canOpenChannel failed, error code " << channel << std::endl;
        return 1;
    }

    // Set the baud rate of the channel
    canSetBusParams(channel, canBITRATE_500K, 0, 0, 0, 0, 0);

    // Start the channel
    canStatus status = canBusOn(channel);
    if (status != canOK) {
        std::cerr << "Error: canBusOn failed, status " << status << std::endl;
        canClose(channel);
        return 1;
    }

    // Construct a CAN message
    canMessage msg;
    msg.id = 0x123;          // CAN identifier
    msg.len = 2;             // Message length
    msg.flags = 0;           // Standard frame
    msg.data[0] = 0x01;      // Data byte 1
    msg.data[1] = 0x02;      // Data byte 2

    // Send CAN message
    status = canWrite(channel, &msg);
    if (status != canOK) {
        std::cerr << "Error: canWrite failed, status " << status << std::endl;
        canBusOff(channel);
        canClose(channel);
        return 1;
    }

    // Receive CAN messages
    canMessage rxMsg;
    while (true) {
        status = canRead(channel, &rxMsg, 0);
        if (status == canOK) {
            std::cout << "Received message. ID: 0x" << std::hex << rxMsg.id << ", Length: "
                      << static_cast<int>(rxMsg.len) << ", Data: ";
            for (int i = 0; i < rxMsg.len; ++i) {
                std::cout << std::hex << static_cast<int>(rxMsg.data[i]) << " ";
            }
            std::cout << std::endl;
        }
        else if (status == canERR_NOMSG) {
            // No news, keep waiting
            continue;
        }
        else {
            std::cerr << "Error: canRead failed, status " << status << std::endl;
            break;
        }
    }

    // Close the CAN channel
    canBusOff(channel);
    canClose(channel);

    // Uninstall CANlib
    canUnloadLibrary();

    return 0;
}