2024年linux can编程详解

linux can编程详解前言 本文简要总结本人近两周从 0 开始接触 linux can 通信了解到的相关知识 使用的 CAN 设备为 ARS408 毫米波雷达 带有个人理解 辩证看待 虚心学习 欢迎指教 linux can 命令 雷达接在工控机的 can0 端口 接好后可以通过 linux 命令设置波特率接收到 CAN 报文 ifconfig

前言

本文简要总结本人近两周从0开始接触linux can 通信了解到的相关知识,使用的CAN设备为ARS408毫米波雷达,带有个人理解,辩证看待,虚心学习,欢迎指教。

linux can命令

雷达接在工控机的can0端口,接好后可以通过linux命令设置波特率接收到CAN报文

ifconfig # 产看can口,PC不带CAN口是没有的 # 1. 设置波特率 sudo ip link set can0 down # 不使能,再设置波特率,否则会出现设备忙 sudo ip link set can0 type can bitrate  # 波特率500kb/s ip -details link show can0 # 打印can0详细,查看修改 # 2. 查看接收的CAN帧 sudo ip link set can0 up # 使能 candump can0 # 接收can0发送的帧 

CAN报文示例如下

can0 60A [4] 01 88 4F 10 can0 60B [8] 00 4E 83 FD 80 20 01 92 

CAN 基础知识

消息ID类似MAC地址作用,用作总线仲裁 cam_frame.can_id 32bit 标识符(消息ID)29bit 29-31:1错误帧(0数据帧) 1远程帧 帧格式标志位(1扩展帧0标准帧) 标准帧11位扩展帧29位 

CAN 编码相关

8x8矩阵 64bit 当前雷达CAN协议的字节序是大端编码,比特顺序是逆序 发送顺序矩阵从上到下,can_frame.data[0]是数据低位,data[0-7]即矩阵的0-7行 1. 字节序: 【小端 低位数据放低地址】"小弟弟" 数据线位数决定着数据会按32/64bit方式分段传输,假设按字节(byte)编址,那么32bit即4字节数据有高低位,4个地址有高低位,如何存放 字节序就是两种排列方案,大端即高位数据放低地址,小端即低位数据放低地址 一块4G内存(32bit地址线),现有数据0x的地址0x0000 0010,其最高址0xffff ffff,最低址0x0000 0000 小端为 0x0010放0x78 0x0011放0x56 ... 大端编码即motorola格式,小端编码即intel格式 反映在CAN的跨字节传输中为,当数据长度当前字节已经放不下了(数据是可能小于8bit的),需要跨字节存放,如0xf2,假设当前只能放6位 intel格式即数据的高位放在高字节(下一字节)的高位,数据的低位放当前字节低位,起始位(第一位)在当前字节,数据会切成11 ,val = 11<<6 +  motorola格式即数据的高位放在当前字节的高位,数据的低位放高字节低位,起始位在下一字节,数据会切成0x 10,val = <<2 + 10 其中所谓字节的高低位其实就是矩阵从上到下从左到右1-64的编号(即比特顺序正序),所以motorola格式数据排列反映在矩阵中就是往左上角挤 2. 比特顺序: 矩阵编号的顺序 正序从左上到右下1-64,逆序从右上到左下1-64 

在这里插入图片描述

CAN 编程

  • 建议在实际编程中将传感器厂商的协议 “翻译” 成结构体定义,这样对收到的数据memcpy进结构体即可,而不再需要对数据与或移位,这里给出参考 ARS408Protocol.h
  • 注: 此做法未在网上找到他人参考,未细究是否合理,对于小端序结构体按协议字段从上往下定义,代码自然简洁;但对大端序,这里逆着协议文档的字段定义,字节内的顺序收到后也要进行逆序再memcpy会显得比较麻烦
  • 存在即合理,大端序符合人类阅读习惯,小端序处理高效

参考

  • 《linux can 编程详解》 | 《socket can 中文文档》 | can编码 | 大端小端
  • 理解字节序


2020-07-12

  • 《linux can 编程详解》中示例代码的奇怪错误与过滤器的设置

// 设置过滤规则过滤can_id,一个int-32bit表示一条规则,可以用int数组设置多条 // 匹配规则为 (received_can_id & mask) == (can_id & mask) // 如标准帧的mask宏#define CAN_SFF_MASK 0x0000 07FF 即 只保留can_id的后11位 /* struct can_filter rfilter[2]; */ /* rfilter[0].can_id = 0x60A; */ /* rfilter[0].can_mask = 0x7FF; // !!这里不能用CAN_SFF_MASK宏,它与内核冲突,内核中也定义了这个宏,值不是这里期待的值 */ /* rfilter[1].can_id = 0x60B; */ /* rfilter[1].can_mask = 0x7FF; */ /* setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); */ 

2020-07-22

  • 使用虚拟CAN模拟雷达发送数据

sudo modprobe vcan # 每次重启都需要设置,可以设置个alias sudo ip link add dev vcan0 type vcan sudo ip link set dev vcan0 up # 不需要设置波特率 ifconfig # 能查看到van0设备 # 发送报文 格式 消息ID#data[0].data[1]..... 需要连着发送 cansend vcan0 60A#02.88.4f.10 ; cansend vcan0 60B#00.4e.83.fd.80.20.01.92; cansend vcan0 60B#00.4e.83.fd.80.20.01.92 # 接收 candump vcan0 

  • 模拟本雷达发送的示例代码
知秋君
上一篇 2024-11-11 14:02
下一篇 2024-11-06 22:55

相关推荐