瑞芯微(EASY EAI)RV1126B CAN使用

1. CAN简介

使用Socket CAN的主要目的就是为用户空间的应用程序提供基于Linux网络层的套接字接口。与广为人知的TCP/IP协议以及以太网不同,CAN总线没有类似以太网的MAC层地址,只能用于广播。CAN ID仅仅用来进行总线的仲裁。因此CAN ID在总线上必须是唯一的。当设计一个CAN-ECU(Electronic Control Unit 电子控制单元)网络的时候,CAN报文ID可以映射到具体的ECU。因此CAN报文ID可以当作发送源的地址来使用。

1.1 开发板的CAN资源

1.2 硬件连接

通常由CPU出来的CAN信号是TTL信号,并不是差分信号。因此需要一个CAN TTL信号转CAN差分信号的模块。其具体的接线图如下所示。

2. 快速上手

2.1 开发环境准备

如果您初次阅读此文档,请阅读《入门指南/开发环境准备/Easy-Eai编译环境准备与更新》,并按照其相关的操作,进行编译环境的部署

在PC端Ubuntu系统中执行run脚本,进入EASY-EAI编译环境,具体如下所示。

复制代码
cd ~/develop_environment
./run.sh

2.2 源码下载以及例程编译

首先,在虚拟机后台终端,执行以下命令,创建外设单例源码管理目录:

复制代码
cd /opt
mkdir -p EASY-EAI-Nano-TB/demo

首先,到【百度网盘】上下载相关的单例程序:

链接:https://pan.baidu.com/s/1Br608Hiff2Xs65PzWO_qWQ?pwd=1234

提取码:1234

比如把单例程序下载到:此电脑\D:\BaiduNetdisk (无规定,用户可自主选择),如下图所示。

再将下载好的单例复制进入虚拟机的文件系统,过程如下图所示。

最后,进入到对应的例程目录执行编译操作,具体命令如下所示:

复制代码
cd EASY-EAI-Nano-TB/demo/11_CAN
./build.sh

注:

* 由于依赖库部署在板卡上,因此交叉编译过程中必须保持/mnt挂载。

编译成功后,会生成2个demo,一个是发送端:test-can_send,另一个是接收端:test-can_reception。并会自动部署到开发板的/userdata/目录中。

* 此例程需要2个板卡做收发测试,所以2个板卡都需要重复上述操作。

2.3 例程运行

通过串口调试ssh调试,进入板卡后台,定位到例程部署的位置,如下所示:

复制代码
cd /userdata

首先在一台板卡上运行发送端,运行命令如下:

复制代码
sudo ./test-can-send

然后【再在另外一台】板卡上,运行接收端,运行命令如下:

复制代码
cd /userdata
sudo ./test-can-reception

【接收端】执行效果如下所示。

API的详细说明,以及API的调用(本例程源码),详细信息见下方说明。

3. CAN操作API说明

3.1 创建socketcan套接字操作

创建socketcan套接字操作函数原型如下所示。

复制代码
int socket(int domain, int type, int protocol);

具体介绍如下所示。

3.2 指定本地网络接口地址操作

指定本地网络接口地址函数原型如下所示。

复制代码
int ioctl(int fd, unsigned long request, ...);

具体介绍如下所示。

3.3 绑定地址结构操作

绑定地址结构函数原型如下所示。

复制代码
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

具体介绍如下所示。

3.4 设置CAN过滤器操作

设置CAN过滤器操作函数原型如下所示。

复制代码
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 

3.5 CAN定义报文格式操作

CAN定义报文格式如下所示。

4. CAN通信例程

【发送端】例程源码为11_CAN/test-can_send/main.c,操作流程如下。

【接收端】例程源码为11_CAN/test-can_send/main.c,操作流程如下。

参考例程如下所示。

发送端例程:

复制代码
/* 将CAN0波特率设置为500000 bps */
#define ip_cmd_set_can_params  "ip link set can0 type can bitrate 500000 triple-sampling on"
 /* 打开CAN0 */
#define ip_cmd_open            "ifconfig can0 up"     
 /* 关闭CAN0 */    
#define ip_cmd_close           "ifconfig can0 down"   
 int main() 
 { 
 	int fd, nbytes; 
	struct sockaddr_can addr; 
	struct ifreq ifr; 
	struct can_frame frame[2] = {{0}}; 
	system(ip_cmd_close);
     system(ip_cmd_set_can_params);
	system(ip_cmd_open);
	fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建套接字 
	strcpy(ifr.ifr_name, "can0" ); 
	ioctl(fd, SIOCGIFINDEX, &ifr); //指定 can0 设备 
	addr.can_family = AF_CAN; 
	addr.can_ifindex = ifr.ifr_ifindex; 
	bind(fd, (struct sockaddr *)&addr, sizeof(addr));//将套接字与 can0 绑定 
	//禁用过滤规则,本进程不接收报文,只负责发送 
	setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); 
	//生成两个报文 
	frame[0].can_id = 0x11; 
	frame[0]. can_dlc = 1; 
	frame[0].data[0] = 'Y'; 
	frame[1].can_id = 0x22; 
	frame[1]. can_dlc = 1; 
	frame[1].data[0] = 'N'; 
	//循环发送两个报文 
	while(1) 
	{ 
	    nbytes = write(fd, &frame[0], sizeof(frame[0])); //发送 frame[0] 
         printf("write ret:%d",nbytes);
		if(nbytes != sizeof(frame[0])) {
			printf("Send Error frame[0]\n!"); 
			break; //发送错误,退出 
	 	} 
		 sleep(1); 
		nbytes = write(fd, &frame[1], sizeof(frame[1])); //发送 frame[1] 
		if(nbytes != sizeof(frame[1])) {
			printf("Send Error frame[1]\n!"); 
			break; 
	 	} 
		sleep(1); 
	} 
	 close(fd); 
	 return 0; 
}

接收端例程:

复制代码
/* 将CAN0波特率设置为500000 bps */
#define ip_cmd_set_can_params  "ip link set can0 type can bitrate 500000 triple-sampling on"
 /* 打开CAN0 */
#define ip_cmd_open            "ifconfig can0 up"     
 /* 关闭CAN0 */    
#define ip_cmd_close           "ifconfig can0 down"   
 int main() 
 { 
	 int fd, nbytes; 
	 struct sockaddr_can addr; 
	 struct ifreq ifr; 
	 struct can_frame frame; 
	 struct can_filter rfilter[1];
	 system(ip_cmd_close);
    	 system(ip_cmd_set_can_params);
	 system(ip_cmd_open);
	 fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建套接字 
	 strcpy(ifr.ifr_name, "can0" ); 
	 ioctl(fd, SIOCGIFINDEX, &ifr); //指定 can0 设备 
	 addr.can_family = AF_CAN; 
	 addr.can_ifindex = ifr.ifr_ifindex; 
	 bind(fd, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与 can0 绑定 
	 //定义接收规则,只接收表示符等于 0x11 的报文 
	 rfilter[0].can_id = 0x11; 
	 rfilter[0].can_mask = CAN_SFF_MASK; 
	 //设置过滤规则 
	 setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); 
	 while(1)
	 { 
		 nbytes = read(fd, &frame, sizeof(frame)); //接收报文 
		//显示报文 
		 if(nbytes > 0) {
			 printf("ID=0x%X DLC=%d data[0]=0x%X\n", frame.can_id, frame.can_dlc, frame.data[0]); 
		 } 
	} 
	close(fd); 
	return 0; 
}
相关推荐
CSDN官方博客7 分钟前
「谁说嵌入式只是调包和焊板子?」—— 2026嵌入式全栈技术征锋令
嵌入式硬件·物联网·embedding
点灯小铭40 分钟前
基于单片机的数码管定时插座设计与定时开关功能实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
凡人叶枫1 小时前
Effective C++ 条款04:确定对象被使用前已先被初始化
java·linux·开发语言·c++·嵌入式开发
云栖梦泽1 小时前
玩转RK3506SDK
linux·嵌入式硬件
智慧光迅AINOPOL1 小时前
校园在线巡课系统方案:督导全覆盖
网络·全光网解决方案·全光网·校园全光网·校园全光网解决方案
Java面试题总结1 小时前
Linux-Ubantu-贴士-apt的地盘
linux·运维·服务器
酉鬼女又兒2 小时前
零基础入门计算机网络:网络层核心任务、三大关键问题、两种服务类型与 TCP/IP 网际层协议体系全解析
服务器·网络·网络协议·tcp/ip·计算机网络·php·求职招聘
Urbano2 小时前
工装制作全流程科普:从面料到自动化生产
网络·人工智能
kong@react2 小时前
Rocky Linux 10.2 全面解析:企业级 CentOS 替代方案及保姆级docker安装
java·linux·运维·docker
2401_868534782 小时前
网规笔记 | 真题解析:2018年11月软考网规-网络安全案例分析
网络