这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【FRDMDEVBOARDFORI.MX91测评】过程贴——CAN的使用

共2条 1/1 1 跳转至

【FRDMDEVBOARDFORI.MX91测评】过程贴——CAN的使用

菜鸟
2026-05-09 15:18:25     打赏

2过程贴——CAN的使用

本次来使用CAN,先看接口,位于P12的8和10引脚。而且SW3也要拨到ON。

image.png

将开发板的与vecory连接,用来测试。

关于can接口的驱动,我在网上找到大佬的使用记录,使用socket驱动can,拿c语言实现的,详细帖子:https://bbs.eeworld.com.cn/thread-1337184-1-1.html

大佬的代码粘贴过来就能用,但是我的项目里想用python+网页展示效果,所以我将大佬的c代码简化,留出了接口,让python来实现应用逻辑,底层调用由c实现。代码如下:

canlib.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>
 #include <stdint.h>
 #include <errno.h>
 #include <fcntl.h>
 
 /********************供python使用***************************/
 int can_init(void);
 int recive_can_data(unsigned int* id,unsigned char* len,unsigned char data[]);
 /*
 * 首先,需要编译C库:gcc -shared -fPIC -o canlib.so canlib.c
 * 使用详情见can.py文件
 */
 /***********************************************************/
 
 
 
 const char* ifname = "can0";  // 默认CAN接口
 int bitrate = 500000;         // 默认波特率 500kbps
 int sock;
 
 int create_can_socket(void);
 void cleanup_can_interface(const char *ifname);
 
 /***********************************************************************
 *@功能: CAN 接口配置 - 设置和启用CAN接口
 
 *@返回值: 成功返回1, 失败返回0
 *@说明:
 **********************************************************************/
 int can_init(void) 
 {
     char cmd[256];
     
     printf("设置CAN接口: %s, 波特率: %d\n", ifname, bitrate);
     
     // 1. 首先关闭接口
     snprintf(cmd, sizeof(cmd), "ip link set %s down", ifname);
     if (system(cmd) != 0) {
         fprintf(stderr, "警告: 无法关闭CAN接口 %s\n", ifname);
     }
     
     // 2. 设置波特率
     if (bitrate > 0) {
         snprintf(cmd, sizeof(cmd), 
                  "ip link set %s type can bitrate %d", 
                  ifname, bitrate);
         if (system(cmd) != 0) {
             fprintf(stderr, "错误: 无法设置波特率\n");
             return 0;
         }
     }
     
     // 3. 启用接口
     snprintf(cmd, sizeof(cmd), "ip link set %s up", ifname);
     if (system(cmd) != 0) {
         fprintf(stderr, "错误: 无法启用CAN接口\n");
         return 0;
     }
     
     // 4. 设置发送队列长度 (可选,但建议设置)
     snprintf(cmd, sizeof(cmd), 
              "ifconfig %s txqueuelen 1000", ifname);
     system(cmd);
     
     // 5. 显示接口状态
     snprintf(cmd, sizeof(cmd), "ip -details link show %s", ifname);
     printf("CAN接口状态:\n");
     system(cmd);
     
     // 等待接口稳定
     usleep(500000);
 
     //创建CAN套接字
     int sock;
     sock = create_can_socket();
     if (sock < 0) {
         fprintf(stderr, "CAN套接字创建失败\n");
         cleanup_can_interface(ifname);
         return 0;
     }
     
     return 1;
 }
 
 void send_can_data(int sock)
 {
     struct can_frame frame;
     static uint8_t pid_index = 0;
     memset(&frame, 0, sizeof(frame));
 
     // 设置 CAN 帧
     frame.can_id = 0x7DF;
     frame.can_dlc = 8;
     frame.data[0] = 0x02;               // 数据长度 (2个数据字节)
     
     // 发送 CAN 帧
     ssize_t sent = write(sock, &frame, sizeof(frame));
     if (sent != sizeof(frame)) {
         if (sent < 0) {
             perror("CAN 发送失败");
         } else {
             fprintf(stderr, "警告: 部分数据发送: %ld/%ld\n", 
                     sent, sizeof(frame));
         }
     }
 }
 
 /***********************************************************************
 *@函数名: cleanup_can_interface
 *@功能: 清理CAN接口
 *@参数: ifname CAN接口名
 *@返回值: 无
 *@说明:
 **********************************************************************/
 void cleanup_can_interface(const char *ifname)
 {
     char cmd[256];
     
     printf("清理CAN接口: %s\n", ifname);
     
     // 关闭CAN接口
     snprintf(cmd, sizeof(cmd), "ip link set %s down", ifname);
     system(cmd);
 }
 
 /***********************************************************************
 *@函数名: create_can_socket
 *@功能: 创建并配置CAN套接字
 *@返回值: 成功返回套接字描述符,失败返回-1
 *@说明:
 **********************************************************************/
 int create_can_socket(void)
 {
     struct ifreq ifr;
     struct sockaddr_can addr;
     
     // 创建 CAN 套接字
     sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
     if (sock < 0) {
         perror("套接字创建失败");
         return -1;
     }
     
     // 获取接口索引
     strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
     ifr.ifr_name[IFNAMSIZ - 1] = '\0';
     
     if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
         perror("获取接口索引失败");
         close(sock);
         return -1;
     }
     
     printf("接口 %s 索引: %d\n", ifname, ifr.ifr_ifindex);
     
     // 绑定 CAN 接口
     memset(&addr, 0, sizeof(addr));
     addr.can_family = AF_CAN;
     addr.can_ifindex = ifr.ifr_ifindex;
     
     if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
         perror("绑定失败");
         close(sock);
         return -1;
     }
     
     // 设置非阻塞模式
     int flags = fcntl(sock, F_GETFL, 0);
     if (flags >= 0) {
         fcntl(sock, F_SETFL, flags | O_NONBLOCK);
     }
     
     return sock;
 }
 int recive_can_data(unsigned int* id,unsigned char* len,unsigned char data[])
 {
     fd_set read_fds;
     struct timeval timeout;
     int ret;
     // 设置超时
     timeout.tv_sec = 0;
     timeout.tv_usec = 10000;  // 10ms超时
     
     FD_ZERO(&read_fds);
     FD_SET(sock, &read_fds);
     
     ret = select(sock + 1, &read_fds, NULL, NULL, &timeout);
     
     if (ret > 0) {
         struct can_frame frame;
         ssize_t bytes_read;
         
         // 读取CAN帧
         bytes_read = read(sock, &frame, sizeof(frame));
         
         if (bytes_read > 0) {
             // printf("接收到CAN帧: ID=0x%X, DLC=%d\n", frame.can_id, frame.can_dlc);
             *id = frame.can_id;
             *len = frame.can_dlc;
             memcpy(data,frame.data,frame.can_dlc);
             return 0;
         } else if (bytes_read == 0) {
             printf("CAN连接关闭\n");
         } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
             perror("读取CAN帧失败");
         }
     } else if (ret == 0) {
         // printf("等待响应超时\n");
     } else {
         perror("select失败");
     }
     return 1;
 }
 /***********************************************************************
 *@函数名: main
 *@功能: 主函数
 *@参数: argc 参数个数
 *       argv 参数数组
 *@返回值: 程序退出码
 *@说明:
 **********************************************************************/
 // int main(int argc, char* argv[])
 int main_lib(int argc, char* argv[])
 {
     if (!can_init()) {
         fprintf(stderr, "CAN接口设置失败\n");
         return 1;
     }
     printf("成功连接到 %s\n", ifname);
     
     // 3. 主循环
     while (1) {
 
         unsigned int id;
         unsigned char len;
         unsigned char data[8];
         // 发送can
         send_can_data(sock);
         if(!recive_can_data(&id,&len,data)) {
             printf("接收到CAN帧: ID=0x%X, DLC=%d\n", id, len);
         }
         
         // 等待2秒再发送下一个请求
         usleep(30000);
     }
     return 0;
 }
 
 //gcc  canlib.c -o canlib.out

在shell中编译这个c文件:

gcc -shared -fPIC -o canlib.so canlib.c

在py中调用:

这部分请移步成果贴。

本节主要实现了can初始化,发送,接收。其中初始化和接收可以被python调用。



院士
2026-05-10 16:30:57     打赏
2楼

学习了,谢谢分享。


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]