CAN
1. 简介
CAN,全称为Controller Area Network(控制器局域网),是一种广泛用于实时数据通信的串行通信协议。CAN协议最初是由德国公司Bosch开发的,用于汽车领域的电子控制单元(ECU)之间的通信。由于其高效、可靠的特性,CAN协议后来被广泛应用于其他领域,如工业自动化、医疗设备、船舶、航空航天等。
2 开启CAN
RM_IO 具有高度灵活性,支持将任意 RMIO 引脚指定为 CAN 接口。考虑到不同客户对于 CAN 接口的使用需求差异较大,我们预先开启的设置可能无法满足所有客户的实际需求。所以,出厂镜像默认未开启 CAN 接口功能。建议客户自行下载 SDK,在设备树中添加本节末尾提供的设备树内容,然后编译镜像,从而按需开启 CAN 接口。本示例以微雪电子的 USB-CAN-A 和 SN65HVD230 CAN Board 为基础进行测试。
3. 常用命令
与USB-CAN-FD模块通信,设置仲裁域波特率、数据域波特率为1M。
sudo su
ip link set can0 down
ip link set can0 type can bitrate 1000000 dbitrate 1000000 fd on
ip link set can0 upCAN FD发送:
发送(标准帧,数据帧,ID:123,date:DEADBEEF): cansend can0 123##1DEADBEEF
发送(扩展帧,数据帧,ID:00000123,date:DEADBEEF): cansend can0 00000123##1DEADBEEFCAN 2.0发送:
发送(标准帧,数据帧,ID:123,date:DEADBEEF): cansend can0 123#DEADBEEF
发送(标准帧,远程帧,ID:123): cansend can0 123#R
发送(扩展帧,数据帧,ID:00000123,date:DEADBEEF): cansend can0 00000123#12345678
发送(扩展帧,远程帧,ID:00000123): cansend can0 00000123#RCAN 2.0 与 CAN FD 接收。
candump can0
4. CAN 测试(Python 程序)
如果您想使用 Python 代码进行 CAN 总线测试,python-can 是一个非常合适的 Python 库。它为 CAN 通信提供了高层封装,支持多种底层 CAN 接口,如 SocketCAN、PCAN 和 Kvaser 等,使开发者能够在 Python 中轻松进行 CAN 总线通信。通过 python-can,您可以专注于数据的发送与接收,而无需深入了解底层的复杂细节。
检测库是否安装成功。
root@luckfox:/home/luckfox# python3
Python 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import can
>>> exit()编写发送程序(脚本命名尽量不要使用
can.py,它可能与python-can库产生冲突)。#!/usr/bin/python3
import can
def send_can_message():
# 使用 SocketCAN 方式连接到 can0
bus = can.interface.Bus(channel='can0', bustype='socketcan')
# 创建一个 CAN 消息
msg = can.Message(arbitration_id=0x123, data=[1, 2, 3, 4, 5, 6, 7, 8], is_extended_id=False)
# 发送 CAN 消息
try:
bus.send(msg)
print("Message sent on can0")
except can.CanError:
print("Message NOT sent")
if __name__ == "__main__":
send_can_message()运行程序,在打开一个新的终端窗口:
chmod +x can_test.py
./can_test.py
root@luckfox:/home/luckfox# candump can0
can0 123 [8] 01 02 03 04 05 06 07 08
5. CAN 测试(C 程序)
SocketCAN是 Linux 系统中原生支持的一种 CAN 总线(Controller Area Network)接口。它通过标准的网络接口(类似以太网)来使用和配置 CAN 总线,提供了一个与常见网络协议栈(如TCP/IP)类似的接口。这使得使用 CAN 变得更加灵活和简洁。
主要特点:
- 统一接口:SocketCAN 将 CAN 设备视为网络接口(如
can0,can1),通过标准的网络API进行访问和配置。 - 内核支持:SocketCAN 是 Linux 内核的一部分,可以直接通过系统调用访问,使用标准的 socket 函数进行发送和接收。
- 协议支持:支持标准 CAN (CAN 2.0) 和 CAN FD(Flexible Data-rate)。
- 设备抽象:将 CAN 控制器抽象为网络设备,使得通过标准网络工具(如
ip命令)配置和管理 CAN 总线变得简单。
5.1 使用 SocketCAN 编程
创建Socket:
int sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);绑定Socket到CAN接口:
struct ifreq ifr;
strcpy(ifr.ifr_name, "can0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
struct sockaddr_can addr;
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));发送和接收CAN帧:
write(sockfd, &frame, sizeof(struct can_frame));
read(sockfd, &frame, sizeof(struct can_frame));CAN 发送数据完整代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main() {
int sockfd;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
// 创建 CAN 套接字
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (sockfd < 0) {
perror("Error while opening socket");
return -1;
}
// 指定 CAN 接口(假设为 can0)
strcpy(ifr.ifr_name, "can0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
// 绑定 CAN 套接字到接口
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Error in socket bind");
return -2;
}
// 准备发送的 CAN 帧
frame.can_id = 0x123; // 11位标准帧ID
frame.can_dlc = 8; // 数据长度为8字节
// 使用循环赋值 CAN 数据帧
for (int i = 0; i < frame.can_dlc; i++)
{
frame.data[i] = i + 1; // 将数据从0x01到0x08依次赋值
}
// 发送 CAN 帧
for(int i=0;i<3;i++)
{
if (write(sockfd, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
perror("Write error");
return -3;
}
}
printf("CAN message sent on can0\n");
// 关闭套接字
close(sockfd);
return 0;
}交叉编译运行程序,搭建交叉编译环境请参考《程序编译》或《GPIO》部分。
arm-none-linux-gnueabihf-gcc can.c -o can重新打开另一个终端接收数据。
root@luckfox:/home/luckfox# candump can0
can0 123 [8] 01 02 03 04 05 06 07 08
can0 123 [8] 01 02 03 04 05 06 07 08
can0 123 [8] 01 02 03 04 05 06 07 08
6. 设备树简介
设备文件路径位于
kernel-6.1/arch/arm/boot/dts/rk3506g-luckfox-lyra.dts,开启can的代码片段如下:&can0 {
assigned-clocks = <&cru CLK_CAN0>;
assigned-clock-rates = <200000000>;
pinctrl-names = "default";
pinctrl-0 = <&rm_io30_can0_tx &rm_io31_can0_rx>;
status = "okay";
};