Linux CAN通信(二)

Linux CANBUS通信

经过canbus模块的学习,自己根据通信协议以及上一节的代码实现报文的接收与发送。希望能给读者提供帮助。

send.cpp
//导入头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <time.h> //生成随机数用
#include <iostream>

#define CAN_EFF_FLAG 0x80000000U  // 扩展帧的标识
#define CAN_RTR_FLAG 0x40000000U // 远程帧的标识
#define CAN_ERR_FLAG 0x20000000U // 错误帧的标识,用于错误检查 

int main()
{
    int s,nbytes1,nbytes2,nbytes3,nbytes4;
    int num;
    srand(time(nullptr));//设置随机数种子
    rand();//产生一个随机数
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame1 = {0};
    struct can_frame frame2 = {0};
    struct can_frame frame3 = {0};
    struct can_frame frame4 = {0};

    s = socket(PF_CAN,SOCK_RAW,CAN_RAW); // 创建套接字
    strcpy(ifr.ifr_name,"vcan0");
    ioctl(s,SIOCGIFINDEX,&ifr);   // 指定can0设备
    addr.can_family = AF_CAN;
    addr.can_ifindex  = ifr.ifr_ifindex;
    bind(s,(struct sockaddr *)&addr,sizeof(addr)); //将套接字与can0设备绑定

    //setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,NULL,0); // 禁用过滤规则
    //生成报文
    frame1.can_id = CAN_EFF_FLAG | 0x18FEF121;// ID为扩展帧
    //车速信号
    frame1.can_dlc = 8;
    frame1.data[0] = 0x00;
    frame1.data[3] = 0x00;
    frame1.data[4] = 0x00;
    frame1.data[5] = 0x00;
    frame1.data[6] = 0x00;
    frame1.data[7] = 0x00;

    frame2.can_id = CAN_EFF_FLAG | 0x18FF0824;// ID为扩展帧
    //发动机转速/电动泵信号
    frame2.can_dlc = 8;
    frame2.data[0] = 0x00;
    frame2.data[1] = 0x00;
    frame2.data[2] = 0x00;
    frame2.data[3] = 0x00;
    frame2.data[5] = 0x00;
    frame2.data[6] = 0x00;
    frame2.data[7] = 0x00;

    frame3.can_id = CAN_EFF_FLAG | 0x0C02A224;// ID为扩展帧
    //发动机转速/电动泵信号
    frame3.can_dlc = 8;
    frame3.data[5] = 0x80;
    frame3.data[6] = 0x80;

    // 转向控制器发给整车控制
    frame4.can_id = CAN_EFF_FLAG | 0x0c02a0a2;// ID为扩展帧
    frame4.can_dlc = 8;
    
    frame4.data[2] = rand() % 0xFF;
    frame4.data[3] = rand() % 0xFF;
    
    while(1)
    {
        frame1.data[1] = rand() % 0xFAFF;
        frame1.data[2] = rand() % 0xFAFF;
        if ((frame1.data[1]+frame1.data[2])>0xFAFF)break;//限制范围在0-250.996km/h
        nbytes1 = write(s,&frame1,sizeof(frame1)); // 发送frame1
        if (nbytes1 != sizeof(frame1))
        {
            printf("Send Error frame1\n");
            break; //发送错误,跳出循环
        }
        sleep(0.1);  //发送周期0.1s

        frame2.data[4] = rand() % 0x07; // 0-0x07
        nbytes2 = write(s,&frame2,sizeof(frame2)); // 发送frame2
        if (nbytes2 != sizeof(frame2))
        {
            printf("Send Error frame2\n");
            break; //发送错误,跳出循环
        }
        sleep(0.1);  //发送周期0.1s
        frame3.data[0] = rand() % 0xf4;
        frame3.data[1] = rand() % 0x7e;//限制范围在0-32500
        frame3.data[3] = rand() % 0x100; // 0-256
        frame3.data[4] = 0x14 + rand() % 0xa; //200-300
        frame3.data[7] = rand() % 0xFA;
        if (frame2.data[4] == 0x03)
        {
            while(1)
            {
                frame3.data[2] = 0x34; // 默认进入手动指令(EPS模式状态4)
                int a;
                if (std::cin >> a,a) //如需进入自动驾驶模式,输入1,否则输入0
                {
                    frame3.data[2] = 0x31;
                } 
                if (std::cin >> a,a) //如需再次进入自动驾驶模式输入5介入恢复指令,否则输入0
                {
                    frame3.data[2] = 0x35;
                    continue;
                }
                break;
            }

            nbytes3 = write(s,&frame3,sizeof(frame3)); // 发送frame3
            if (nbytes3 != sizeof(frame3))
            {
                printf("Send Error frame3\n");
                break; //发送错误,跳出循环
            }
            sleep(0.02);  //发送周期20ms
            frame4.data[0] = frame3.data[0];
            frame4.data[1] = frame3.data[1];
            frame4.data[4] = frame3.data[4];
            frame4.data[5] = frame3.data[3];
            frame4.data[7] = frame3.data[7];
            if (frame3.data[2] == 0x34)
            {
                frame4.data[6] = 0x04; //EPS助力模式
            }
            else if (frame3.data[2] == 0x31)
            {
                frame4.data[6] = 0x01; //自动驾驶模式
            }
            else
            {
                frame4.data[6] = 0x05; // 发送手动介入指令
            }
            nbytes4 = write(s,&frame4,sizeof(frame4)); // 发送frame4
            if (nbytes4 != sizeof(frame4))
            {
                printf("Send Error frame4\n");
                break; //发送错误,跳出循环
            }
            sleep(0.02);  //发送周期20ms
        }
    }

    close(s);
    return 0;
    
}
receive.cpp
//导入头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <time.h> //生成随机数用
#include <iostream>

#define CAN_EFF_FLAG 0x80000000U  // 扩展帧的标识
#define CAN_RTR_FLAG 0x40000000U // 远程帧的标识
#define CAN_ERR_FLAG 0x20000000U // 错误帧的标识,用于错误检查 

#define CAN_SFF_MASK 0x000007FFU /* 标准帧格式 (SFF) */
#define CAN_EFF_MASK 0x1FFFFFFFU /* 扩展帧格式 (EFF) */
#define CAN_ERR_MASK 0x1FFFFFFFU /* 忽略EFF, RTR, ERR标志 */

int main()
{
    int s,nbytes1,nbytes2,nbytes3,nbytes4;
    srand(time(nullptr));//设置随机数种子
    rand();//产生一个随机数
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame1 = {0};
    struct can_frame frame2 = {0};
    struct can_frame frame3 = {0};
    struct can_frame frame4 = {0};
    struct can_filter rfilter[4];
    int count = 0; //故障保护
    s = socket(PF_CAN,SOCK_RAW,CAN_RAW); //创建套接字
    strcpy(ifr.ifr_name,"vcan0");
    ioctl(s,SIOCGIFINDEX,&ifr);
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    bind(s,(struct sockaddr *)&addr,sizeof(addr));
    //定义接收规则
    rfilter[0].can_id = CAN_EFF_FLAG | 0x18FEF121;
    rfilter[0].can_mask = CAN_EFF_MASK;

    rfilter[1].can_id = CAN_EFF_FLAG | 0x18FF0824;
    rfilter[1].can_mask = CAN_EFF_MASK;

    rfilter[2].can_id = CAN_EFF_FLAG | 0x0C02A224;
    rfilter[2].can_mask = CAN_EFF_MASK;

    rfilter[3].can_id = CAN_EFF_FLAG | 0x0c02a0a2;
    rfilter[3].can_mask = CAN_EFF_MASK;
    //设置过滤规则
    setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,&rfilter,sizeof(rfilter));

    while(1)
    {
        double factor = 1/256.0;//车速的分辨率
        int Offset = 0;//车速的偏移量
        int num,num1;
        double zfactor = 0.1; //方向盘转向指令角度的分辨率
        int zOffset = -1575; 方向盘转向指令角度的偏移量
        double nfactor = 0.1; //转向叠加扭矩信号的分辨率
        int nOffset = 0; //转向叠加扭矩信号的偏移量
        double ffactor = 10;//方向盘目标角速度的分辨率
        int fOffset = 0; //方向盘目标角速度的偏移量
        double dfactor = 0.000152;
        int dOffset = -5;
        nbytes1 = read(s,&frame1,sizeof(frame1));  //接收报文
        nbytes2 = read(s,&frame2,sizeof(frame2));  //接收报文
        
        if (nbytes1 > 0)
        {
            printf("ID = 0x%X   dlc = %d  data = 0x ",frame1.can_id,frame1.can_dlc);
            for (int i = 0; i < frame1.can_dlc; i++)printf("%02x ",frame1.data[i]);
            num = (frame1.data[2]<<8) | (frame1.data[1]); //将两个十六进制数字合并
            printf("v = %.2f km/h",factor*num+Offset); // 十六进制转为十进制输出
            printf("\n");
        }
        if (nbytes2 > 0)
        {
            printf("ID = 0x%X   dlc = %d  data = 0x ",frame2.can_id,frame2.can_dlc);
            for (int i = 0; i < frame2.can_dlc; i++)printf("%02x ",frame2.data[i]);
            printf("\n");
            if (frame2.data[4] == 0x01)
            {
                printf("Stop!\n");
            }
            else if (frame2.data[4] == 0x02){
                printf("Ready\n");
            }
            else if (frame2.data[4] == 0x03){
                nbytes3 = read(s,&frame3,sizeof(frame3));  //接收报文
                if (nbytes3 >0)
                {
                    count++;
                    if (count >5) //五个周期故障保护
                    {
                        if (frame3.data[7]>0xFA) //数据大于250
                        {
                            printf("此报文不可靠\n");
                        }
                        else printf("此报文可靠\n");
                    }
                    printf("ID = 0x%X   dlc = %d  data = 0x ",frame3.can_id,frame3.can_dlc);
                    for (int i = 0; i < frame3.can_dlc; i++)printf("%02x ",frame3.data[i]);
                    printf("\nGo转向可以启动!\n");//转向可以启动
                    num1 = (frame3.data[1]<<8) | (frame3.data[0]); //将两个十六进制数字合并
                    printf("方向盘转向指令角度 = %.1f度\n",num1*zfactor+zOffset); 
                    if (frame3.data[2] == 0x34)printf("收到EPS助力模式指令,进入EPS模式\n");
                    if (frame3.data[2] == 0x31)printf("收到自动驾驶模式指令,进入自动驾驶模式\n");

                    printf("转向叠加扭矩信号 =  %.1f  N.m\n",nfactor*frame3.data[3]+nOffset);
                    printf("方向盘目标角速度 =  %.1f  度/s\n",ffactor*frame3.data[4]+fOffset);
                    printf("\n\n");

                    nbytes4 = read(s,&frame4,sizeof(frame4));  //接收报文
                    if (nbytes4>0)
                    {
                        printf("ID = 0x%X   dlc = %d  data = 0x ",frame4.can_id,frame4.can_dlc);
                        for (int i = 0; i < frame4.can_dlc; i++)printf("%02x ",frame4.data[i]);
                        if (frame4.data[6] == 0x04)
                        {
                            printf("处于EPS模式状态\n");
                        }
                        else if (frame4.data[6] == 0x01)
                        {
                            printf("处于自动驾驶模式状态\n");
                        }
                        num1 = (frame4.data[1]<<8) | (frame4.data[0]); //将两个十六进制数字合并
                        printf("方向盘转向角度 = %.1f度\n",num1*zfactor+zOffset); 
                        num1 = (frame4.data[3]<<8) | (frame4.data[2]); //将两个十六进制数字合并
                        printf("电机助力扭矩 = %.2f Nm\n",num1*dfactor+dOffset);
                        printf("方向盘反馈角速度 = %.1f 度/s \n",ffactor*frame4.data[4]+fOffset);
                        printf("转向盘转矩信号 = %.1f Nm\n",nfactor*frame4.data[5]+nOffset);
                        
                        printf("\n");
                    }
                }
                
            }
                else if (frame2.data[4] == 0x04){
                    printf("远程升级\n");
                }
                else if (frame2.data[4] == 0x06){
                    printf("跛行\n");
                }
                else{
                    printf("失效\n");
                    }
            }
        }   
        close(s);
        return 0;
    }
    
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值