开发板引出了一路CAN接口,可以用它来做CAN通讯相关的应用程序。
在 Linux 系统中, CAN 总线接口设备作为网络设备被系统进行统一管理。在控制台下, CAN 总线的配置和以太网的配置使用相同的命令。
在控制台输入ifconfig -a
可以查看CAN接口
显示有一路CAN接口can0可用。
另外,可以用相关命令对其进行操作:
线的位速率:
ip link set can0 type cantq 125 prop-seg 6phase-seg1 7 phase-seg2 2 sjw 1
也可以使用 ip 命令直接设定位速率:
ip link set can0 type can bitrate 125000
当设置完成后,可以通过下面的命令查询 can0 设备的参数设置:
ip -details link show can0
当设置完成后,可以使用下面的命令使能 can0 设备:
ifconfig can0 up
使用下面的命令取消 can0 设备使能:
ifconfig can0 down
在设备工作中,可以使用下面的命令来查询工作状态:
ip -details -statistics link show can0
由于系统将 CAN 设备作为网络设备进行管理,因此在 CAN 总线应用开发方面, Linux 提供了SocketCAN 接口,使得 CAN 总线通信近似于和以太网的通信,应用程序开发接口 更加通用, 也更加灵活。
关于Linux的CAN接口编程详细技术文档可以参考如下文章:
https://blog.csdn.net/panfei263031/article/details/122977734
根据开发板用户手册和原理图可以确定CAN接口(TX,RX)的位置:
在正式开始之前,需要设置设置一下系统启动脚本,否则使用过程中会存在一些问题。
参考用户手册的CAN章节,需要修改/etc/rc.local文件,添加对CAN的配置:
本次应用程序将实现如下功能:
1、循环发送CAN数据帧,ID:0x12,DLC:4,data:01 02 03 04 ,每秒一次
2、以非阻塞的方式周期性读取CAN数据,若接收到数据则把数据打印出来
源代码如下:
#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 <fcntl.h>
int main(void)
{
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
struct can_frame frame = {0};
struct can_filter rfilter;
int loopback = 0;//1-开启回环模式,0-关闭回环模式
int sockfd = -1;
int ret;
/* 打开套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (sockfd < 0)
{
printf("socket error\r\n");
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 (ret < 0)
{
printf("bind error\r\n");
close(sockfd);
exit(EXIT_FAILURE);
}
/* 设置read函数的非阻塞 */
fcntl(sockfd, F_SETFL, FNDELAY);
/* 设置过滤规则 */
rfilter.can_id = 0x12;
rfilter.can_mask = 0x7FF;
//设置过滤器
//setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
/* 设置回环模式 */
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
int ro = 0;
//设置接收自己的消息
//setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &ro, sizeof(ro));
/* 发送数据 */
frame.data[0] = 0x01;
frame.data[1] = 0x02;
frame.data[2] = 0x03;
frame.data[3] = 0x04;
frame.can_dlc = 4;
frame.can_id = 0x12;
while(1)
{
printf("CAN data write\r\n");
ret = write(sockfd, &frame, sizeof(frame));//发送数据
if(ret != sizeof(frame))
{
printf("write error,ret = %d\r\n",ret);
break;
}
sleep(1);
printf("CAN data read\r\n");
struct can_frame rec_frame;
if(read(sockfd, &rec_frame, sizeof(struct can_frame)) > 0)//读取数据
{
char temp[50];
for(int i = 0; i < rec_frame.can_dlc; i++)
{
sprintf(&temp[i * 3], "%02x ", rec_frame.data[i]);
}
printf("recv message :ID:0x%x, DLC:%d, data:%s\r\n", rec_frame.can_id, rec_frame.can_dlc, temp);
}
}
close(sockfd);
exit(EXIT_SUCCESS);
}
开发板运行can_test程序,并使用USB转CAN工具连接开发板,使用PC工具进行can数据的接收和发送。
PC端接收开发板发送的数据:
开发板接收PC端发送的数据:
根据实验结果说明开发板的CAN数据收发是成功的,达到了预期的效果。
由此可见,Linux下的CAN编程与网络编程非常相似,极大的简化了CAN的应用程序编程。
更多回帖