本文博客深度参考了前辈的作品:
TX2/Linux下can总线的接收与发送详解!
https://blog.csdn.net/hhlenergystory/article/details/81976069
Linux CAN 编程详解
https://blog.csdn.net/ppdyhappy/article/details/79458458
使用CAN本人归纳为6个步骤:
0.测试之前最好先下载安装好测试工具can-utils
sudo apt-get install can-utils
1.加载can设备驱动:
sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan
2.设置波特率(注意这里不能使能can或者打开can)
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 berr-reporting on fd on
sudo ip link set can1 type can bitrate 500000 dbitrate 2000000 berr-reporting on fd on
如果出现了RTNETLINK answers: Device or resource busy 这种情况,则需要使用命令
sudo ip link set down can0
sudo ip link set down can1
来关闭掉;
3.设置为回环模式(因为要测试使用,在不外接can驱动和120欧姆电阻的情况下是可以回环测试的,使用can0设备)
sudo ip link set can0 type can loopback on
如果由外设,可以省略此步骤。
4.开启can设备:
sudo ip link set up can0
sudo ip link set up can1
5.发送和接收:
发送:
cansend can0 123#abcdabcd
cansend是命令,can0是参数,123是ID,#分隔符,abcdabcd是发送数据。
接收:接收需要另外开一个终端
candump can0
candump 是命令,can0是参数,表示哪个设备,这个命令是阻塞型的,会一直等待接收。
6.关闭can设备。
sudo ip link set down can0
sudo ip link set down can1
上面的测试,本人是在tx2上面一会儿就跑通了。但是不满足控制出身的技术人员对于控制的需要,所以需要自己写一个程序来实现接收和发送。使用了实例程序:
两个c文件:1.can_send.c
#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);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s,(struct sockaddr*)&addr,sizeof(addr));
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[1].can_id = 0x11;//0x33;
frame[1].can_dlc =1;
frame[1].data[0]= 'N';
while(1)
{
nbytes = write(s, &frame[0], sizeof(frame[0]));
printf("nbytes=%d\n",nbytes);
if(nbytes != sizeof(frame[0]))
{
printf("Send Error frame[0]\n!");
break; //发送错误,退出
}
sleep(1);
nbytes = write(s, &frame[1], sizeof(frame[1]));
if(nbytes != sizeof(frame[1]))
{
printf("Send Error frame[1]\n!");
break;
}
sleep(1);
}
close(s);
return 0;
}
2.can_receive.c
#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]);
//printf(“ID=0x%X DLC=%d data[0]=0x%X\n”, frame.can_id, frame.can_dlc, frame.data[0]);
}
}
close(s);
return 0;
}
实测也是可以实现发送与接收的。
与其他设备的通信,TX2与window7进行can通信,TX2外接了can转换芯片,window使用usb转can设备进行直连(可以直连,在usb转can里已经包含了120欧姆的电阻,看到这里,就不用担心没有匹配电阻的问题咯),打开can设备之后,使用程序进行收发,测试了一下午,没有毛病。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)