Linux应用程序--CAN总线
文章摘要:本文描述了关于CAN总线应用程序的编程。
内核版本:linux-3.8.13
硬件平台:AM335x
内核配置: 添加CAN驱动程序及协议
[*] Networking support --->
<*> CAN bus subsystem support --->
<*> Raw CAN Protocol (raw access with CAN-ID filtering)
<*> Broadcast Manager CAN Protocol (with content filtering)
CAN Device Drivers --->
<*> Bosch D_CAN devices --->
<*> Generic Platform Bus based D_CAN driver
AM335x CAN控制器驱动程序位于:drivers/net/can/c_can目录下
c_can_platform.c
c_can.c
开机自动配置: /etc/network/interface
auto can0
iface can0 inet manual
pre-up /ip link set $IFACE type can bitrate 125000 triple-sampling on
up /sbin/ifconfig $IFACE up
down /sbin/ifconfig $IFACE down
查看可用列表: 查看/sys/class/net/目录
$ ls /sys/class/net/can*
设置波特率:
# echo 500000 > /sys/class/net/can%d/can_bittiming/bitrate
系统设置:命令及说明:
配置CAN总线参数
# ip link set can0 type can bitrate 500000 triple-sampling on
或者
# canconfig can0 bitrate 500000 ctrlmode triple-sampling on
bitrate参数用于设置波特率,此处设置为500K bps.
loopback on/off - 使能/禁止回环(除了测试,一般都关闭回环功能)
使能CAN总线接口
# ip link set can0 up
或者
# canconfig can0 start
此命令完成后,可通过ifconfig查看到相关接口。
关闭CAN总线接口
# ip link set can0 down
或者
# canconfig can0 stop
查询当前工作状态:
# ip -details -statistics link show can0
发送测试:
# cansend can0 7ff#112233
接收测试:
# candump can0
C语言示例代码:
#include <stdio.h>
#include <string.h>
#include <linux/can.h>
#include <linux/sockios.h>
#include <net/if.h>
/*
* 初始化CAN控制器
*/
int can_open(char* name)
{
int fd;
struct ifreq can_ifr;
struct sockaddr_can can_addr;
// int flag = 1;
// 初始化socket套接字用于CAN设备
fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(can_ifr.ifr_name, name);
ioctl(fd, SIOCGIFINDEX, &can_ifr); // 指定can设备
can_addr.can_family = AF_CAN; // 指定协议族
can_addr.can_ifindex = can_ifr.ifr_ifindex;
bind(fd, (struct sockaddr *)&can_addr, sizeof(can_addr)); // 绑定
//ioctl(fd, FIONBIO, &flag); //设置为非阻塞模式
return fd;
}
/*
* 向CAN总线发送数据
*/
int can_send(int can, int id, unsigned char* buff)
{
int ret;
struct can_frame can_frm = {0};
can_frm.can_id = id;
// 如果为扩展帧则为: can_frm.can_id = CAN_EFF_FLAG | id;
can_frm.can_dlc = 8;
memcpy(can_frm.data, buff, 8);
ret = write(can, &can_frm, sizeof(can_frm));
if(ret != sizeof(can_frm))
{
printf("can send error: id = %X\r\n", id);
}
return 0;
}
/*
* 向CAN总线读取数据
*/
int can_recv(int can, struct can_frame* pcf)
{
int rxlen;
// 正常情况下返回值为16(struct can_frame的长度)
rxlen = read(can, pcf, sizeof(struct can_frame));
if(rxlen != sizeof(struct can_frame))
{
return -1; // 读取失败
}
return 0;
}
发送远程帧:
struct can_frame frame;
frame.can_id = CAN_RTR_FLAG | id;
write(s, &frame, sizeof(frame));
设置过滤规则: 可以设置多条
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));//设置规则
// 过滤所有报文(只发不接)
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));
错误处理:
通过can_id 中的 CAN_ERR_FLAG 位来判断接收的帧是否为错误帧。
如果为错误帧,可以通过 can_id 的其他符号位来判断错误的具体原因。
关闭/开启回环功能:
// 0 表示关闭, 1 表示开启( 默认)
int loopback = 0;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
http://emb.hqyj.com/Column/Column596.htm
https://public.pengutronix.de/software/libsocketcan/
http://www.pengutronix.de/software/socket-can/download/canutils
http://www.kernel.org/pub/linux/utils/net/iproute2/