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
-
Socket creation and binding:
- use
socket()
Creates a raw SocketCAN socket. - use
ioctl()
andSIOCGIFINDEX
Gets the index of the CAN interface. - use
bind()
Bind the SocketCAN socket to the CAN interface.
- use
-
CAN frame preparation and sending:
- set up
can_frame
Structuralcan_id
(frame identifier) anddata
(Data) field. - use
write()
Send CAN frames to the CAN bus.
- set up
-
CAN frame reception:
- use
read()
Receive CAN frames from the CAN bus. - Parses the received CAN frame and prints out its ID and data.
- use
-
Socket Close:
- use
close()
Close the SocketCAN socket.
- use
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
-
Initialize PCAN device:
Initialize the PCAN device using the CAN_Initialize function, specifying the channel and baud rate used (500 kbps here). -
Send a CAN message:
Use the CAN_Write function to send a simple CAN message, setting the message's identifier, length, and data content. -
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. -
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
-
Initialize CANlib:
Initialize the Kvaser CANlib SDK using the canInitializeLibrary() function. -
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. -
Set channel parameters:
Use the canSetBusParams() function to set the baud rate of the channel.
Set to canBITRATE_500K, i.e. 500 kbps. -
Start the CAN channel:
Use the canBusOn() function to start the CAN channel so that it can send and receive CAN messages. -
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. -
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. -
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. -
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;
}