<Linux开发> linux应用开发-之-can通信开发例程

20 篇文章 3 订阅
4 篇文章 1 订阅

<Linux开发> linux应用开发-之-can通信开发例程

一、简介
对于Can通信的相关介绍,读作不过多介绍了,网上其它网友的介绍有很多。

二、环境搭建
本次测试can通信的应用例程是运行在ubuntu pc上的;当然也是可以运行在linux开发板 或相关linux设备上的。
在ubuntu pc上安装虚拟can,命令如下:

 1.sudo modprobe vcan
 加载虚拟can模块

 2.sudo ip link add dev can0 type vcan
 添加can0网卡
 
 3.ifconfig -a
 查看can0

 4.sudo ip link set dev can0 up
 开启can0

 5.sudo ip link set dev can0 down
 关闭can0

 6. sudo ip link del dev can0
 删除can0

对于我们要使用虚拟Can,运行1~4步即可;当测试完Can通信,不使用时可使用 5~6删除。

启动后查看如下:
在这里插入图片描述

三、例程代码
本次代码会使用主进程发送数据,子进程接收数据;详细代码如下:

/***************************************************************
Copyright © OneFu Co., Ltd. 1998-2022. All rights reserved.
文件名 : can.c
作者 : waterfxw
版本 : V1.0
描述 : CAN 数据发送接收示例代码
其他 : 无
日志 : 初版 V1.0 2023/03/15 waterfxw创建
***************************************************************/


#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 <sys/types.h>
#include <sys/wait.h>
#include <errno.h>


void procc(void)
{
    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    struct can_frame frame = {0};
    int sockfd = -1;
    int i;
    int ret;

    /* 打开套接字 */
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(0 > sockfd) {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    /* 指定 can0 设备 */
    strcpy(ifr.ifr_name, "can0");
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    /* 将 can0 与套接字进行绑定 */
    ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
    if (0 > ret) {
        perror("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    /* 设置过滤规则 */
    //setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
    /* 接收数据 */
    for ( ; ; ) {
        if (0 > read(sockfd, &frame, sizeof(struct can_frame))) {
            perror("water read error");
            break;
        }

        /* 校验是否接收到错误帧 */
        if (frame.can_id & CAN_ERR_FLAG) {
            printf("water Error frame!\n");
            break;
        }

        /* 校验帧格式 */
        if (frame.can_id & CAN_EFF_FLAG) //扩展帧
            printf("扩展帧 <0x%08x> ", frame.can_id & CAN_EFF_MASK);
        else //标准帧
            printf("标准帧 <0x%03x> ", frame.can_id & CAN_SFF_MASK);

        /* 校验帧类型:数据帧还是远程帧 */
        if (frame.can_id & CAN_RTR_FLAG) {
            printf(" remote request\n");
            continue;
        }

        /* 打印数据长度 */
        printf(" [%d] ", frame.can_dlc);

        /* 打印数据 */
        for (i = 0; i < frame.can_dlc; i++)
            printf("%02x ", frame.data[i]);
        printf(" [子进程 接收数据] \n");
    }
    /* 关闭套接字 */
    close(sockfd);
    exit(EXIT_SUCCESS);

    //子进程测试使用
    // while (1)
    // {
    //     /* code */
    //      printf("子进程<%d>被创建---\n", getpid());
    //       sleep(2);
           
    // }
    //  _exit(0);
}





int main(void) {
    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    struct can_frame frame = {0};
    int sockfd = -1;
    int ret;
    int status;
    int i;

    switch (fork()) {
        case -1:
            perror("fork error");
            exit(-1);
        case 0:
            /* 子进程 */
           procc();
            sleep(1);
            _exit(0);
        default:
            /* 父进程 */
        break;
    }

    //父进程测试使用
    //  while (1)
    // {
    //     /* code */
    //      printf("父进程<%d>被创建---\n", getpid());
    //       sleep(2);
           
    // }

    


    /* 打开套接字 */
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(0 > sockfd) {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    /* 指定 can0 设备 */
    strcpy(ifr.ifr_name, "can0");
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    /* 将 can0 与套接字进行绑定 */
    ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
    if (0 > ret) {
        perror("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    /* 设置过滤规则:不接受任何报文、仅发送数据 */
    setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);

    /* 发送数据 */
    frame.data[0] = 0xA0;
    frame.data[1] = 0xB0;
    frame.data[2] = 0xC0;
    frame.data[3] = 0xD0;
    frame.data[4] = 0xE0;
    frame.data[5] = 0x11;
    frame.data[6] = 0x22;
    frame.data[7] = 0x33;
    frame.can_dlc = 8; //一次发送 6 个字节数据
    frame.can_id = 0x321;//帧 ID 为 0x123,标准帧

    for ( ; ; ) {
        ret = write(sockfd, &frame, sizeof(frame)); //发送数据
        if(sizeof(frame) != ret) { //如果 ret 不等于帧长度,就说明发送失败
            perror("write error");
            goto TT;
        }
        printf("[OnefU] 主进程发送数据成功!!!\n");
        sleep(1); //一秒钟发送一次
    }

    ret = waitpid(-1, &status, 0);
    if (-1 == ret) {
        if (ECHILD == errno) {
            printf("没有需要等待回收的子进程\n");
            exit(0);
        }
        else {
            perror("wait error");
            exit(-1);
        }
    }
   
   printf("回收子进程<%d>, 终止状态<%d>\n", ret, WEXITSTATUS(status));
   


TT:
    /* 关闭套接字 */
    close(sockfd);
    exit(EXIT_SUCCESS);
}

四、编译运行

1、编译命令:

gcc can.c -o can

2、运行命令

./can

3、运行输出效果如下图:
在这里插入图片描述

linux下can通信应用例程测试完毕,上述例程只是一个简单的应用。实际开发过程可能会更加复杂。

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

waterfxw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值