Linux下的CAN通讯
CAN总线
CAN总线简介
CAN(Controller Area Network)总线是一种多主从式 <font color = red>
异步半双工串行 </font>
通信总线,它最早由Bosch公司开发,用于汽车电子系统。CAN总线具有以下特点:
- 多主从式:CAN总线允许多个节点同时进行通信,每个节点都可以发送和接收数据。
- 工作频率:CAN总线的工作频率通常为40kHz到1MHz,具体取决于应用场景。
- 通信距离:CAN总线可以在不同的通信距离下工作,最长可达1公里。
- 通信速率:CAN总线支持多种通信速率,从10kbps到1Mbps不等。高速CAN的通信速率为125kbps到1Mbps。低速CAN的通信速率为低于125kbps。
CAN的硬件连接
一般没有can控制器的设备,可以靠使用SPI转CAN模块,再外接CAN收发器,实现can的数据收发
CAN总线两端的120欧姆为终端电阻,是为了消除总线上的信号反射
电器属性
在高速 CAN中:
- 当 CANH 和 CANL 电压相同 (CANH= CANL=2.5V) 时为逻辑“1”(隐形状态)
- CANH 和 CANL 电压相差 2V (CANH=3.5V,CANL= 1.5V) 时为逻辑“0”(显性状态)。
CAN协议
缩写 | 含义 | 解释 |
---|---|---|
SOF | (strat offrame): | 帧起始。表示一帧数据的起始 |
ID | (identify): | 标识符 |
RTR | (remote transmission request): | 远程请求标志位 |
IDE | (identify extension): | 扩展标志位 |
SRR | (substitute remote request): | 替代远程请求标志位 |
R0/R1 | (reserve): | 保留位 |
DLC | (date length code) : | 表示数据字段有多少个字节 |
CRC | (cyclic redundancy check): | CRC校验 |
ACK | (acknowledge): | 应答 |
EOF | (end offrame): | 帧结束。表示一帧数据结束 |
1.数据帧
can通信是通过数据帧进行发送数据的,所以数据帧是:数据帧携带数据从发送设备到接收设备
1.2.数据帧格式
数据帧有 标准数据帧 和 扩展数据帧
1.3.1标准数据帧格式
标准数据帧格式分析:
can的空闲电平是1(高电平,隐性),所以起始帧是0(低电平,显性)
- 帧起始和帧结束
帧起始和帧结束表示一帧数据的起始和结束,帧起始由 1 个显性位组成,结束由 7 个连续
的隐形位组成。 - 仲裁字段
仲裁字段包括 11位ID 位,1位 RTR 位,共 12 位。D 位用可以用来区分数据的功能(不
司功能的报数据帧,ID 是不同的),也可以用来区分优先级。根据仲裁规则,ID 小的数据帧
优先发送。禁止高 7 位都为隐性(禁止设定: ID=1111111xXXX)。
RTR 是远程请求标志位,用于区分数据帧还是遥控帧。数据帧 RTR 位必须为显性 0,遥控
必须位隐性 1。(相同ID的数据和遥控,数据的优先级大干遥控帧)。 - 控制字段
控制字段由 1位IDE 位,1位 RO 保留位,4 位 DLC共6 位组成。
- IDE 位表示数据帧是标准数据帧还是扩展数组帧,标准格式固定为显示0,扩展格式固定为
隐性 1。 - RO 保留位,固定为显示 0。
- DLC 位表示数据字段的数据字节数(数据段的长度)。
- 数据字段
可以承载 0 到 64 位数据。 - CRC 校验字段
CRC 校验字段由 15 位校验位和 1位 CRC 界定字符组成,前 15 位用于 CRC 校验。CRC 界定符
必须为隐性 1 - ACK 字段
ACK 字段由确定间隙位和确认界定符组成,确认界定符必须是隐性 1。
1.3.2扩展数据帧格式
相比于标准帧格式,扩展帧多了一个扩展ID,扩展ID由29位组成,标准帧的ID由11位组成
SRR替换了原有的RTR,IDE为扩展帧的标识符(低电平0),外加了18为扩展ID,其他的并无异样
2.遥控帧
遥控帧用于接收设备主动请求数据。发送方通过广播的形式发送数据,数据帧中通过ID 区分不同功能的数据帧,如果发送方没有广播这个数据,接收方可以广播发送一个遥控帧,有接收方想要的数据的发送方就会广播这个数据出来。接收方就可以接收到这个数据了。
2.1 遥控帧格式
数据帧去掉数据段就是遥控帧,所以遥控帧也有两种帧格式
3.错误帧
在发送或者接收时,总线上的设备发生错误的时候,可以通过发送错误帧的方式告知其他节点发生了错误。错误帧由俩个部分组成,分别是错误标志和错误界定符。错误标志:
- 主动错误标志:6 个连续显性位
- 被动错误标志:6 个连续隐性位
错误界定符:8 个连续隐性位
4.过载帧
当某个接收节点没有做好接收下一帧数据的准备时,接收方将发送过载帧通知发送节点节点最多可产生俩条连续的过载顺来延迟一下次发送。过载标志的构成与主动错误标志的构成相同,过载界定符的构成与错误界定符的构成相同。
- 过载标志:6个位的显行
- 过载界定符:8个位的隐行
5.帧间隔
帧间隔是用于分隔数据帧和遥控帧的帧。数据帧和遥控帧可通过插入帧间隔将本帧与前面的任何帧(数据帧、遥控帧、错误帧、过载帧) 分开。
过载帧和错误帧前不能插入帧间隔。
6.位填充
CAN 总线上的数据是按照位来传输的,为了保证数据传输的可靠性,CAN 总线对数据进行了位填充。位填充是指在数据传输过程中,如果连续 5 个位都是显性位,那么就会插入一个隐形位。如果连续 5 个位都是隐形位,那么就会插入一个显性位。
仲裁机制
CAN 总线是一种多主从式总线,多个节点可以同时发送数据。为了防止多个节点同时发送数据导致冲突,CAN 总线采用了仲裁机制。仲裁机制是通过比较各个节点的 ID 来决定哪个节点可以发送数据。ID 小的节点优先发送数据。如果多个节点同时发送数据,那么 ID 小的节点会优先发送数据,其他节点会停止发送数据并进入监听状态,等待 ID 小的节点发送完数据后再发送数据。
在总线空闲态,最先开始发送消息的单元获得发送权。多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送。
主要通过以下方法:
- 非破坏性仲裁:显性优先,即显性优先级大于隐性优先级(线与机制: 只有所有节点都发送隐性 1 时,总线才为 1,只要有一个节点发送显性 0,则总线就为显性 0)
- 载波侦听: 总线上各个节点在发送数据前要侦听总线的状态,只有在总线是空闲状态时才允许发送。
- 回读:节点在发送数据时要不停的检测要发送的数据。通过非破坏性仲裁判断是否与其他节点的数据发生冲突。
CAN的应用工具
iproute2 工具移植
下载路径:
https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/
./configure
make CC=arm-linux-gcc
make install
CAN是作为网络设备存在的,所以查看CAN设备:
ifconfig -a
启动:
# 设置波特率
ip link set can0 type can bitrate 500000
# 启动can0设备
ifconfig can0 up
CAN的应用编程
CAN被规划为网络设备,所以在通信中使用的是socket编程。
int sokcet(int domain, int type, int protocol);
参数 | 解释 |
---|---|
domain: | 协议域,通常为PF_CAN |
type: | 指定协议类型,SOCK_RAW表示原始套接字,SOCK_DGRAM表示数据报套接字 |
protocol: | 指定协议,通常为CAN_RAW或CAN_BCM |
domain的常用协议族:
- PF_UNIX, PF_LOCAL: 本地通信
- PF_INET: IPv4网络通信
- PF_INET6: IPv6网络通信
- PF_NETLINK: 内核套接字,
- PF_CAN: CAN网络通信
type的常用协议类型:
- SOCK_STREAM:面向连接、可靠的、双向的、基于字节流的通数据按顺序传输,不会丢失或重复。通常用于TCP 协议
- SOCK_DGRAM:支持无连接、不可靠的、固定最大长度的消息据报传输。消息可能会丢失、重复或乱序。通常用于 UDP 协议
- SOCK SEQPACKET:提供面向连接、可靠的、双向的、基于固定最度数据报的通信,接收者必须每次系统调用读个数据包
- SOCK RAW:对原始网络协议的访问,允许应用程序直接发接收 IP 层的数据包,绕过传输层协议
- SOCK RDM:提供一种可靠的数据报层,但不保证顺序
- SOCK PACKET:提供对底层网络协议的直接访问,通常用于与设备驱动程序的通信
- SOCK NONBLOCK:新打开的文件描述符的非阻塞标志
- SOCK CLOEXEC:新文件描述符的在执行时关闭 (FD CLOEXEC)如果程序执行了一个新的程序,这个文件描将会被关闭,这有助于防止文件泄露到不受信程序中
SOURCE CODE
send CAN data:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>int main(int argc, char *argv[]){int s = socket(AF_CAN, SOCK_RAW, CAN_RAW); // Create CAN socketif(s < 0){printf("Error creating socket\n");return 1;}struct ifreq ifr; // Interface requeststrcpy(ifr.ifr_name, "can0"); // CAN interface nameif(ioctl(s, SIOCGIFINDEX, &ifr) < 0){ // Get CAN interface indexprintf("Error getting interface index\n");}struct sockaddr_can addr; // CAN socket addressaddr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex; // CAN interface index (0 for first interface)if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0){printf("Error binding socket\n");return 1;}struct can_frame frame[3]; // CAN frame 标准帧frame[0].can_id = 0x123; // CAN IDframe[0].can_dlc = 8; // Data length codefor(int i = 0; i < 8; i++){frame[0].data[i] = i; // Data}if(send(s, &frame[0], sizeof(frame[0]), 0) < 0){printf("Error sending frame\n");return 1;}frame[1].can_id = 0x456 | CAN_EFF_FLAG; // CAN ID with EFF flag 扩展帧frame[1].can_dlc = 2; // Data length codeframe[1].data[0] = 0x12;frame[1].data[1] = 0x34;if(send(s, &frame[1], sizeof(frame[1]), 0) < 0){printf("Error sending frame\n");return 1;}frame[2].can_id = 0x789 | CAN_RTR_FLAG; // CAN ID with RTR flag 远程帧frame[2].can_dlc = 0; // Data length codeif(send(s, &frame[2], sizeof(frame[2]), 0) < 0){printf("Error sending frame\n");return 1;}close(s);return 0;
}
recv CAN data:
- 在接收时可以配置过滤规则,只接收符合过滤条件的帧。
/* special address description flags for the CAN_ID */*#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */#define CAN_ERR_FLAG 0x20000000U /* error message frame */**/* valid bits in CAN ID for frame formats */#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */*
在配置时只需记得后缀为FLAG是要过滤的帧,后缀为MASK是要接收的帧。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>int main(int argc, char *argv[]){int s = socket(AF_CAN, SOCK_RAW, CAN_RAW); // Create CAN socketif(s < 0){printf("Error creating socket\n");return 1;}struct ifreq ifr; // Interface requeststrcpy(ifr.ifr_name, "can0"); // CAN interface nameif(ioctl(s, SIOCGIFINDEX, &ifr) < 0){ // Get CAN interface indexprintf("Error getting interface index\n");}struct sockaddr_can addr; // CAN socket addressaddr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex; // CAN interface index (0 for first interface)if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0){printf("Error binding socket\n");return 1;}struct can_frame frame; // CAN framechar buff[1024];struct can_filter filter[2]; // CAN filter 设置两条过滤规则// 设置过滤规则,只接收ID为0x123的标准帧filter[0].can_id = 0x123; // Filter IDfilter[0].can_mask = CAN_SFF_MASK; // Filter mask// 设置过滤规则,只接收ID为0x456的扩展帧和标准帧,但不要远程帧filter[1].can_id = 0x123; // Filter IDfilter[1].can_mask = CAN_SFF_MASK | CAN_EFF_MASK | CAN_RTR_FLAG; // Filter masksetsockopt(s,SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)); // 设置过滤规则while (1){int ret = read(s, &frame, sizeof(frame)); // Read CAN frameif(ret < 0){printf("Error reading frame\n");return 1;}else{if(frame.can_id & CAN_EFF_FLAG){printf("Extended ID: %x\n", frame.can_id & CAN_EFF_MASK);}else{printf("Standard ID: %x\n", frame.can_id & CAN_SFF_MASK);}printf("Data: ");for(int i = 0; i < frame.can_dlc; i++){printf("%02x ", frame.data[i]);}if(frame.can_id && CAN_RTR_FLAG){printf("Remote Transmission Request\n");}}}close(s);return 0;
}
相关文章:

Linux下的CAN通讯
CAN总线 CAN总线简介 CAN(Controller Area Network)总线是一种多主从式 <font color red>异步半双工串行 </font> 通信总线,它最早由Bosch公司开发,用于汽车电子系统。CAN总线具有以下特点: 多主从式&a…...
【Python】pip安装加速:使用国内镜像源
【Python】pip安装加速:使用国内镜像源 零、使用命令行设置 设置全局镜像源 随便使用下面任一命令即可! 阿里云: pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/豆瓣: pip config set global.in…...
SpringBoot lombok(注解@Getter @Setter)
SpringBoot lombok(注解Getter Setter) 使用lombok注解的方式,在编译生成的字节码文件中就会存在setter/getter等方法,减少代码量,方便了代码的维护 添加依赖 <dependency><groupId>org.projectlombok</groupId><artif…...

descrTable常用方法
descrTable 为 R 包 compareGroups 的重要函数,有关该函数以及 compareGroups 包的详细内容见:R包compareGroups详细用法 加载包和数据 library(compareGroups)# 加载 REGICOR 数据(横断面,从不同年份纳入,每个变量有…...

回归预测 | Matlab实现ReliefF-XGBoost多变量回归预测
回归预测 | Matlab实现ReliefF-XGBoost多变量回归预测 目录 回归预测 | Matlab实现ReliefF-XGBoost多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.ReliefF-xgboost回归预测代码,对序列数据预测性能相对较高。首先通过ReleifF对输入特征计算权…...

年度最强悬疑美剧重磅回归,一集比一集上头
纽约的夜晚,平静被一声枪响打破,一场离奇的谋杀案悄然上演。《大楼里只有谋杀》正是围绕这样一桩扑朔迷离的案件展开的。三位主角,赛琳娜戈麦斯饰演的梅宝、史蒂夫马丁饰演的查尔斯、马丁肖特饰演的奥利弗,这些性格迥异的邻居因为…...
AI一点通: 简化大数据与深度学习工作流程, Apache Spark、PyTorch 和 Mosaic Streaming
在大数据和机器学习飞速发展的领域中,数据科学家和机器学习工程师经常面临的一个挑战是如何桥接像 Apache Spark 这样的强大数据处理引擎与 PyTorch 等深度学习框架。由于它们在架构上的固有差异,利用这两个系统的优势可能令人望而生畏。本博客介绍了 Mo…...
Python知识点:深入理解Python的模块与包管理
开篇,先说一个好消息,截止到2025年1月1日前,翻到文末找到我,赠送定制版的开题报告和任务书,先到先得!过期不候! 深入理解Python的模块与包管理 Python的模块和包是代码组织、复用和分发的基本…...

倒排索引(反向索引)
倒排索引(Inverted Index)是搜索引擎和数据库管理系统中常用的一种数据结构,用于快速检索文档集合中的文档。在全文搜索场景中,倒排索引是一种非常高效的手段,因为它能够快速定位到包含特定关键词的所有文档。 1、基本…...
openCV的python频率域滤波
在OpenCV中实现频率域滤波通常涉及到傅里叶变换(Fourier Transform)和其逆变换(Inverse Fourier Transform)。傅里叶变换是一种将图像从空间域转换到频率域的数学工具,这使得我们可以更容易地在图像的频域内进行操作,如高通滤波、低通滤波等。 下面,我将提供一个使用Py…...

探索视频美颜SDK与直播美颜工具的开发实践方案
直播平台的不断发展,让开发出性能优异、效果自然的美颜技术,成为了技术团队必须面对的重要挑战。本篇文章,小编将深入讲解视频美颜SDK与直播美颜工具的开发实践方案。 一、视频美颜SDK的核心功能 视频美颜SDK是视频处理中的核心组件…...

Linux通过yum安装Docker
目录 一、安装环境 1.1. 旧的docker包卸载 1.2. 安装常规环境包 1.3. 设置存储库 二、安装Docker社区版 三、解决拉取镜像失败 3.1. 创建文件目录/etc/docker 3.2. 写入镜像配置 https://docs.docker.com/engine/install/centos/ 检测操作系统版本,我操作的…...

面部表情数据集合集——需要的点进来
文章目录 1、基本介绍2、每个数据集介绍2.1、FER2013(已预处理)2.2、FERPLUS(已预处理)2.3、RAF2.4、CK2.5、AffectNet2.6、MMAFEDB 3、获取方式 1、基本介绍 收集并整理了面部表情识别(Facial Emotion Recognition&am…...
AI学习指南深度学习篇-Adagrad的Python实践
AI学习指南深度学习篇-Adagrad的Python实践 在深度学习领域,优化算法是模型训练过程中至关重要的一环。Adagrad作为一种自适应学习率优化算法,在处理稀疏梯度和非凸优化问题时表现优异。本篇博客将使用Python中的深度学习库TensorFlow演示如何使用Adagr…...

vue2使用npm引入依赖(例如axios),报错Module parse failed: Unexpected token解决方案
报错情况 Module parse failed: Unexpected token (5:2) You may need an appropriate loader to handle this file type. 原因 因为我们npm install时默认都是下载最新版本,然后个别依赖的版本太新,vue2他受不起这个福分。 解决方法 先去package.js…...

MySQl篇(基本介绍)(持续更新迭代)
目录 一、为什么要使用数据库 1. 以前存储数据的方式 2. 什么是数据库 3. 采用的数据库的好处 4. 如何理解数据库、数据库管理系统、SQL 5. 如何理解数据是有组织的存储 6. 现在的数据库 二、关系型数据系统 1. 什么是关系型数据库 2. 关系型数据库特点 3. 关系型数据…...

Java开发与实现教学管理系统动态网站
博主介绍:专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的可以…...
麒麟操作系统 MySQL 主从搭建
MySQL rpm64 架构搭建主从 文章目录 1.检查操作系统2.配置基础环境3.下载软件并安装4. 服务初始化5 主从搭建5.1 主节点配置(192.168.31.82)5.2 从节点配置(192.168.31.83)5.3 从节点配置(192.168.31.84)5.4 节点都重启5.5 在主机上建立帐户并授权slave5.6 salve 来同步master…...

OSSEC搭建与环境配置Ubuntu
尝试使用Ubuntu配置了OSSEC,碰见很多问题并解决了,发表博客让后来者不要踩那么多坑 环境 : server :Ubuntu22.04 64位 内存4GB 处理器4 硬盘60G agent: 1.Windows11 64位 2.Ubuntu22.04 64位 服务端配置 一、配置安装依赖项&…...

【RabbitMQ】消息分发、事务
消息分发 概念 RabbitMQ队列拥有多个消费者时,队列会把收到的消息分派给不同的消费者。每条消息只会发送给订阅该队列订阅列表里的一个消费者。这种方式非常适合扩展,如果现在负载加重,那么只需要创建更多的消费者来消费处理消息即可。 默…...
抖音怎么下载没有水印的视频?
你是不是经常在抖音上刷到喜欢的视频,想保存下来却总是带着烦人的水印?无论是想收藏精彩片段,还是二次创作,水印都成了“拦路虎”。别急!今天就来教你3种超简单方法,轻松下载无水印抖音视频,高清…...

CoordConv: CNN坐标感知特征适应
传统卷积 vs CoordConv 详细对比 传统卷积对空间位置不敏感,CoordConv通过显式添加坐标信息解决这个问题在特征图中嵌入(x, y)坐标和可选的径向距离r使模型能够感知空间位置关系 1. 传统卷积的"空间位置不敏感"问题 传统卷积的特点: 输入: …...

mariadb5.5.56在centos7.6环境安装
mariadb5.5.56在centos7.6环境安装 1 下载安装包 https://mariadb.org/mariadb/all-releases/#5-5 2 上传安装包的服务器 mariadb-5.5.56-linux-systemd-x86_64.tar.gz 3 解压安装包 tar -zxvf mariadb-5.5.56-linux-systemd-x86_64.tar.gz mv mariadb-5.5.56-linux-syst…...
vm+ubuntu24.04扩展磁盘
vmubuntu24.04扩展磁盘 $ lsblk $ sudo fdisk -l 1.修复 GPT 表警告 $ sudo parted /dev/sda print当询问是否修复时,输入 Fix2.扩展物理分区 /dev/sda3 $ sudo growpart /dev/sda 33.刷新物理卷 (PV) $ sudo pvresize /dev/sda3检查可用的扩展空间. $ sudo vgd…...
嵌入式链表操作原理详解
嵌入式链表操作原理详解 链表是嵌入式软件开发中最基础的数据结构之一,其设计采用嵌入式链表节点的思想,实现了高度通用的链表管理机制。以下是核心原理和操作的全面解析: 一、基础数据结构 struct list_head {struct list_head *next, *pr…...
人工智能:网络安全的“智能守护者”
在数字化时代,网络安全已经成为企业和个人面临的重大挑战。随着网络攻击的复杂性和频率不断增加,传统的安全防护手段已经难以应对。人工智能(AI)技术的出现为网络安全带来了新的希望和解决方案。本文将探讨人工智能在网络安全中的…...

9.RV1126-OPENCV 视频的膨胀和腐蚀
一.膨胀 1.视频流的膨胀流程 之前膨胀都是在图片中进行的,现在要在视频中进行也简单,大概思路就是:获取VI数据,然后把VI数据给Mat化发给VENC模块,然后VENC模块获取,这样就完成了。流程图: 2.代…...

【八股消消乐】如何解决SQL线上死锁事故
😊你好,我是小航,一个正在变秃、变强的文艺倾年。 🔔本专栏《八股消消乐》旨在记录个人所背的八股文,包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法等相关知识点ÿ…...

OSCP备战-BSides-Vancouver-2018-Workshop靶机详细步骤
一、靶机介绍 靶机地址:https://www.vulnhub.com/entry/bsides-vancouver-2018-workshop%2C231/ 靶机难度:中级(CTF) 靶机发布日期:2018年3月21日 靶机描述: Boot2root挑战旨在创建一个安全的环境&…...

iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
在vue项目中使用iview 框架部分组件时,直接引入使用报Maximum call stack size exceeded image.png 堆栈溢出 解决方案 更换组件名称就可以了 image.png 或 image.png 就可以了 猜测是因为和vue自己提供的组件名称一致了,重名问题导致的,具体…...