Arm Linux Can

news2025/1/20 20:11:10

Arm Linux Can

  • 一:can-utils 安装
  • 二:can-utils 使用
    • can网络关闭
    • can波特率设置
    • 查询can0设备的参数设置
    • can网络开启
    • 查询工作状态
    • can发送数据
    • can接受数据
  • 三:can回环测试
  • 四:C语言CAN编程
    • 初始化
    • 数据结构
    • 数据发送
    • 错误处理
    • 过滤规则
    • 回环设置
  • 五:Linux 系统中CAN 接口应用程序示例
    • 报文发送程序
    • 报文过滤接收程序

一:can-utils 安装

在这里插入图片描述
生产如下工具:
在这里插入图片描述

二:can-utils 使用

ip link set can0 down
ip link set can0 type can bitrate 250000 loopback off//设置波特率,关闭回环测试
ip link set can0 up

说明:

  1. loopback off:关闭回环模式。测试发现关闭后,可以实现CAN设备与外界的收发通信。
  2. loopback on:打开回环模式。测试发现打开后,可以实现自发自收,不依赖外部CAN设备。

can网络关闭

ip link set can0 down

can波特率设置

ip link set can0 type can bitrate 500000 loopback off

查询can0设备的参数设置

ip -details link show can0

can网络开启

ip link set can0 up

查询工作状态

ip -details -statistics link show can0

can发送数据

数据发送格式:
cansend can0 XXX#11223344
eg:
cansend can0 12345678#112233
XXX:表示标识符ID,ID越小优先级越高CAN数据冲突时,优先发送。
112233344:表示发送的数据,以16进制表示。最小发送数据单位是字节,可发0~8个字节。

can接受数据

candump can0 或 candump can0 &

三:can回环测试

ip link set down can0
ip link set can0 type can loopback on
ip link set up can0
candump can0 -L &
cansend can0 123#1122334455667788
ip -details link show can0

四:C语言CAN编程

由于系统将 CAN 设备作为网络设备进行管理,因此在 CAN 总线应用开发方面, Linux 提供了SocketCAN 接口,使得 CAN 总线通信近似于和以太网的通信,应用程序开发接口更加通用,也更加灵活。

初始化

SocketCAN 中大部分的数据结构和函数在头文件 linux/can.h 中进行了定义。 CAN 总线套接字的创建采用标准的网络套接字操作来完成。网络套接字在头文件 sys/socket.h 中定义。 套接字的初始化方法如下:

int init(char *drvcan_name)
{
    int ret;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_filter rfilter[1];
    int fd;
    char can_down_cmd[64] = "";
    char can_init_cmd[64] = "";
    char can_up_cmd[64] = "";

    if (drvcan_name == NULL)
    {
        printf("drvcan_name is null");
        return -1;
    }

    sprintf(can_down_cmd, CAN_DOWN, drvcan_name);
    sprintf(can_init_cmd, CAN_INIT, drvcan_name);
    sprintf(can_up_cmd, CAN_UP, drvcan_name);

    system(can_down_cmd);
    system(can_init_cmd);
    system(can_up_cmd);

    fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (fd < 0)
    {
        printf("socket error\n");
        return -2;
    }

    sprintf(ifr.ifr_name, "%s", drvcan_name);
    ret = ioctl(fd, SIOCGIFINDEX, &ifr);
    if (ret < 0)
    {
        printf("ioctl error ret:%d", ret);
        return -3;
    }

    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    bind(fd, (struct sockaddr *)&addr, sizeof(addr));

    /*设置过滤规则*/
    // rfilter[0].can_id = 0x2;
    // rfilter[0].can_mask = 0;
    // Setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
    // setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, NULL);

    /*启动接收线程*/
    thread_exit_state = EM_THREAD_STATE_RUN;
    pthread_t _threadID;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&_threadID, &attr, can_recv_thread, fd);
    pthread_attr_destroy(&attr);
    return fd;
}

数据结构

在数据收发的内容方面,CAN 总线与标准套接字通信稍有不同,每一次通信都采用 can_frame 结构体将数据封装成帧。 结构体定义

/**
 * struct can_frame - basic CAN frame structure
 * @can_id:  CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
 * @can_dlc: frame payload length in byte (0 .. 8) aka data length code
 *           N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
 *           mapping of the 'data length code' to the real payload length
 * @__pad:   padding
 * @__res0:  reserved / padding
 * @__res1:  reserved / padding
 * @data:    CAN frame payload (up to 8 byte)
 */
struct can_frame {
	canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
	__u8    can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
	__u8    __pad;   /* padding */
	__u8    __res0;  /* reserved / padding */
	__u8    __res1;  /* reserved / padding */
	__u8    data[CAN_MAX_DLEN] __attribute__((aligned(8)));
};

can_id 为帧的标识符,如果发出的是标准帧,就使用 can_id的低11位。如果为扩展帧,就使用 0~ 28 位。can_id 的第 29、 30、 31 位是帧的标志位,用来定义帧的类型,定义如下:

/* 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 */

数据发送

struct can_frame frame;
frame.can_id = 0x123;//如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 0x123;
frame.can_dlc = 1; //数据长度为 1
frame.data[0] = 0xAB; //数据内容为 0xAB
int nbytes = write(s, &frame, sizeof(frame)); //发送数据
if(nbytes != sizeof(frame)) //如果 nbytes 不等于帧长度,就说明发送失败
printf("Error\n!");

如果要发送远程帧(标识符为 0x123),可采用如下方法进行发送

struct can_frame frame;
frame.can_id = CAN_RTR_FLAG | 0x123;
write(s, &frame, sizeof(frame));

当然, 套接字数据收发时常用的 send、 sendto、 sendmsg 以及对应的 recv 函数也都可以用于 CAN总线数据的收发

错误处理

当帧接收后,可以通过判断 can_id 中的 CAN_ERR_FLAG 位来判断接收的帧是否为错误帧。 如果为错误帧,可以通过 can_id 的其他符号位来判断错误的具体原因。
错误帧的符号位在头文件 linux/can/error.h 中定义。

过滤规则

在数据接收时,系统可以根据预先设置的过滤规则,实现对报文的过滤。过滤规则使用 can_filter 结构体来实现,定义如下:

/**
 * struct can_filter - CAN ID based filter in can_register().
 * @can_id:   relevant bits of CAN ID which are not masked out.
 * @can_mask: CAN mask (see description)
 *
 * Description:
 * A filter matches, when
 *
 *          <received_can_id> & mask == can_id & mask
 *
 * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
 * filter for error message frames (CAN_ERR_FLAG bit set in mask).
 */
struct can_filter {
	canid_t can_id;
	canid_t can_mask;
};

接收到的数据帧的 can_id & mask == can_id & mask。
通过这条规则可以在系统中过滤掉所有不符合规则的报文,使得应用程序不需要对无关的报文进行处理。

struct can_filter rfilter[2];
rfilter[0].can_id = 0x123;
rfilter[0].can_mask = CAN_SFF_MASK; //#define CAN_SFF_MASK 0x000007FFU
rfilter[1].can_id = 0x200;
rfilter[1].can_mask = 0x700;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));//设置规则

在极端情况下,如果应用程序不需要接收报文,可以禁用过滤规则。这样的话,原始套接字就会忽略所有接收到的报文。在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少 CPU 资源的消耗。禁用方法如下:

setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); //禁用过滤规则

通过错误掩码可以实现对错误帧的过滤, 例如:

can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF );
setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, err_mask, sizeof(err_mask));

回环设置

在默认情况下, 本地回环功能是开启的,可以使用下面的方法关闭回环/开启功能:

int loopback = 0; // 0 表示关闭, 1 表示开启( 默认)
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

在本地回环功能开启的情况下,所有的发送帧都会被回环到与 CAN 总线接口对应的套接字上。 默认情况下,发送 CAN 报文的套接字不想接收自己发送的报文,因此发送套接字上的回环功能是关闭的。可以在需要的时候改变这一默认行为:

int ro = 1; // 0 表示关闭( 默认), 1 表示开启
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &ro, sizeof(ro));

五:Linux 系统中CAN 接口应用程序示例

报文发送程序

#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 s, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame[2] = {{0}};

    s = socket(PF_CAN, SOCK_RAW, CAN_RAW); // 创建套接字
    strcpy(ifr.ifr_name, "can0");
    ioctl(s, SIOCGIFINDEX, &ifr); // 指定 can0 设备
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    bind(s, (struct sockaddr *)&addr, sizeof(addr)); // 将套接字与 can0 绑定

    // 禁用过滤规则,本进程不接收报文,只负责发送
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);

    // 生成两个报文
    frame[0].can_id = 0x11;
    frame[0].can_dlc = 1;
    frame[0].data[0] = 'Y';
    frame[0].can_id = 0x22;
    frame[0].can_dlc = 1;
    frame[0].data[0] = 'N';

    // 循环发送两个报文
    while (1)
    {
        nbytes = write(s, &frame[0], sizeof(frame[0])); // 发送 frame[0]
        if (nbytes != sizeof(frame[0]))
        {
            printf("Send Error frame[0]\n!");
            break; // 发送错误,退出
        }

        sleep(1);

        nbytes = write(s, &frame[1], sizeof(frame[1])); // 发送 frame[1]

        if (nbytes != sizeof(frame[0]))

        {

            printf("Send Error frame[1]\n!");

            break;
        }

        sleep(1);
    }

    close(s);
    return 0;
}

报文过滤接收程序

/* 2. 报文过滤接收程序 */
#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 s, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    struct can_filter rfilter[1];

    s = socket(PF_CAN, SOCK_RAW, CAN_RAW); // 创建套接字
    strcpy(ifr.ifr_name, "can0");
    ioctl(s, SIOCGIFINDEX, &ifr); // 指定 can0 设备

    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    bind(s, (struct sockaddr *)&addr, sizeof(addr)); // 将套接字与 can0 绑定

    // 定义接收规则,只接收表示符等于 0x11 的报文
    rfilter[0].can_id = 0x11;
    rfilter[0].can_mask = CAN_SFF_MASK;

    // 设置过滤规则
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
    while (1)
    {
        nbytes = read(s, &frame, sizeof(frame)); // 接收报文
        // 显示报文
        if (nbytes > 0)
        {
            printf(“ID = 0x % X DLC = % d data[0] = 0x % X\n”, frame.can_id,
                   frame.can_dlc, frame.data[0]);
        }
    }
    close(s);
    return 0;
}

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

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

相关文章

Spring 整合 Redis 的三个简单步骤

一、导入 Redis 依赖 1、导入 Redis 客户端 jar 包依赖 导入 jar 包是需要注意&#xff0c;Redis 是属于 CS 架构模式&#xff0c;服务端需先启动&#xff0c;然后客户端主动去连它。但是客户端怎么去连接服务端呢&#xff1f;这里有两种方式&#xff1a;一种是 Jedis 客户端…

糖果(差分约束+找最小值)

糖果 题目描述 幼儿园里有 n 个小朋友&#xff0c; lxhgww 老师现在想要给这些小朋友们分配糖果&#xff0c;要求每个小朋友都要分到糖果。 但是小朋友们也有嫉妒心&#xff0c;总是会提出一些要求&#xff0c;比如小明不希望小红分到的糖果比他的多&#xff0c;于是在分配糖果…

区块链技术相关概述

第一节区块链技术相关概述一、区块链定义区块链其实就相当于一个去中介化的数据库&#xff0c;是由一串数据块组成的。狭义&#xff1a;区块链是就是一种按照时间顺序来将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c;并以密码学方式保证的不可篡改和不可伪造…

WebDAV之葫芦儿·派盘+MiXplorer

MiXplorer 支持WebDAV方式连接葫芦儿派盘。 手机内存不够用了?东西太多清理不过来?快来试试这款MiXplorer。 MiXplorer是一款非常强大实用的手机文档管理器,能给用户提供了一系列的文档处理功能,包括本地文件浏览、文件排序、文件筛选、切换视图、新建文件、添

SSH免密登录配置

情况 服务器A: 192.168.0.101 服务器B: 192.168.0.102 在服务器A上 可以使用 ssh root192.168.0.102 无需密码登录到192.168.0.102 配置 服务器A: 192.168.0.101 上查看是否有ssh公钥 1.进入.ssh目录&#xff1a; cd ~/.ssh 2.找到id_rsa.pub文件&#xff1a; ls 3.查看公钥…

ucos3+emwin+appwizard控制硬件LED

1.新建appwizard项目2.AppWizard 设计器导出代码&#xff0c;点击 File→Export&Save 3.移植代码到keil其中&#xff0c;Soure 和Resource 中的C文件&#xff0c;添加到项目代码Simulation和Soure 和Resource 中的h文件,添加到编译器的include path。修改Source\Generated下…

Docker容器管理常用

Docker容器管理常用docker容器管理命令创建容器进入容器Attach和exec暂停容器删除容器创建容器并在停止时销毁容器查看容器查看容器的详细信息查看容器执行的完整命令查看容器日志查看已退出容器的日志查看容器指定日期的日志修改容器名指定容器实例的主机名容器特权privileged…

从零开始学习Redis

非关系型数据库简述 关系型数据库(SQL)&#xff1a;Mysql,oracle 特点&#xff1a;数据和数据之间、表和字段之间&#xff0c;表和表之间是存在关系的。 优点&#xff1a;数据之间有关系、进行数据的增删改查时非常方便、关系型数据库有事务操作&#xff0c;保证数据的完整性…

离散数学与组合数学-02二元关系

文章目录离散数学与组合数学-02二元关系上2.1 序偶和笛卡尔积2.1.1 有序组的定义2.1.2 笛卡儿积笛卡儿积的性质2.2 关系的定义2.2.1 二元关系定义与案例2.2.2 二元关系的数学符号定义案例枚举二元关系2.2.3 定义域和值域2.2.4 二元关系概念的推广2.3 关系的表示2.3.1 集合表示法…

Swift(1)

前段时间在忙着考试&#xff0c;今天终于线上考试结束了&#xff0c;最后一场考试被安排到开学。 今天来看一下Swift&#xff1a; 首先&#xff0c;Swift是苹果于2014年WWDC苹果开发者大会发布的新开发语言&#xff0c;可与Objective-C共同运行于macOS和iOS平台&#xff0c;用…

CadSoftTools Web CAD SDK 14.1.0.51184 Crack

Web CAD SDK是一个 ASP.NET 控件&#xff0c;用于在Internet、Intranet、SharePoint、Office 365 和其他支持 HTML5 的在线技术上 查看DWG和其他CAD 文件。该产品不需要安装AutoCAD或其他第三方应用程序或组件&#xff0c;并随 C# 示例一起提供。 格式 CAD 格式&#xff1a; A…

克里金法学习笔记

目录1.Arcmap克里金法的工作原理&#xff1a;2.Kriging From Wikipedia:[https://en.wikipedia.org/wiki/Kriging](https://en.wikipedia.org/wiki/Kriging)3.实例分析4.代码部分5.较好的案例1.Arcmap克里金法的工作原理&#xff1a; https://desktop.arcgis.com/zh-cn/arcmap…

Android so库开发——使用addr2line查看so异常信息(四)

在NDK开发中经常会出现应用Crash的情况&#xff0c;而JNI层的报错信息&#xff0c;不像Java层报错信息那样可以直接在日志中看到错误的行数&#xff0c;JNI层中出现的错误直接看根本定位不到错误的位置。通常来说&#xff0c;JNI报的基本都是堆栈信息&#xff0c;需要NDK的一些…

时序数据库TDengine建模思路

一、时序数据库基本概念 基本属性 1.采集量 采集量是指传感器、设备或其他类型采集点采集的物理量&#xff0c;比如电流、电压、温度、压力、GPS 位置等&#xff0c;是随时间变化的参数 2.标签 标签是指传感器、设备或其他类型采集点的静态属性&#xff0c;不是随时间变化的…

纯 CSS3 卡通小火车行驶动画

自从CSS3流行以来&#xff0c;基于纯CSS3的动画就层出不穷&#xff0c;有纯CSS3的人物动画、纯CSS3按钮动画等。这次&#xff0c;我们给大家分享一个很不错的CSS3卡通火车沿轨道行驶动画&#xff0c;一辆卡通样式的火车缓缓驰过&#xff0c;特别是火车头的动画设计&#xff0c;…

二叉树21:合并二叉树

主要是我自己刷题的一些记录过程。如果有错可以指出哦&#xff0c;大家一起进步。 转载代码随想录 原文链接&#xff1a; 代码随想录 leetcode链接&#xff1a;617. 合并二叉树 题目&#xff1a; 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其…

Vuex状态管理

Vuex&#xff1a;管理组件中共用的一些状态&#xff0c;并能够做一些操作 一、准备工作 安装Vuex ① 默认安装vuex4版本&#xff1a;执行命令 npm install vuex ② 指定安装vuex3版本&#xff1a;执行命令 npm install vuex3 引入Vuex 在src目录下新建名称为store的文件夹&am…

微信小程序wxss相关介绍、全局配置和tabbar知识以及发送数据请求(post,get)

wxss相关介绍 什么是wxss??? wxss (WeiXin Style Sheets)是一套样式语言&#xff0c;用于美化WXML的组件样式&#xff0c;类似于网页开发中的CSS。 WXSS 具有CSS大部分特性&#xff0c;同时&#xff0c;WXSS还对CSS进行了扩充以及修改&#xff0c;以适应微信小程序的开发。 …

数据探索性分析(EDA)——不平衡样本处理

1、何为不平衡样本&#xff1f; 样本不平衡是指分类任务中不同类别的训练样例数目差别很大的情况。在实际的分类任务中&#xff0c;我们经常会遇到类别不平衡&#xff0c;例如广告点击率预测、情感分类、异常检测等。而机器学习算法通常假设不同类别的样本数量大致相似&#x…

【4】k8s_NameSpacePod

目录 一、NameSpace 二、Pod 【1】命令式对象管理: 直接使用命令去操作kubernetes资源 【2】命令式对象配置: 通过命令配置和配置文件去操作作kubernetes资源 1、写一个ymal文件 2、然后运行yaml文件&#xff08;提前创建好了命名空间string&#xff09; 3、用bashboard创…