ARM40-­A5应用程序——CAN总线的发送和接收

ARM40-­A5应用程序——CAN总线的发送和接收

版权声明:本文为博主原创文章,允许转载。
  
  ARM40-A5系列板卡共有2路隔离CAN总线,CAN总线的引脚定义见《ARM40-­A5指南——CAN总线接口与测试》。

一、shell中CAN总线的接收与发送

1.1、硬件接线与配置

  将CAN0的TX与CAN1的TX通过100R电阻连接,CAN0的RX和CAN1的RX通过100R电阻连接(直接相连亦可),然后:

ifconfig can0 down
ip link set can0 type can bitrate 250000        //配置can0的波特率为250kbps
ifconfig can0 up

ifconfig can1 down
ip link set can1 type can bitrate 250000        //配置can0的波特率为250Kbps
ifconfig can1 up

2.2、shell中接收与发送

root@ARM40:~# candump can1 &			                        //将CAN1设置为接收
root@ARM40:~# cansend can0 5A1#11.2233.44556677.88	    		// CAN0发数据
can1  5A1   [8]  11 22 33 44 55 66 77 88
root@ARM40:~# candump can0 &			                    	//将CAN0设置为接收
root@ARM40:~# cansend can1 5A1#11.2233.44556677.88	    		// CAN1发数据
can0  5A1   [8]  11 22 33 44 55 66 77 88

二、CAN总线发送和接收的C源码

2.1、CAN总线发送

  这个测试程序要用USB CAN II调试盒或者睿芯CAN转串口(USB串口)做接收,传送到PC机上。

/*
 * test_can_recv.c 
 *ARM40发送,PC接收
 */
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/sockios.h>
#include <linux/if.h>

int main( int argc,char* argv[] )
{
        int i, ret;
        int nbytes;
        int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
        char *interface = "can0";

        int can_fd = -1;
        struct sockaddr_can addr;
        struct ifreq ifr;
        struct can_frame frame_rev;

        printf("SocketCAN Test V1.0\n");

        can_fd = socket(family, type, proto);                // 创建SocketCAN 套接字
        printf("SOCK_RAW can sockfd:%d\n", can_fd);
        if( can_fd < 0 )
        {
                perror("socket");
                return can_fd;
        }

        int loopback = 0;         // 0 = disabled, 1 = enabled (default)
        setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

        strcpy(ifr.ifr_name, interface);        // 指定 can0 设备 strcpy(ifr.ifr_name, "can0" );
        ret = ioctl(can_fd, SIOCGIFINDEX, &ifr);        // 指定 can0 设备
        if(ret) {
                perror("ioctl:interface");
                goto abort;
        }

        addr.can_family = family;
        addr.can_ifindex = ifr.ifr_ifindex;
        ret = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr));        // 将套接字与 can0 绑定
        if (ret)        {
                perror("bind\n");
                goto abort;
        }

        // 设置过滤规则,只接收表示符等于 0x123 的报文,如果没有这段,则接受所有报文
        struct can_filter rfilter;
        rfilter.can_id = 0x123;
        rfilter.can_mask = CAN_SFF_MASK;     							  // 0x000007FFU
        setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));        //设置过滤规则
        /*
         * 如果应用程序不需要接收报文,可以禁用过滤规则。这样的话,原始套接字就会忽略所有接收到的报文。
         * 在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少 CPU 资源的消耗。
         * 禁用方法如下:
         * setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);     //禁用过滤规则
         */
        memset(&frame_rev,0x0,sizeof(frame_rev));
        while(1) {
                nbytes = read(can_fd, &frame_rev, sizeof(frame_rev));               //接收报文
                if(nbytes < 0){
                        perror("read");
                        goto abort;
                }

                if(nbytes < sizeof(struct can_frame)){
                        printf("read:incomplete can frame\n");
                        goto abort;
                }

                printf("ID=0x%X,DLC=%d",frame_rev.can_id,frame_rev.can_dlc);        //显示报文
                for(i=0; i<frame_rev.can_dlc; i++)
                        printf(",data[%d]=%x", i,frame_rev.data[i]);
                printf("\n");

                memset(&frame_rev,0x0,sizeof(frame_rev));
        }
        close(can_fd);
        return 0;

abort:
        close(can_fd);
        return ret;
}

  测试结果为:

root@ARM40:~# ./test_can0_recv 
SocketCAN Test V1.0
SOCK_RAW can sockfd:3        // PC上发送数据,ARM40上可以接收到
ID=0x123,DLC=8,data[0]=0,data[1]=1,data[2]=2,data[3]=3,data[4]=4,data[5]=5,data[6]=6,data[7]=7
ID=0x123,DLC=8,data[0]=0,data[1]=1,data[2]=2,data[3]=3,data[4]=4,data[5]=5,data[6]=6,data[7]=7

2.2、CAN总线接收

  这个测试程序要用USB CAN II调试盒或者睿芯CAN转串口(USB串口)接到PC机上,PC发送,ARM40接收。

/*
 *test_can_send.c 
 *ARM40接收,PC发送
 */
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/sockios.h>
#include <linux/if.h>


int main( int argc,char* argv[] )
{
        int i, ret;
        int nbytes;
        int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
        char *interface = "can1";

        int can_fd = -1;
        struct sockaddr_can addr;
        struct ifreq ifr;
        struct can_frame frame_send;


        printf("SocketCAN Test V1.0\n");

        can_fd = socket(family, type, proto);                // 创建SocketCAN 套接字
        printf("SOCK_RAW can sockfd:%d\n", can_fd);
        if( can_fd < 0 )
        {
                perror("socket");
                return can_fd;
        }

        int loopback = 0; 									// 0 = disabled, 1 = enabled (default)
        setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

        strcpy(ifr.ifr_name, interface);        			// 指定 can0 设备 strcpy(ifr.ifr_name, "can0" );
        ret = ioctl(can_fd, SIOCGIFINDEX, &ifr);        	// 指定 can0 设备
        if(ret)
        {
                perror("ioctl:SIOCGIFINDEX");
                goto abort;
        }

        addr.can_family = family;
        addr.can_ifindex = ifr.ifr_ifindex;
        ret = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr));        // 将套接字与 can0 绑定
        if(ret) {
                perror("bind\n");
                goto abort;
        }

		/* 发送一个字节的情况
        frame_send.can_id = 0x00;
        frame_send.can_dlc = 1;
        frame_send.data[0] = 'Y';
		*/
        frame_send.can_id = 0x123;
        frame_send.can_dlc = 8;        									 // 发送8个字节,一次最多发8个字节
        for(i=0; i<8; ++i)      {    
                frame_send.data[i] = i;
        }
        //strncpy(frame_send.data,"12345678",8);

        nbytes = write(can_fd, &frame_send, sizeof(frame_send));        //发送
        if(nbytes <0 ){
                perror("write");
                goto abort;
        }

        // 打印发送的字节
        printf("write %d bytes frame:can_id=0x%x,can_dlc=%d\n", i,frame_send.can_id,frame_send.can_dlc);
        for(i=0; i<frame_send.can_dlc; i++)
                        printf(",data[%d]=%x", i,frame_send.data[i]);
        printf("\n");

        close(can_fd);
        return 0;

abort:
        close(can_fd);
        return ret;
}

  测试结果为:

root@ARM40:~# ./test_can1_send
SocketCAN Test V1.0
SOCK_RAW can sockfd:3        // PC上收到的数据
write 8 bytes frame:can_id=0x123,can_dlc=8
,data[0]=0,data[1]=1,data[2]=2,data[3]=3,data[4]=4,data[5]=5,data[6]=6,data[7]=7
root@ARM40:~# 

参考文章:
  Linux内核 Documentation/networking/can.txt
  Low Level CAN Framework Application Programmers Interface
  Linux内核Socket CAN中文文档
  https://blog.csdn.net/yuanlulu/article/details/7220060
  Linux socket CAN编程示例
  https://blog.csdn.net/jirryzhang/article/details/79417986
  Linux CAN编程详解
  https://blog.csdn.net/reille/article/details/49980469
  linux can 总线socket接口测试使用
  http://blog.chinaunix.net/uid-13889805-id-3072479.html
  CAN接口测试方法
  http://www.embedsky.com/index.php?g=home&m=news&a=show&id=62
  https://github.com/linux-can/can-utils
  荟聚计划:共商 共建 共享 Grant

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值