Linux下的CAN通讯

news2024/11/24 18:33:04

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的硬件连接

1726464274793

一般没有can控制器的设备,可以靠使用SPI转CAN模块,再外接CAN收发器,实现can的数据收发

1726464704534

CAN总线两端的120欧姆为终端电阻,是为了消除总线上的信号反射

电器属性

1726464469095

在高速 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标准数据帧格式

1726465394762

标准数据帧格式分析:

1726465435459

can的空闲电平是1(高电平,隐性),所以起始帧是0(低电平,显性)

  1. 帧起始和帧结束
    帧起始和帧结束表示一帧数据的起始和结束,帧起始由 1 个显性位组成,结束由 7 个连续
    的隐形位组成。
  2. 仲裁字段
    仲裁字段包括 11位ID 位,1位 RTR 位,共 12 位。D 位用可以用来区分数据的功能(不
    司功能的报数据帧,ID 是不同的),也可以用来区分优先级。根据仲裁规则,ID 小的数据帧
    优先发送。禁止高 7 位都为隐性(禁止设定: ID=1111111xXXX)。
    RTR 是远程请求标志位,用于区分数据帧还是遥控帧。数据帧 RTR 位必须为显性 0,遥控
    必须位隐性 1。(相同ID的数据和遥控,数据的优先级大干遥控帧)。
  3. 控制字段
    控制字段由 1位IDE 位,1位 RO 保留位,4 位 DLC共6 位组成。
  • IDE 位表示数据帧是标准数据帧还是扩展数组帧,标准格式固定为显示0,扩展格式固定为
    隐性 1。
  • RO 保留位,固定为显示 0。
  • DLC 位表示数据字段的数据字节数(数据段的长度)。
  1. 数据字段
    可以承载 0 到 64 位数据。
  2. CRC 校验字段
    CRC 校验字段由 15 位校验位和 1位 CRC 界定字符组成,前 15 位用于 CRC 校验。CRC 界定符
    必须为隐性 1
  3. ACK 字段
    ACK 字段由确定间隙位和确认界定符组成,确认界定符必须是隐性 1。

1.3.2扩展数据帧格式

1726486254683

相比于标准帧格式,扩展帧多了一个扩展ID,扩展ID由29位组成,标准帧的ID由11位组成
SRR替换了原有的RTR,IDE为扩展帧的标识符(低电平0),外加了18为扩展ID,其他的并无异样

2.遥控帧

遥控帧用于接收设备主动请求数据。发送方通过广播的形式发送数据,数据帧中通过ID 区分不同功能的数据帧,如果发送方没有广播这个数据,接收方可以广播发送一个遥控帧,有接收方想要的数据的发送方就会广播这个数据出来。接收方就可以接收到这个数据了。

1726486647771

2.1 遥控帧格式

数据帧去掉数据段就是遥控帧,所以遥控帧也有两种帧格式

1726486841125

3.错误帧

在发送或者接收时,总线上的设备发生错误的时候,可以通过发送错误帧的方式告知其他节点发生了错误。错误帧由俩个部分组成,分别是错误标志和错误界定符。错误标志:

  • 主动错误标志:6 个连续显性位
  • 被动错误标志:6 个连续隐性位
    错误界定符:8 个连续隐性位

1726487041603

4.过载帧

当某个接收节点没有做好接收下一帧数据的准备时,接收方将发送过载帧通知发送节点节点最多可产生俩条连续的过载顺来延迟一下次发送。过载标志的构成与主动错误标志的构成相同,过载界定符的构成与错误界定符的构成相同。

  • 过载标志:6个位的显行
  • 过载界定符:8个位的隐行

1726487097242

5.帧间隔

帧间隔是用于分隔数据帧和遥控帧的帧。数据帧和遥控帧可通过插入帧间隔将本帧与前面的任何帧(数据帧、遥控帧、错误帧、过载帧) 分开。
过载帧和错误帧前不能插入帧间隔。

1726487216832

6.位填充

CAN 总线上的数据是按照位来传输的,为了保证数据传输的可靠性,CAN 总线对数据进行了位填充。位填充是指在数据传输过程中,如果连续 5 个位都是显性位,那么就会插入一个隐形位。如果连续 5 个位都是隐形位,那么就会插入一个显性位。

1726487436502

仲裁机制

CAN 总线是一种多主从式总线,多个节点可以同时发送数据。为了防止多个节点同时发送数据导致冲突,CAN 总线采用了仲裁机制。仲裁机制是通过比较各个节点的 ID 来决定哪个节点可以发送数据。ID 小的节点优先发送数据。如果多个节点同时发送数据,那么 ID 小的节点会优先发送数据,其他节点会停止发送数据并进入监听状态,等待 ID 小的节点发送完数据后再发送数据。

在总线空闲态,最先开始发送消息的单元获得发送权。多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送。
主要通过以下方法:

  1. 非破坏性仲裁:显性优先,即显性优先级大于隐性优先级(线与机制: 只有所有节点都发送隐性 1 时,总线才为 1,只要有一个节点发送显性 0,则总线就为显性 0)
  2. 载波侦听: 总线上各个节点在发送数据前要侦听总线的状态,只有在总线是空闲状态时才允许发送。
  3. 回读:节点在发送数据时要不停的检测要发送的数据。通过非破坏性仲裁判断是否与其他节点的数据发生冲突。

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的应用编程

1726560568299

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 socket
    if(s < 0){
        printf("Error creating socket\n");
        return 1;
    }

    struct ifreq ifr; // Interface request
    strcpy(ifr.ifr_name, "can0"); // CAN interface name
    if(ioctl(s, SIOCGIFINDEX, &ifr) < 0){ // Get CAN interface index
        printf("Error getting interface index\n");
    }

    struct sockaddr_can addr; // CAN socket address
    addr.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 ID
    frame[0].can_dlc = 8; // Data length code
    for(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 code
    frame[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 code
    if(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 socket
    if(s < 0){
        printf("Error creating socket\n");
        return 1;
    }

    struct ifreq ifr; // Interface request
    strcpy(ifr.ifr_name, "can0"); // CAN interface name
    if(ioctl(s, SIOCGIFINDEX, &ifr) < 0){ // Get CAN interface index
        printf("Error getting interface index\n");
    }

    struct sockaddr_can addr; // CAN socket address
    addr.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 frame

    char buff[1024];

    struct can_filter filter[2]; // CAN filter 设置两条过滤规则


    // 设置过滤规则,只接收ID为0x123的标准帧
    filter[0].can_id = 0x123; // Filter ID
    filter[0].can_mask = CAN_SFF_MASK; // Filter mask

    // 设置过滤规则,只接收ID为0x456的扩展帧和标准帧,但不要远程帧
    filter[1].can_id = 0x123; // Filter ID
    filter[1].can_mask = CAN_SFF_MASK | CAN_EFF_MASK | CAN_RTR_FLAG; // Filter mask

    setsockopt(s,SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)); // 设置过滤规则

    while (1)
    {
        int ret = read(s, &frame, sizeof(frame)); // Read CAN frame
        if(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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2142736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA基础面试题总结(十五)——设计模式

面试专题-设计模式 前言 在平时的开发中&#xff0c;涉及到设计模式的有两块内容&#xff0c;第一个是我们平时使用的框架&#xff08;比如spring、mybatis等&#xff09;&#xff0c;第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#…

面向对象程序设计(C++)———多态

1.认识多态 多态(polymorphism)的概念&#xff1a;通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)&#xff0c;这⾥我们重点讲运⾏时多态&#xff0c;编译时多态(静态多态)和运⾏时多态(动态多态)。编译时 多态(静态多态)主要就是我们…

一分钟掌握 Excel VBA 技巧,轻松批量生成工资条,提高工作效率!

可能大家忽视了一点&#xff0c;Excel是我们日常办公中使用最多的工具&#xff0c;所以&#xff0c;学好Excel并加以运用&#xff0c;一定能提升你的工作效率&#xff0c;比如Excel VBA可以用代码实现自动化办公&#xff0c;下面举一个Excel VBA批量生成工资条的办公小案例。 …

swagger新玩法 - 让你API接口开发原地起飞

作为Java后台接口开发人员&#xff0c;无论对对接方是前端还是第三方&#xff0c;很多时候我们在文档和代码两头都需要费心&#xff0c;而做到自动的同步将会非常省心。本教程将带你领略下如何借助swagger官方提供的新玩法&#xff0c;让你的API接口开发原地起飞&#xff0c;甚…

34.贪心算法1

0.贪心算法 1.柠檬水找零&#xff08;easy&#xff09; . - 力扣&#xff08;LeetCode&#xff09; 题目解析 算法原理 代码 class Solution {public boolean lemonadeChange(int[] bills) {int five 0, ten 0;for (int x : bills) {if (x 5) // 5 元&#xff1a;直接收下…

4. Python之运算符

一. Python运算符 常用的运算符有&#xff1a;算述运算符&#xff0c;赋值运算符&#xff0c;比较运算述&#xff0c;逻辑运算符&#xff0c;位运算符等等。 1. 算述运算符 用于处理四则运算的符号&#xff0c;主要有&#xff1a; 运算符描述加法-减法*乘法/除法//整除%取余…

嵌入式DCMI摄像头功能调试方法

STM32F407芯片带有DCMI接口,在我们的核心板上已经将接口用18PIN的FPC座子引出。 这个接口可以接我们的OV2640接口。 本节我们开始调试摄像头。 16.1. DCMI DCMI接口是ST自己定义的接口。 Digital camera interface (DCMI),是意法半导体公司产品STM32F4xx系列芯片的快速摄像头…

【JavaEE初阶】多线程(5 单例模式 \ 阻塞队列)

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 实例1: 单例模式 饿汉模式 懒汉模式 实例2:阻塞队列 生产者消费者模型 优点 ​编辑 代价 简单实现一个生产者消费者模型 Java标准库中的阻塞队列 ​编辑 模拟实现一…

面试官问:你如何看待加班?

面试官问&#xff1a;你如何看待加班&#xff1f; 面试官问&#xff1a;你如何看待加班&#xff1f;这类问题是比较常见的&#xff0c;出现频率相当高。有些同学看到这样的问题&#xff0c;就会断定这家公司估计是经常加班的&#xff0c;绝对的不能去&#xff01;&#xff01;…

通信工程学习:什么是PON无缘光纤网络

PON&#xff1a;无源光纤网络 PON&#xff08;Passive Optical Network&#xff0c;无源光纤网络&#xff09;是一种采用光分路器等无源光器件进行信号传输和分配的光纤接入技术。它利用光纤作为传输媒介&#xff0c;通过无源设备将光信号从中心局&#xff08;如光线路终端OLT&…

中秋节特别游戏:给玉兔投喂月饼

&#x1f5bc;️ 效果展示 &#x1f4dc; 游戏背景 在中秋这个充满诗意的节日里&#xff0c;玉兔因为贪玩被赶下人间。在这个温柔的夜晚&#xff0c;我们希望通过一个小游戏&#xff0c;让玉兔感受到人间的温暖和关怀。&#x1f430;&#x1f319; &#x1f3ae; 游戏设计 人…

太阳能光伏板航拍红外图像缺陷分类数据集

太阳能光伏板航拍红外图像缺陷分类数据集 一、数据集简介 太阳能光伏板的性能直接影响到光伏发电系统的效率和可靠性。随着无人机和红外成像技术的发展&#xff0c;通过航拍红外图像对光伏板进行缺陷检测已成为一种高效且准确的方法。本数据集包含11种不同的缺陷分类&#xf…

【CPP】模板(后篇)

目录 13.1 非类型模板参数13.2 函数模板的特化13.3 类模板的特化13.4 模板的分离编译 这里是oldking呐呐,感谢阅读口牙!先赞后看,养成习惯! 个人主页:oldking呐呐 专栏主页:深入CPP语法口牙 13.1 非类型模板参数 顾名思义,非类型模板参数就是一个模板的参数,只不过不是类型,而…

第二十六篇——九地篇:九种形势的应对之道

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 地势的维度重新阐述了懂得人心的重要性&#xff0c;道久其归一为为别人。…

个人随想-gpt-o1大模型中推理链的一个落地实现

​首先祝大家中秋节快乐。 最近openai又推出了新的模型openai o1​还有它的mini版。官网的介绍&#xff0c;就是它的推理能力很强&#xff0c;比gpt-4o​有很大的提升。 最近也跟同行在聊这个o1&#xff0c;​看看落地方面有哪些可行性。在我们自己的实验上&#xff0c;把o1用…

Python画笔案例-052 绘制彩色递归六边形

1、绘制彩色递归六边形 通过 python 的turtle 库绘制 彩色递归六边形&#xff0c;如下图&#xff1a; 2、实现代码 绘制彩色递归六边形&#xff0c;以下为实现代码&#xff1a; """彩色递归六边形.py """ import turtledef draw_circle(radius,…

【自动化测试】移动app的分层测试以及自动遍历的基本概念

引言 移动应用的分层测试是一种系统化的测试方法&#xff0c;它将测试过程分解为不同的层次&#xff0c;以确保应用在每个层面上都符合设计要求和用户期望 文章目录 引言一、移动app的分层测试1.1 单元测试&#xff08;Unit Testing&#xff09;1.2 集成测试&#xff08;Integr…

甲骨文创始人埃里森:人工智能终有一天会追踪你的一举一动

9月17日消息&#xff0c;据外电报道&#xff0c;甲骨文创始人拉里埃里森在甲骨文财务分析师会议上表示&#xff0c;他预计人工智能有一天将为大规模执法监控网络提供动力。“我们将进行监督。”他说。“每一位警察都将随时受到监督&#xff0c;如果有问题&#xff0c;人工智能会…

人工智能辅助汽车造型设计

随着科技的不断进步&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域的应用越来越广泛&#xff0c;汽车设计行业也不例外。尤其在车辆外观造型设计中&#xff0c;AI正在成为设计师的重要助手&#xff0c;通过提供强大的工具和独特的创意方式&#xff0c;革新了传统设…

算法之搜索--最长公共子序列LCS

最长公共子序列&#xff08;longest common sequence&#xff09;:可以不连续 最长公共子串&#xff08;longest common substring&#xff09;&#xff1a;连续 demo for (int i 1;i<lena;i){for (int j 1;j<lenb;j){if(a[i-1]b[j-1]){dp[i][j]dp[i-1][j-1]1;}el…