学习记录
前言:168买了一块瑞米派,因为从事汽车电子行业需要学一下CAN,所以当时为了实操申请了一块瑞米派的CAN扩展版。扩展版是通过SPI通信控制CAN通信从而发送CAN信号。虽然发货很及时,但我的Linux技术有限,在回来的时候CAN已经学会了。后面再拿出来在开发板的Linux系统上实操一下。
需要的在下面链接
2-CH CAN HAT - Waveshare Wikihttps://www.waveshare.net/wiki/2-CH_CAN_HAT
这个扩展版兼容树莓派,看教程是有树莓派的c例程和python例程。瑞米派自带系统也有python3的环境,但c例程需要在ubuntu下交叉编译然后移植到开发板然后跑通。
因为我尝试使用c例程,所以放C的例程代码。
思路1:
1.移植交叉编译器
2.在ubuntu下编译c代码,然后移植到开发板跑例程。但是需要两个扩展版,所以可以使用第一个发,想办法再建立一个终端和账号然后运行收的C例程。可以实现自收自发。
思路2:
可以直接调用现有系统的例程和命令,进行CAN发送。目前走的这一条,但是没法接收数据,可以通过连接CAN盒查看收的ID和数据。目前可以发送。
先把CAN关闭,然后配置为CANFD,然后调用cansend 发送ID为100,数据为11.22.33.44的消息。最后统计CAN0接口的数据,发送16个包,128个字节。证明可以发送。目前手头没有CAN盒,但使用CAN盒必须使用支持CANFD的CAN盒。
后面是例程的源码,也是同样的调用系统函数和发送信息。但需要先移植交叉编译器再ubuntu系统编译后移植再跑程序。
can_receive.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>
int main()
{
int ret;
int s, nbytes;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
memset(&frame, 0, sizeof(struct can_frame));
system("sudo ip link set can0 type can bitrate 100000");
system("sudo ifconfig can0 up");
printf("this is a can receive demo\r\n");
//1.Create socket
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("socket PF_CAN failed");
return 1;
}
//2.Specify can0 device
strcpy(ifr.ifr_name, "can0");
ret = ioctl(s, SIOCGIFINDEX, &ifr);
if (ret < 0) {
perror("ioctl failed");
return 1;
}
//3.Bind the socket to can0
addr.can_family = PF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
perror("bind failed");
return 1;
}
//4.Define receive rules
struct can_filter rfilter[1];
rfilter[0].can_id = 0x123;
rfilter[0].can_mask = CAN_SFF_MASK;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
//5.Receive data and exit
while(1) {
nbytes = read(s, &frame, sizeof(frame));
if(nbytes > 0) {
printf("can_id = 0x%X\r\ncan_dlc = %d \r\n", frame.can_id, frame.can_dlc);
int i = 0;
for(i = 0; i < 8; i++)
printf("data[%d] = %d\r\n", i, frame.data[i]);
break;
}
}
//6.Close the socket and can0
close(s);
system("sudo ifconfig can0 down");
return 0;
}
can_send.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>
int main()
{
int ret;
int s, nbytes;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
memset(&frame, 0, sizeof(struct can_frame));
system("sudo ip link set can0 type can bitrate 100000");
system("sudo ifconfig can0 up");
printf("this is a can send demo\r\n");
//1.Create socket
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("socket PF_CAN failed");
return 1;
}
//2.Specify can0 device
strcpy(ifr.ifr_name, "can0");
ret = ioctl(s, SIOCGIFINDEX, &ifr);
if (ret < 0) {
perror("ioctl failed");
return 1;
}
//3.Bind the socket to can0
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
perror("bind failed");
return 1;
}
//4.Disable filtering rules, do not receive packets, only send
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
//5.Set send data
frame.can_id = 0x123;
frame.can_dlc = 8;
frame.data[0] = 1;
frame.data[1] = 2;
frame.data[2] = 3;
frame.data[3] = 4;
frame.data[4] = 5;
frame.data[5] = 6;
frame.data[6] = 7;
frame.data[7] = 8;
printf("can_id = 0x%X\r\n", frame.can_id);
printf("can_dlc = %d\r\n", frame.can_dlc);
int i = 0;
for(i = 0; i < 8; i++)
printf("data[%d] = %d\r\n", i, frame.data[i]);
//6.Send message
nbytes = write(s, &frame, sizeof(frame));
if(nbytes != sizeof(frame)) {
printf("Send Error frame[0]!\r\n");
system("sudo ifconfig can0 down");
}
//7.Close the socket and can0
close(s);
system("sudo ifconfig can0 down");
return 0;
}