TX2/Linux下can总线的接收与发送命令和C程序实例

本文博客深度参考了前辈的作品:

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设备之后,使用程序进行收发,测试了一下午,没有毛病。

猜你喜欢

转载自blog.csdn.net/weixin_41579872/article/details/119426097