can/socket can

1. 概念

参考:Linux-CAN编程详解

can引脚: cn2: 15:CAN1_H 19 CAN1_L


根据每组报文开头的 11 位标识符(扩展帧为29位标识符、CAN 2.0A 规范)解释数据的含义来决定是否接收。

 

CAN状态:

准备状态:
这个节点的处理器将要发送的数据和自己的标识符传送给该节点的 CAN 总线接口控制器

报文状态:
当收到总 线分配时,转为发送报文状态。

接收状态:
数据根据协议组织成一定的报文格式后发出,此时网络上的其他节点处于接收状态。处于接收状态的每个节点对接
收到的报文进行检测,判断这些报文是否是发给自己的以确定是否接收。


层次结构:
对象层:在对象层中可以为远程数据请求以及数据传输提供服务,确定由实际要使用的传输层接收哪一个报文,并且
为恢复管理和过载通知提供手段。
传输层:传输层负责位的定时及同步、报文分帧、仲裁、应答、错误检测和标定、故障界定。
物理层:波特率之类的


报文结构:
数据帧:发送数据
远程帧:请求数据
错误帧:检测到错误则发出
过载帧:提供帧与帧之间的延时

 


ip link set can0 type can bitrate 125000

 流程:

1. 创建socket
2. bind将socket绑定can
3. 设置选项setsockopt
4. read/write

 

常用命令:

在控制台上输入命令:
ifconfig –a
可以得到以下结果:

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope: Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 TX bytes:0

eth0 Link encap:Ethernet HWaddr F6:88:05:8F:72:8C
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 TX bytes:0

can0 Link encap:UNSPEC
UP RUNNING NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 TX bytes:2
Interrupt:32

 

令来配置 CAN 总线的位速率:

ip link set can0 type cantq 125 prop-seg 6phase-seg1 7 phase-seg2 2 sjw 1


也可以使用 ip 命令直接设定位速率:

ip link set can0 type can bitrate 125000


当设置完成后,可以通过下面的命令查询 can0 设备的参数设置:

ip -details link show can0


当设置完成后,可以使用下面的命令使能 can0 设备:

ifconfig can0 up


使用下面的命令取消 can0 设备使能:

ifconfig can0 down


在设备工作中,可以使用下面的命令来查询工作状态:

ip -details -statistics link show can0

 

2. 测试流程:

1. 启动Linux的can0,并初始化

ifconfig can0 down   //要修改can的参数,必须先down
ip link set can0 type can bitrate 1000000
ifconfig can0 up

 

2. 测试代码

#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 fd, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    int ret;
    
    //1. 初始化
    struct can_frame frame[4] = {{0}};
    fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建套接字

    printf("version=6;fd=%d\n", fd);
    
    strcpy(ifr.ifr_name, "can0" );
    ioctl(fd, SIOCGIFINDEX, &ifr); //指定 can0 设备
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));//将套接字与 can0 绑定
    printf("ret=%d\n", ret);
    
    //禁用过滤规则,本进程不接收报文,只负责发送
    setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
    //报文1:数据帧:标准帧、ID=0x11;
    frame[0].can_id = 0x11;
    frame[0]. can_dlc = 1;
    frame[0].data[0] = 0x12;
    
    //报文2:数据帧:扩展帧、ID=0x22
    frame[1].can_id = 0x22 | CAN_EFF_FLAG;
    frame[1]. can_dlc = 1;
    frame[1].data[0] = 0x34;

    //报文3:远程帧:ID=0x33;
    frame[2].can_id = 0x33 | CAN_RTR_FLAG;

    //报文4:错误帧:ID=0x44;
    frame[3].can_id = 0x44 | CAN_ERR_FLAG;


    //循环发送两个报文
    //while(1)
    {
        nbytes = write(fd, &frame[0], sizeof(frame[0])); //发送 frame[0]
        if(nbytes != sizeof(frame[0]))
        {
            printf("Send Error frame[0]\n!");
            //break; //发送错误,退出
        }else{
            printf("Send Sucess frame[0]\n!");
        }
        //usleep(10000);
        sleep(1);
        nbytes = write(fd, &frame[1], sizeof(frame[1])); //发送 frame[1]
        if(nbytes != sizeof(frame[1]))
        {
            printf("Send Error frame[1]\n!");
            //break;
        }else{
                printf("Send Sucess frame[1]\n!");
        }
        //usleep(10000);
        sleep(1);
        nbytes = write(fd, &frame[2], sizeof(frame[2])); //发送 frame[1]
        if(nbytes != sizeof(frame[2]))
        {
            printf("Send Error frame[2]\n!");
            //break;
        }else{
                printf("Send Sucess frame[21]\n!");
        }
        //usleep(10000);
        sleep(1);
        nbytes = write(fd, &frame[3], sizeof(frame[3])); //发送 frame[1]
        if(nbytes != sizeof(frame[3]))
        {
            printf("Send Error frame[3]\n!");
            //break;
        }else{
                printf("Send Sucess frame[3]\n!");
        }
        //usleep(10000);
        sleep(1);
    }
    
    close(fd);
    return 0;
}

 

3. 现象

android上现象:

 

Windows上现象:

 

波形现象:(注:因为上面的发送太少,抓不到数据,所以下面的是我更换了其他代码查看的)

CPU出来的CAN信号,是标准信号

 

进过转换过后的,很难查看出来,但是就是这个差分信号

 

posted on 2018-03-28 10:38  maogefff  阅读(4275)  评论(1编辑  收藏  举报

导航