Linux的can口编程

1.先启动can

1.在linux下先使用ifconfig -a命令

Linux的can口编程_第1张图片
如图显示出来can0和can1。此时can0是打开的,can1是关闭的。

2.使用shell脚本打开你要打开的can口,并设置波特率。
#/bin/sh

ifconfig canX down   #把canX关闭

# set bitrate
/sbin/ip link set canX type can bitrate xxxxxx
#设置canX的波特率位xxxxxx

ifconfig canX up      #把canX打开

canX:代表你要打开的can口(can0或者can1)。
xxxxxx:代表你要给can口设置的波特率(这个波特率和串口的不一样)。

3.在使用ifconfig -a命令查看can口状态

2.在确定canX已经开启后开始编写程序(本次使用can0)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
	int s;
	int ret;
	struct sockaddr_can addr;
	struct ifreq ifr;
	int master = 3;
	int frameId = 0; 

	if(argc >= 2) {
		master = atoi(argv[1]);
	}
	if(argc >= 3)
		frameId = (int)strtol(argv[2], NULL, 0);
		
	if(master < 1)
		master = 1;
		
	srand(time(NULL));
	s = socket(AF_CAN, SOCK_RAW, CAN_RAW);		/* 创建套接字	*/
	//can编程在linux里是和网络编程一样的,PF_CAN是can的代号,可见下图
	
	if (s < 0) {
        perror("socket PF_CAN failed");
        return 1;
	}

	/* 把套接字绑定到can0接口	*/
	/* 如需要使用can1,将"can0"替换为"can1"*/
	strcpy(ifr.ifr_name, "can0");
	ret = ioctl(s, SIOCGIFINDEX, &ifr);				
	if (ret < 0) {
        perror("ioctl failed");
        return 1;
	}
	
	addr.can_family = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;

	ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));	
	if (ret < 0) {
        perror("bind failed");
        return 1;
	}
	
	/* 设置过滤规则,可要可不要 */
     {
		struct can_filter filter[2];
		/* 第1个规则是可以接收ID为0x200 & 0xFFF的数据帧 */
        filter[0].can_id = 0x200 | CAN_EFF_FLAG;
		filter[0].can_mask = 0xFFF;
	    /* 第2个规则是可以接收ID为0x20F& 0xFFF的数据帧 */
		filter[1].can_id = 0x20F | CAN_EFF_FLAG;
		filter[1].can_mask = 0xFFF;

		/* 启用过滤规则,只要CAN0接收到的数据帧满足上面2个规则中的任何一个也被接受*/
		ret = setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter));
		//sizeof(filter)这个参数为零时,代表禁用规则

		if (ret < 0) {
			perror("setsockopt failed");
			return 1;
		}
	}
	
	test_can_rw(s, master, frameId);		/*在这里对can的报文进行收发*/

	close(s);
	return 0;
}
static int test_can_rw(int fd, int master, int frameId)
{
	int ret;
	struct can_frame  frdup;
	struct timeval tv;
	fd_set rset;
	
	
	while (1) 
	{
		tv.tv_sec = 1;
		tv.tv_usec = 0;
		FD_ZERO(&rset);
		FD_SET(fd, &rset);
		
		/* 可以使用select进行can口的多路复用*/
		ret = select(fd+1, &rset, NULL, NULL, NULL);
		if (ret == 0) {
			myerr("select time out");
			return -1;
		}

		/* select调用无错返回时,表示有符合规则的数据帧到达	*/	
		ret = read(fd, &frdup, sizeof(frdup));
		if (ret < sizeof(frdup)) {
			myerr("read failed");
			return -1;
		}
		if (frdup.can_id & CAN_ERR_FLAG) { 	/* 检查数据帧是否错误 */
			handle_err_frame(&frdup);
			myerr("CAN device error");
			continue;
		}
		print_frame(&frdup);                   /* 打印数据帧信息	        */
		ret = write(fd, &frdup, sizeof(frdup));	    /* 把接收到的数据帧发送出去 */
		if (ret < 0) {
			myerr("write failed");
			return -1;
		}
		sleep(1);
	}
	return 0;
}
/*can是高速、实时的通讯协议,可以精确到毫秒进行传输*/
/*这里进行了毫秒级的打印*/
static void print_frame(struct can_frame *fr)
{
	int i;	
    static char timestr[200] ={0};
    struct tm * pTempTm;
    struct timeval time1;
    
    /*打印时间(毫秒级的)*/
    gettimeofday(&time1,NULL);
    pTempTm = localtime(&time1.tv_sec);
    if( NULL != pTempTm )
    {
        snprintf(timestr,199,"%04d-%02d-%02d %02d:%02d:%02d.%03ld",
            pTempTm->tm_year+1900,
            pTempTm->tm_mon+1, 
            pTempTm->tm_mday,
            pTempTm->tm_hour, 
            pTempTm->tm_min, 
            pTempTm->tm_sec,
            time1.tv_usec/1000);
		printf("timestr = %s\n",timestr);
	}
	/*打印接收到的数据*/
	{
		printf("recv: can.id=0x%08x  ", fr->can_id & CAN_EFF_MASK);
		printf("%08x      ", fr->can_id);
		printf("dlc = %d  ", fr->can_dlc);
		printf("data = ");
		for (i = 0; i < fr->can_dlc; i++)
			printf("%02x ", fr->data[i]);
		printf("\n");
	}
}
1.该图为PF_CAN等在linux内的宏定义(可以看一下struct sockaddr_can结构体和address faimly) Linux的can口编程_第2张图片

3.交叉编译后放到板子上进行测试。

你可能感兴趣的:(Linux,嵌入式,linux)