ARM40-A5D27应用程序——CAN总线应用程序示例
本文为CAN总线应用程序示例,测试板为ARM40-A5D27.
一、在shell中测试
把can0的TX与CAN1的TX连接,CAN0的RX和CAN1的RX连接,然后:
# ifconfig can0 down
//配置can0的波特率为250Kbps
# ip link set can0 type can bitrate 250000
# ifconfig can0 up
# ifconfig can1 down
//配置can1的波特率为250Kbps
# ip link set can1 type can bitrate 250000
# ifconfig can1 up
# candump can1 & // 将CAN1设置为接收(后台接收)
# cansend can0 5A1#11.2233.44556677.88 // CAN0发数据
二、CAN总线发送/接收C代码
CAN总线发送,文件名为 test_canrecv.c,代码见本文附录(1)。
CAN总线接收,文件名为 test_cansend.c,代码见本文附录(2)。
三、交叉编译
arm-linux-gnueabihf-gcc -o test_canrecv test_canrecv.c
arm-linux-gnueabihf-gcc -o test_cansend test_cansend.c
四、执行程序
将ARM40-A5D27的CAN总线连接到PC(周立功USB CAN盒子),设置PC端USBCAN波特率为250k.
配置如下:
# ifconfig can0 down
//配置can0的波特率为250Kbps
# ip link set can0 type can bitrate 250000
# ifconfig can0 up
4.1、CAN总线接收测试:
//在PC端周立功USB CAN上发送数据,ARM40-A5D27上可以接收到数据
# ./test_canrecv
### 4.2、CAN总线发送测试:
//在ARM40-A5D27上发送数据,在PC端周立功USB CAN上可以接收到数据
# ./test_cansend
参考文章:
http://lxr.linux.no/linux+v2.6.34/Documentation/networking/can.txt
Low Level CAN Framework Application Programmers Interface
http://www.emtronix.com/article/article2013603.html
https://blog.csdn.net/jirryzhang/article/details/79417986
http://velep.com/archives/1181.html
http://blog.chinaunix.net/uid-13889805-id-3072479.html
https://github.com/linux-can/can-utils
荟聚计划:共商 共建 共享 Grant
附:
(1)test_canrecv.c 的代码
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/sockios.h>
#include <linux/if.h>
int main( int argc,char* argv[] )
{
int i, ret;
int nbytes;
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
char *interface = "can0";
int can_fd = -1;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame_rev;
printf("SocketCAN Test V1.0\n");
can_fd = socket(family, type, proto); // 创建SocketCAN 套接字
printf("SOCK_RAW can sockfd:%d\n", can_fd);
if( can_fd < 0 )
{
perror("socket");
return can_fd;
}
int loopback = 0; // 0 = disabled, 1 = enabled (default)
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
strcpy(ifr.ifr_name, interface); // 指定 can0 设备 strcpy(ifr.ifr_name, "can0" );
ret = ioctl(can_fd, SIOCGIFINDEX, &ifr); // 指定 can0 设备
if(ret) {
perror("ioctl:interface");
goto abort;
}
addr.can_family = family;
addr.can_ifindex = ifr.ifr_ifindex;
ret = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr)); // 将套接字与 can0 绑定
if (ret) {
perror("bind\n");
goto abort;
}
// 设置过滤规则,只接收表示符等于 0x123 的报文,如果没有这段,则接受所有报文
struct can_filter rfilter;
rfilter.can_id = 0x123;
rfilter.can_mask = CAN_SFF_MASK; // #define CAN_SFF_MASK 0x000007FFU
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); //设置过滤规则
/*
在极端情况下,如果应用程序不需要接收报文,可以禁用过滤规则。这样的话,原始套接字就会忽略所有接收到的报文。在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少 CPU 资源的消耗。禁用方法如下:
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); //禁用过滤规则
*/
memset(&frame_rev,0x0,sizeof(frame_rev));
while(1) {
nbytes = read(can_fd, &frame_rev, sizeof(frame_rev)); //接收报文
if(nbytes < 0){
perror("read");
goto abort;
}
if(nbytes < sizeof(struct can_frame)){
printf("read:incomplete can frame\n");
goto abort;
}
printf("ID=0x%X,DLC=%d",frame_rev.can_id,frame_rev.can_dlc); //显示报文
for(i=0; i<frame_rev.can_dlc; i++)
printf(",data[%d]=%x", i,frame_rev.data[i]);
printf("\n");
memset(&frame_rev,0x0,sizeof(frame_rev));
}
close(can_fd);
return 0;
abort:
close(can_fd);
return ret;
}
(2)test_cansend.c 的代码
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/sockios.h>
#include <linux/if.h>
int main( int argc,char* argv[] )
{
int i, ret;
int nbytes;
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
char *interface = "can0";
int can_fd = -1;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame_send;
printf("SocketCAN Test V1.0\n");
can_fd = socket(family, type, proto); // 创建SocketCAN 套接字
printf("SOCK_RAW can sockfd:%d\n", can_fd);
if( can_fd < 0 )
{
perror("socket");
return can_fd;
}
int loopback = 0; // 0 = disabled, 1 = enabled (default)
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
strcpy(ifr.ifr_name, interface); // 指定 can0 设备 strcpy(ifr.ifr_name, "can0" );
ret = ioctl(can_fd, SIOCGIFINDEX, &ifr); // 指定 can0 设备
if(ret)
{
perror("ioctl:SIOCGIFINDEX");
goto abort;
}
addr.can_family = family;
addr.can_ifindex = ifr.ifr_ifindex;
ret = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr)); // 将套接字与 can0 绑定
if(ret) {
perror("bind\n");
goto abort;
}
/* // 发送一个字节的情况
frame_send.can_id = 0x00;
frame_send.can_dlc = 1;
frame_send.data[0] = 'Y';
*/
frame_send.can_id = 0x123;
frame_send.can_dlc = 8; // 发送8个字节,一次最多发8个字节
for(i=0; i<8; ++i) {
frame_send.data[i] = i;
}
//strncpy(frame_send.data,"12345678",8);
nbytes = write(can_fd, &frame_send, sizeof(frame_send)); //发送
if(nbytes <0 ){
perror("write");
goto abort;
}
// 打印发送的字节
printf("write %d bytes frame:can_id=0x%x,can_dlc=%d\n", i,frame_send.can_id,frame_send.can_dlc);
for(i=0; i<frame_send.can_dlc; i++)
printf(",data[%d]=%x", i,frame_send.data[i]);
printf("\n");
close(can_fd);
return 0;
abort:
close(can_fd);
return ret;
}