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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章