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

将开发板的与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调用。
我要赚赏金
