Linux CAN编程详解

2019-07-13 02:30发布

转发自:http://velep.com/archives/1181.html
《Linux CAN编程详解》是一篇百度文库上的文档,主要描述了以下内容:
  1. can总线介绍及其帧类型;
  2. Linux 系统中CAN 接口配置;
  3. Linux 系统中CAN 接口应用程序开发;
  4. Linux 系统中CAN 接口编程实例
总体来说,这篇文档,对于嵌入式linux can应用编程还是有很大的帮助。特别是里面关于“Linux 系统中CAN 接口应用程序开发”的介绍,总结的很全面,讲述的比较清楚。 本人编写的linux socket can程序cantool(一个基于linux socket can机制编写的can接口应用程序),在调试CAN帧发送功能的时候,就有参考过该文档“5. 过滤规则设置”一节内容。 下面是该文档中个人认为比较有价值的内容部分。完整PDF文档下载地址:Linux CAN编程详解 Linux 系统中CAN 接口配置 在 Linux 系统中, CAN 总线接口设备作为网络设备被系统进行统一管理。在控制台下, CAN 总线的配置和以太网的配置使用相同的命令。 在控制台上输入命令:
ifconfig –a 可以得到以下结果: image_thumb.png 在上面的结果中, eth0 设备为以太网接口, can0和can1 设备为两个 CAN 总线接口。接下来使用 ip 命令来配置 CAN 总线的位速率: ip link set can0 type cantq 125 prop-seg 6phase-seg1 7 phase-seg2 2 sjw 1 也可以使用 ip 命令直接设定位速率: ip link set can0 type can bitrate 125000 当设置完成后,可以通过下面的命令查询 can0 设备的参数设置: ip -details link show can0 当设置完成后,可以使用下面的命令使能 can0 设备: ifconfig can0 up 使用下面的命令取消 can0 设备使能: ifconfig can0 down 在设备工作中,可以使用下面的命令来查询工作状态: ip -details -statistics link show can0 Linux 系统中CAN 接口应用程序开发 由于系统将 CAN 设备作为网络设备进行管理,因此在 CAN 总线应用开发方面, Linux 提供了SocketCAN 接口,使得 CAN 总线通信近似于和以太网的通信,应用程序开发接口 更加通用, 也更加灵活。 此外,通过 https://gitorious.org/linux-can/can-utils 网站发布的基于 SocketCAN 的 can-utils 工具套件, 也可以实现简易的 CAN 总线通信。 下面具体介绍使用 SocketCAN 实现通信时使用的应用程序开发接口。 (1). 初始化 SocketCAN 中大部分的数据结构和函数在头文件 linux/can.h 中进行了定义。 CAN 总线套接字的创建采用标准的网络套接字操作来完成。网络套接字在头文件 sys/socket.h 中定义。 套接字的初始化方法如下: 1 int s; 2 struct sockaddr_can addr; 3 struct ifreq ifr; 4 s = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建 SocketCAN 套接字 5 strcpy(ifr.ifr_name, "can0" ); 6 ioctl(s, SIOCGIFINDEX, &ifr);//指定 can0 设备 7 addr.can_family = AF_CAN; 8 addr.can_ifindex = ifr.ifr_ifindex; 9 bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与 can0 绑定 (2). 数据发送 在数据收发的内容方面, CAN 总线与标准套接字通信稍有不同,每一次通信都采用 can_ frame 结构体将数据封装成帧。 结构体定义如下: 1 struct can_frame { 2 canid_t can_id;//CAN 标识符 3 __u8 can_dlc;//数据场的长度 4 __u8 data[8];//数据 5 }; can_id 为帧的标识符, 如果发出的是标准帧, 就使用 can_id 的低 11 位; 如果为扩展帧, 就使用 0~ 28 位。 can_id 的第 29、 30、 31 位是帧的标志位,用来定义帧的类型,定义如下: 1 #define CAN_EFF_FLAG 0x80000000U //扩展帧的标识 2 #define CAN_RTR_FLAG 0x40000000U //远程帧的标识 3 #define CAN_ERR_FLAG 0x20000000U //错误帧的标识,用于错误检查 数据发送使用 write 函数来实现。 如果发送的数据帧(标识符为 0x123)包含单个字节(0xAB)的数据,可采用如下方法进行发送: 1 struct can_frame frame; 2 frame.can_id = 0x123;//如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 0x123; 3 frame.can_dlc = 1; //数据长度为 1 4 frame.data[0] = 0xAB; //数据内容为 0xAB 5 int nbytes = write(s, &frame, sizeof(frame)); //发送数据 6 if(nbytes != sizeof(frame)) //如果 nbytes 不等于帧长度,就说明发送失败 7 printf("Error !"); 如果要发送远程帧(标识符为 0x123),可采用如下方法进行发送: 1 struct can_frame frame; 2 frame.can_id = CAN_RTR_FLAG | 0x123; 3 write(s, &frame, sizeof(frame)); (3). 数据接收 数据接收使用 read 函数来完成,实现如下: 1 struct can_frame frame; 2 int nbytes = read(s, &frame, sizeof(frame)); 当然, 套接字数据收发时常用的 send、 sendto、 sendmsg 以及对应的 recv 函数也都可以用于 CAN总线数据的收发。 (4). 错误处理 当帧接收后,可以通过判断 can_id 中的 CAN_ERR_FLAG 位来判断接收的帧是否为错误帧。 如果为错误帧,可以通过 can_id 的其他符号位来判断错误的具体原因。 错误帧的符号位在头文件 linux/can/error.h 中定义。 (5).