can口通信详解

can口通信详解

can口分为:

标准帧:使用can_id的0~10位作为标识符
扩展帧:使用can_id的0~28位作为标识符
远程帧:由总线上的节点发出,用于请求其他节点发送具有同一标识符的数据帧。当某个节点需要数据时,可以发送远程帧请求另一节点发送相应数据帧。与数据帧相比,远程帧没有数据场(主要用来避免数据同时发送造成冲突,数据帧的优先级大于远程帧)
数据帧:数据帧携带数据从发送器至接收器
错误帧:任何单元,一旦检测到总线错误就发出错误帧。错误帧由两个不同的场组成,第一个场是由不同站提供的错误标志的叠加(错误标志),第二个场是错误界定符

can_id的第29、30、31位是帧的标志位,用来定义帧的类型
#define CAN_EFF_FLAG 0x80000000U //扩展帧的标识
#define CAN_RTR_FLAG 0x40000000U //远程帧的标识
#define CAN_ERR_FLAG 0x20000000U //错误帧的标识,用于错误检查

使用can口时,要先设置速率,只有速率一致才能收发到数据。

  1. 使用IP命令 设置波特率
ifconfig can0 down         					//一定要先关闭才能设置
ip link set can0 type can bitrate 125000    //设置波特率
ifconfig can0 up                            //打开can接口
  1. 使用canconfig命令 设置波特率
ifconfig can0 down                         //一定要先关闭才能设置
canconfig can0 bitrate 125000 ctrlmode triple-sampling on //设置波特率
canconfig can0 start        
ifconfig can0 up                          //打开can接口

使用canconfig命令时,如果没有需要交叉编译;
先下载 canutils和 libsocketcan下载链接
首先编译ibsocketcan库

tar -xvf canutils-4.0.6.tar.bz2
cd libsocketcan-0.0.10/
mkdir out
./configure --prefix=/home/qt/test/libsocketcan-0.0.10/out --host=arm-none-linux-gnueabi//这里选择自己的交叉编译器
make
make install

生成的库在 out/lib 下,将这些生成的库复制到你板子的文件系统内,放在 lib 目录下也行,放在 usr/lib 里面也可以
然后编译canutils库:

tar -xvf canutils-4.0.6.tar.bz2
cd canutils-4.0.6/
mkdir out
./configure --host=arm-none-linux-gnueabi --prefix=/home/qt/test/canutils-4.0.6/out libsocketcan_LIBS=-lsocketcan LDFLAGS="-L/home/qt/test/libsocketcan-0.0.10/out/lib/" libsocketcan_CFLAGS="-I/home/qt/test/libsocketcan-0.0.10/out/include" //注意选择自己的路径和自己的编译器
make
make install

然后就编译成功,生成了canconfigcansendcandump等小工具都在out目录中

cansend can0 -i 0x800 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 -e
-e 表示扩展帧,CAN_ID最大29bit,标准帧CAN_ID最大11bit  -i表示CAN_ID
candump can0
监听CAN0数据

参考链接

C语言代码实例:

can口初始化函数

int canInit(int fd, char *dev, char id_1, char id_2)
{
    int ret;
    struct ifreq ifr;
    struct sockaddr_can addr;
    struct can_filter rfilter[2] = {{0}};      //这里要接收两个can_id号,所以建了两个结构体
    char * cmd = (char *)calloc(125, sizeof(char));
    
    memset(cmd, 0, 125);
    snprintf(cmd, 125, "ifconfig %s down", dev);
    system(cmd);
    memset(cmd, 0, 125);                         //配置can口速率
    snprintf(cmd, 125, "canconfig %s bitrate 125000 ctrlmode triple-sampling on", dev);
    system(cmd);
    memset(cmd, 0, 125);
    snprintf(cmd, 125, "canconfig %s start", dev);
    system(cmd);
    memset(cmd, 0, 125);
    snprintf(cmd, 125, "ifconfig %s up", dev);
    system(cmd);

    fd = socket(PF_CAN,SOCK_RAW,CAN_RAW);
    strcpy(ifr.ifr_name,dev);                        //映射实际的can接口
    ret = ioctl(fd ,SIOCGIFINDEX ,&ifr);
    if(ret < 0) {
        ERR_DEBUG("ioctl error[%d]", ret);
        ES_FREE(cmd);
        return CAN_IOCTL_ERROR;
    }
    memset(&addr, 0, sizeof(addr));
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    bind(fd, (const struct sockaddr *)&addr, sizeof(addr));

    rfilter[0].can_id = id_1;                        // 要接收的can_id
    rfilter[0].can_mask = CAN_SFF_MASK;

    rfilter[1].can_id = id_2;                         //要接收的can_id    这里这两个id都能监听到
    rfilter[1].can_mask = CAN_SFF_MASK;

    setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(struct can_filter)); 
    ESdata->can_p->fd = fd;
    
    ES_FREE(cmd);
    return 0;
}

can口发送函数

int can_send(int sock_fd, int can_id/*发送can_id*/, char * data/*发送的数据*/)
{
    int i, j, ret;
    struct can_frame frame;
    
    memset(&frame, 0, sizeof(struct can_frame));
    if(data == NULL){
        ERR_DEBUG("can data is null");
        return CAN_DATA_NULL;
    }
    if(can_id != 0){    
        frame.can_id = can_id;
        frame.can_dlc = 8;
        for(i=0;i<8;i++)
            frame.data[i] = data[i];
        ret = write(sock_fd, &frame, sizeof(struct can_frame));
        if(ret != sizeof(frame)) {
            ERR_DEBUG("send message error");
            return CAN_SEND_ERROR;
        }
    }

    DEBUG("send [0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x]",frame.data[0],frame.data[1],frame.data[2],frame.data[3],frame.data[4],frame.data[5],frame.data[6],frame.data[7]);

    return 0;
}

can口接收函数

int can_recv(const int fd, char * recv_data/*接收buf*/)
{
    int i;    
    int nbytes;
    struct can_frame frame;
    
    nbytes = read(fd, &frame, sizeof(frame));
    if(nbytes > 0){
        memset(recv_data, 0, CAN_LEN);
        DEBUG("recv from [0x%x] dlc [%d]",frame.can_id,frame.can_dlc);
        for(i = 0; i < nbytes; i++)
            recv_data[i] = frame.data[i];

        DEBUG("recv [%x %x %x %x %x %x %x %x]", recv_data[0], recv_data[1], recv_data[2], recv_data[3], recv_data[4], recv_data[5], recv_data[6], recv_data[7]);
    }else{
        ERR_DEBUG("can receive error");
        return CAN_RECV_ERROR;
    }
    
    return 0;
}
发布了4 篇原创文章 · 获赞 4 · 访问量 171

猜你喜欢

转载自blog.csdn.net/wazqybz/article/details/104691828
今日推荐