Linux can接口通信编程

⌚Time: 2022-08-03 21:09:11

👨‍💻Author: Jack Ge

由于没有can通信设备,使用以下命令模拟了一个vcan0接口


sudo modprobe vcan

sudo ip link add dev vcan0 type vcan

sudo ip link set up vcan0

编写程序,首先向vcan0发送两次数据,之后监听数据

代码:


extern "C" {



#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

#include <sys/ioctl.h>

#include <sys/ioctl.h>

#include <net/if.h>

#include <linux/can.h>



}



#include <string>



using namespace std;



int main(){



    int socket_0;

    struct sockaddr_can addr_0;

        struct ifreq ifr;//接口请求结构体

    struct can_frame frame;



    socket_0 = ::socket(PF_CAN,SOCK_RAW,CAN_RAW);//创建套接字

        strcpy((char *)(ifr.ifr_name),"vcan0");

        //fcntl(socket, F_SETFL, 1);        //标志FNDELAY可以保证read函数在端口上读不到字符的时候返回0

        fcntl(socket_0, F_SETFL, 0);            //回到正常(阻塞)模式

        ioctl(socket_0,SIOCGIFINDEX,&ifr);//指定 CAN0/1 设备

        addr_0.can_family = AF_CAN;//协议类型

        addr_0.can_ifindex = ifr.ifr_ifindex;//can总线外设的具体索引 类似 ip地址

        bind(socket_0,(struct sockaddr*)&addr_0,sizeof(addr_0));//将套接字和canbus外设进行绑定,即套接字与 can0/1 绑定

        memset(&frame,0,sizeof(struct can_frame));

        frame.can_id = (0x12345678 & CAN_EFF_MASK) | CAN_EFF_FLAG;//扩展帧

        //frame.can_id = (0x12345678 & CAN_SFF_MASK);//标准帧

        

    frame.can_dlc= 8;

    frame.data[0]= 0x11;

    frame.data[1]= 0x22;

    frame.data[2]= 0x33;

    frame.data[3]= 0x44;

    frame.data[4]= 0xaa;

    frame.data[5]= 0xbb;

    frame.data[6]= 0xcc;

    frame.data[7]= 0xdd;





    //发送can数据:方式一

    sendto(socket_0,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr_0,sizeof(addr_0));

    //发送can数据:方式二

    //write(socket_0, &frame, sizeof(frame)); //发送 frame



    frame.data[0]= 0xff;

    frame.data[1]= 0xee;

    frame.data[2]= 0xdd;

    frame.data[3]= 0xcc;

    frame.data[4]= 0xbb;

    frame.data[5]= 0xaa;

    frame.data[6]= 0x99;

    frame.data[7]= 0x88;



    sendto(socket_0,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr_0,sizeof(addr_0));





    //接收can数据

    while(1){

        

        int nbytes;

        struct can_frame frameReceive;

        string data;

        char dataBuffer[1024];



        

        nbytes = read(socket_0, &frameReceive, sizeof(frameReceive)); //接收报文

        if(nbytes > 0){

            printf("%08X ",frameReceive.can_id&0x7fffffff);

            for(int i=0;i<frameReceive.can_dlc;i++){

                memset(dataBuffer,0,sizeof(dataBuffer));

                sprintf(dataBuffer,"%02X",frameReceive.data[i]);

                data.append(dataBuffer);

            }

        printf("%s\n",data.c_str());



        }

    }

    ::close(socket_0);

    return 0;

}

使用can-utils对通信进行测试

安装can-utils


sudo apt-get install can-utils

使用以下命令向vcan0发送十六进制数据12 34 56 78,can id:0x123


cansend vcan0 -i 0x123 0x12 0x34 0x56 0x78

使用以下命令监听vcan0接口


candump  vcan0

效果