文章目录
CAN总线通讯正常模式
在第六篇中已经完成了,can0自己接收自己发送的报文。
功能描述以及接线
功能描述
这里以can0和can1作为两个can设备,两者之间进行通讯。can0发送的报文ID是0x123,内容是从0x01自增;can1发送的报文ID是0x456内容是从0x66自增。
查看原理图,可以知道can0,can1内部集成了can的收发器,can0,can1可以直接挂载到can总线上通讯,这里可以直接,并联起来直接通讯,没有can收发器的设备则需要连接一个can收发器,再挂载到can总线上。:
接线
硬件接线:因为是差分信号,不用数字共地,直接将CAN0_H和CAN1_H接起来,CAN0_L和CAN1_L接起来。
先借助CAN总线调试器单方调通
can0调试
借助can总线调试器,与can0通讯。
接线
代码
代码跟之前的can0 回环测试一模一样。这里把禁用回环模式,禁用监听自己的消息打开。最好打开以下哈,不打开也是可以的。
#include "can_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <libgen.h>
#include <getopt.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
/*
1. 确认硬件支持(一般都支持)
ip link show type can
2.关闭can0接口
ip link set can0 down
3. 配置 CAN0 接口设置波特率
ip link set can0 type can0 bitrate 500000
4.关闭回环模式(默认正常模式)
ip link set can0 type can loopback off
5.启动can0
ip link set can0 up
6.查看can0接口是否启动成功
ip -details link show can0
*/
// 使用 SocketCAN API 编写应用程序
int main()
{
int s; // 就是fd
int n_read = 0; // 读取到的数据个数
//创建 CAN 套接字
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("Socket creation failed");
return -1;
}
printf("socket ok ========================\n");
// 禁用回环模式(如果需要)
int loopback = 0; // 0 表示关闭回环模式
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback)) < 0) {
perror("Failed to disable loopback mode");
close(s);
return -1;
}
// 禁用监听自己的消息(可选)
int recv_own_msgs = 0; // 0 表示关闭接收自己的消息
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs)) < 0) {
perror("Failed to disable receiving own messages");
close(s);
return -1;
}
// 绑定 CAN 接口
struct ifreq ifr;
struct sockaddr_can addr;
addr.can_family = AF_CAN;
strcpy(ifr.ifr_name, "can0");
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("Interface index get failed");
close(s);
return -1;
}
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Bind to CAN interface failed");
close(s);
return -1;
}
printf("bind ok ========================\n");
// 构造要发送的 CAN 帧
struct can_frame wirte_frame;
struct can_frame recive_frame;
wirte_frame.can_id = 0x123; // CAN ID
wirte_frame.can_dlc = 8; // 数据长度码(DLC),表示数据域的字节数
memset(wirte_frame.data, 0x01, wirte_frame.can_dlc); // 设置数据域内容
int data = 0x01;
//开启线程 一个接收一个发送;
__pid_t pid