EcellentSNEK666 发表于 2024-8-7 23:04:56

Remi_Pi瑞米派linux开发板的CAN扩展板学习记录_20240807

学习记录
前言:168买了一块瑞米派,因为从事汽车电子行业需要学一下CAN,所以当时为了实操申请了一块瑞米派的CAN扩展版。扩展版是通过SPI通信控制CAN通信从而发送CAN信号。虽然发货很及时,但我的Linux技术有限,在回来的时候CAN已经学会了。后面再拿出来在开发板的Linux系统上实操一下。
扩展版资料需要的在下面链接
2-CH CAN HAT - Waveshare Wiki



这个扩展版兼容树莓派,看教程是有树莓派的c例程和python例程。瑞米派自带系统也有python3的环境,但c例程需要在ubuntu下交叉编译然后移植到开发板然后跑通。



硬件连接,通过对比Remi_Pi电路图与扩展版电路图,定义一致,可以直接连接。

因为我尝试使用c例程,所以放C的例程代码。
思路1:
1.移植交叉编译器
2.在ubuntu下编译c代码,然后移植到开发板跑例程。但是需要两个扩展版,所以可以使用第一个发,想办法再建立一个终端和账号然后运行收的C例程。可以实现自收自发。
思路2:
可以直接调用现有系统的例程和命令,进行CAN发送。目前走的这一条,但是没法接收数据,可以通过连接CAN盒查看收的ID和数据。目前可以发送。

使用linux软件评估文档中的内容,用命令行配置CAN,然后调用系统函数CAN外发。



先把CAN关闭,然后配置为CANFD,然后调用cansend 发送ID为100,数据为11.22.33.44的消息。最后统计CAN0接口的数据,发送16个包,128个字节。证明可以发送。目前手头没有CAN盒,但使用CAN盒必须使用支持CANFD的CAN盒,我使用1610不支持CAN FD 所以下面只放了CAN外发数据的统计内容。



后面是例程的源码,也是同样的调用系统函数和发送信息。但需要先移植交叉编译器再ubuntu系统编译后移植再跑程序。

can_receive.c

#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 ret;
    int s, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;

    memset(&frame, 0, sizeof(struct can_frame));

    system("sudo ip link set can0 type can bitrate 100000");
    system("sudo ifconfig can0 up");
    printf("this is a can receive demo\r\n");

    //1.Create socket
    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (s < 0) {
      perror("socket PF_CAN failed");
      return 1;
    }

    //2.Specify can0 device
    strcpy(ifr.ifr_name, "can0");
    ret = ioctl(s, SIOCGIFINDEX, &ifr);
    if (ret < 0) {
      perror("ioctl failed");
      return 1;
    }

    //3.Bind the socket to can0
    addr.can_family = PF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0) {
      perror("bind failed");
      return 1;
    }

    //4.Define receive rules
    struct can_filter rfilter;
    rfilter.can_id = 0x123;
    rfilter.can_mask = CAN_SFF_MASK;
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

    //5.Receive data and exit
    while(1) {
      nbytes = read(s, &frame, sizeof(frame));
      if(nbytes > 0) {
            printf("can_id = 0x%X\r\ncan_dlc = %d \r\n", frame.can_id, frame.can_dlc);
            int i = 0;
            for(i = 0; i < 8; i++)
                printf("data[%d] = %d\r\n", i, frame.data);
            break;
      }
    }

    //6.Close the socket and can0
    close(s);
    system("sudo ifconfig can0 down");

    return 0;
}


can_send.c

#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 ret;
    int s, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    memset(&frame, 0, sizeof(struct can_frame));

    system("sudo ip link set can0 type can bitrate 100000");
    system("sudo ifconfig can0 up");
    printf("this is a can send demo\r\n");

    //1.Create socket
    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (s < 0) {
      perror("socket PF_CAN failed");
      return 1;
    }

    //2.Specify can0 device
    strcpy(ifr.ifr_name, "can0");
    ret = ioctl(s, SIOCGIFINDEX, &ifr);
    if (ret < 0) {
      perror("ioctl failed");
      return 1;
    }

    //3.Bind the socket to can0
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0) {
      perror("bind failed");
      return 1;
    }

    //4.Disable filtering rules, do not receive packets, only send
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);

    //5.Set send data
    frame.can_id = 0x123;
    frame.can_dlc = 8;
    frame.data = 1;
    frame.data = 2;
    frame.data = 3;
    frame.data = 4;
    frame.data = 5;
    frame.data = 6;
    frame.data = 7;
    frame.data = 8;

    printf("can_id= 0x%X\r\n", frame.can_id);
    printf("can_dlc = %d\r\n", frame.can_dlc);
    int i = 0;
    for(i = 0; i < 8; i++)
      printf("data[%d] = %d\r\n", i, frame.data);

    //6.Send message
    nbytes = write(s, &frame, sizeof(frame));
    if(nbytes != sizeof(frame)) {
      printf("Send Error frame!\r\n");
      system("sudo ifconfig can0 down");
    }

    //7.Close the socket and can0
    close(s);
    system("sudo ifconfig can0 down");
    return 0;
}





页: [1]
查看完整版本: Remi_Pi瑞米派linux开发板的CAN扩展板学习记录_20240807