当前位置: 首页 > web >正文

CAN(控制器局域网络)协议详解

CAN (Controller Area Network) 是什么?

CAN(控制器局域网络) 是一种用于设备之间通信的串行通信协议,最初由 Bosch 公司在 1980 年代开发,用于汽车内部控制系统。它是一种 多主总线通信系统,具有高可靠性和实时性,广泛应用于汽车、工业控制、医疗设备等领域。


CAN 的工作原理:

  • 数据传输方式: 基于 差分信号传输,即通过两根数据线 CAN_H(高电平)和 CAN_L(低电平)传输数据。

  • 拓扑结构: 通常为 总线拓扑,多个节点(设备)共享一条总线。

  • 多主架构: 任何节点都可以主动发送数据,不存在主从关系。

  • 优先级控制: CAN 消息帧中的 标识符(ID) 用于确定优先级,ID 数值越小,优先级越高。


CAN 帧结构:

CAN 数据帧主要分为以下几种类型:

  1. 数据帧 (Data Frame): 用于发送数据。

  2. 远程帧 (Remote Frame): 请求数据。

  3. 错误帧 (Error Frame): 报告总线上发生的错误。

  4. 过载帧 (Overload Frame): 指示接收节点需要更多时间处理数据。

典型的 CAN 数据帧 结构如下:

字段位数描述
Start of Frame1起始帧标志
Identifier11/29消息标识符
Control Field6控制字段(数据长度)
Data Field0-8字节数据字段
CRC Field15校验码
ACK Field2应答字段
End of Frame7帧结束标志

CAN 波特率:

CAN 总线支持多种波特率,常见波特率如下:

  • 125 kbps

  • 250 kbps

  • 500 kbps

  • 1 Mbps

1 Mbps 是传统 CAN 的最高速率。
如果波特率设置不一致,不同节点之间将无法正常通信。


CAN 协议版本:

  1. CAN 2.0A: 11 位标识符(标准帧)。

  2. CAN 2.0B: 29 位标识符(扩展帧)。

  3. CAN FD (Flexible Data-rate): 增加了数据传输速率(最高 8 Mbps)和数据长度(8 到 64 字节)。

CAN 的配置命令、调试方法或编程示例

1. Linux 中的 CAN 配置命令

Linux 内核从 2.6.25 版本开始内置了 SocketCAN,它提供了标准化的 CAN 网络接口,可以像网络接口一样操作 CAN 设备。

前提:

  • 内核必须启用 CAN 模块:can.kocan_raw.kovcan.ko 等。

  • 硬件设备如 USB-CAN 模块或 PCI-CAN 卡需要安装驱动。

1.1 启用 CAN 模块

首先,加载 CAN 模块:

sudo modprobe can
sudo modprobe can_raw
sudo modprobe can_dev

1.2 配置 CAN 接口

假设 CAN 设备节点为 can0,以 500 kbps 波特率为例:

# 关闭 CAN 接口
sudo ip link set can0 down# 设置波特率并启动
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up

查看 CAN 接口状态:

ip -details link show can0

1.3 模拟 CAN 接口 (vcan)

如果没有硬件设备,可以使用 vcan 虚拟 CAN 接口:

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 up

1.4 发送与接收 CAN 数据

发送数据帧:

cansend can0 123#1122334455667788

123:CAN 标识符(ID)
1122334455667788:8 字节数据

接收数据帧:

candump can0

 2. CAN 调试方法

2.1 使用 candump 监听 CAN 数据
candump can0

显示类似以下输出:

  can0  123   [8]  11 22 33 44 55 66 77 88
  • 123:CAN ID

  • [8]:数据长度

  • 11 22 33 44 55 66 77 88:数据内容


2.2 发送测试数据:

模拟发送数据:

cansend can0 321#DEADBEEF
  • 321:CAN ID

  • DEADBEEF:4 字节数据


2.3 过滤特定 CAN ID:

监听特定 CAN ID(例如 321):

candump can0,321:7FF
  • 321:7FF:表示仅显示 ID 为 321 的帧。


3. CAN 编程示例:C语言与 SocketCAN

示例:发送和接收 CAN 数据帧

示例 1:发送 CAN 数据帧

send_can.c

#include <stdio.h>
#include <stdlib.h>
#include <string.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 sock;struct sockaddr_can addr;struct ifreq ifr;struct can_frame frame;// 创建套接字sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);if (sock < 0) {perror("Socket");return 1;}// 设置 CAN 设备名称strcpy(ifr.ifr_name, "can0");ioctl(sock, SIOCGIFINDEX, &ifr);// 绑定套接字addr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;bind(sock, (struct sockaddr *)&addr, sizeof(addr));// 设置 CAN 数据帧frame.can_id = 0x123;frame.can_dlc = 8;frame.data[0] = 0x11;frame.data[1] = 0x22;frame.data[2] = 0x33;frame.data[3] = 0x44;frame.data[4] = 0x55;frame.data[5] = 0x66;frame.data[6] = 0x77;frame.data[7] = 0x88;// 发送数据帧if (write(sock, &frame, sizeof(frame)) != sizeof(frame)) {perror("Write");return 1;}printf("CAN 数据发送成功\n");close(sock);return 0;
}

编译并运行:

gcc -o send_can send_can.c 
sudo ./send_can

示例 2:接收 CAN 数据帧

recv_can.c

#include <stdio.h>
#include <stdlib.h>
#include <string.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 sock;struct sockaddr_can addr;struct ifreq ifr;struct can_frame frame;// 创建套接字sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);if (sock < 0) {perror("Socket");return 1;}// 设置 CAN 设备名称strcpy(ifr.ifr_name, "can0");ioctl(sock, SIOCGIFINDEX, &ifr);// 绑定套接字addr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;bind(sock, (struct sockaddr *)&addr, sizeof(addr));printf("等待 CAN 数据帧...\n");// 循环接收数据while (1) {int nbytes = read(sock, &frame, sizeof(frame));if (nbytes < 0) {perror("Read");return 1;}printf("接收 CAN ID: 0x%03X DLC: %d Data: ", frame.can_id, frame.can_dlc);for (int i = 0; i < frame.can_dlc; i++) {printf("%02X ", frame.data[i]);}printf("\n");}close(sock);return 0;
}

编译并运行:

gcc -o recv_can recv_can.c 
sudo ./recv_can

 调试方法:

  • 开启调试日志:

    sudo ip link set can0 up type can bitrate 500000
    sudo ip link set can0 up
    dmesg | grep can
    
  • 查看网络流量:

    candump can0
  • 发送测试数据:

    cansend can0 123#1122334455667788

http://www.xdnf.cn/news/6054.html

相关文章:

  • 反射(Reflection)详解
  • leetcode0295. 数据流的中位数-hard
  • python数据分析常用的10个核心库
  • gradle--问答
  • Vxworks 系统详解
  • Realtek 8126驱动分析第四篇——multi queue相关
  • vLLM Serve 命令参数详解
  • 小白成长之路-文件和目录内容检索处理(一)
  • 2025年项目管理软件哪个更流行?如何解决用例复用率低的难题?
  • write failed: Connection reset by peer
  • 抖音怎么快速涨粉(抖音推流算法研究)
  • python语言与地理处理note 2025/05/11
  • ArrayList的扩容机制
  • 基于脑功能连接组和结构连接组的可解释特定模态及交互图卷积网络|文献速递-深度学习医疗AI最新文献
  • 普通IT的股票交易成长史--20250513复盘
  • 收集卡牌 第23次CCF-CSP计算机软件能力认证
  • 大模型中的KV Cache
  • 开发者版 ONLYOFFICE 协作空间:3.1版本 API 更新
  • RabbitMQ学习(自用)
  • (顺序表、单链表、双链表)==>一篇解决!(Java版)
  • 【即插即用涨点模块】【上采样】CARAFE内容感知特征重组:语义信息与高效计算两不误【附源码】
  • MyBatis与MyBatis-Plus深度分析
  • SimpleAdmin云服务器发布
  • Qt —— 在Windows10下通过在线安装方式安装Qt6.9.0(附:“server replied: Forbidden“网络出错解决办法)
  • Pytorch张量和损失函数
  • 电子科技浪潮下的华秋电子:慕尼黑上海电子展精彩回顾
  • 反转链表II
  • mysql常用方法
  • 关于Go语言的开发环境的搭建
  • 组合问题(多条件)