1.引言
CAN总线由于其高可靠性,被广泛的应用在汽车电子及工业领域。生活中常见的一个使用CAN的地方是汽车OBD接口,它一般位于汽车方向盘的左下角,是一个16针的插座,其中里面就有一个CAN接口,可以用来查看汽车的刹车、转向、故障信息等。单片机或处理器上如果有CAN控制器,外围再搭配一个CAN收发器,就可以进行通信了。本篇对Linux下CAN使用做个简单总结,希望对大家有所帮助。
![a85695d75a7186393681da974e3f6c7e.png](https://i-blog.csdnimg.cn/blog_migrate/3543ecbe537f1a418f7c70130be5f804.jpeg)
2.环境介绍
2.1.硬件
1) NUC972开发板
2) CAN相关电路
![cbe5a7f19a72524eeed34b42da78db43.png](https://i-blog.csdnimg.cn/blog_migrate/a1da56cd90e449455c48511f1470fa64.jpeg)
为了进行后面的实验,将CAN0的H和CAN1的H,CAN0的L和CAN1的L分别短接起来。
结合我之前遇到的实际问题,对上面电路做两点说明:
i)从处理器芯片CAN控制器出来的两个引脚TX和RX,和CAN收发器的TX(上图收发器芯片的1脚D)和RX(上图收发器芯片的4脚R)是直连的,就是TX连接TX,RX连接RX,千万别把TX和RX连接在一起了,这个和串口里的交叉连接不是一回事。当年就因为这个小问题,我在一个客户那里折腾了老半天。
ii) 收发器出来的CANH和CANL之间有一个120欧姆电阻,CAN总线结构如下,这个120欧姆电阻只需要在两侧的节点上加就行,用来保证整个总线的阻抗匹配。这个得注意,虽然有时不加也能通信,但是还是得按照CAN总线的要求加上,不然通信会不稳定的。
![dc603c01df14e1fb3b34e8ba387a1b4b.png](https://i-blog.csdnimg.cn/blog_migrate/d3a46457fa79bbfe09330221852b94a1.jpeg)
2.2.软件
1) Uboot继续使用之前文章用的,无需改动。
2) Kernel在上一篇基础上,要做一定的修改。
3) Rootfs在上一篇用Buildroot生成的基础上,要做一定的修改。
3.内核配置
· 内核CAN配置
![e3d8f57dac2e1ef939dad3d77404d4d3.png](https://i-blog.csdnimg.cn/blog_migrate/00d4f189dceeb3dd66f562e51bf3e89e.jpeg)
![1b3399be53aac8db5630099dc6d92cd7.png](https://i-blog.csdnimg.cn/blog_migrate/249ce4a0b78bc417ec626fc04504d1fb.jpeg)
4.Buildroot配置
· iproute2配置
![d3ef5a1e53e88f5df5ed4f2203354636.png](https://i-blog.csdnimg.cn/blog_migrate/c8104bbf44265e45afa5aad0d6197edc.jpeg)
· 使能can-utils工具,用来支持candump/cansend命令
![55fb6609850649014922fcc455329ee6.png](https://i-blog.csdnimg.cn/blog_migrate/3f8ebb2ed774664ea333b9d818473bc9.jpeg)
· socketcand配置
![56a40b143dcee4f81205021770094fd6.png](https://i-blog.csdnimg.cn/blog_migrate/b24555e0aa0329ebe570ad328e10f443.jpeg)
5.收发测试
5.1.命令行调试
将上述修改后的内核和文件系统下载到板子里启动后,
1) ifconfig -a 查看全部接口,可以看到can0和can1接口
![754924f4b755a7d70ae575d12c075374.png](https://i-blog.csdnimg.cn/blog_migrate/03ce1faf0b6b74e6575a60130be028b2.jpeg)
2) 输入下面两条指令
ip link set can0 up type can bitrate 500000ip link set can1 up type can bitrate 500000
![0e6f2605461fba53ff9783eb65b29d9d.png](https://i-blog.csdnimg.cn/blog_migrate/29eac9a382a0c8f641e7ccd0278f8d47.jpeg)
ifconfig 可以看到两个can接口
![f1300e83bec37cb8150fa2f6f5b027d0.png](https://i-blog.csdnimg.cn/blog_migrate/e7b6a6aa3e938e51aa0b9dc570858a3a.jpeg)
下面的两条指令完成can0接收,can1发送,可以看到收发正常
candump can0 &cansend can1 888#11223344
![9d1b6a9451544ed72e17099d7a84176c.png](https://i-blog.csdnimg.cn/blog_migrate/b7892a90e434b467998f3556d5b98efd.jpeg)
如果也让can1接收,通过can0或者can1发送,两个can口都可以接收到数据。
![d9fbb98d985bf3c0271ce46b19334176.png](https://i-blog.csdnimg.cn/blog_migrate/df9c50a63af4498175d4201bdc95ed85.jpeg)
5.2.C代码实现
1) 代码实现的功能是,先通过can0发送一串数据,然后不断接收数据并打印。
2)执行can_demo程序,可以看到can1会收到can0发送的数据
![438b7dcf31fd49110617fdd0087a20d3.png](https://i-blog.csdnimg.cn/blog_migrate/dda225f551ac506c9700b1cd620ed19e.jpeg)
如果通过cansend can1 12345678#1122334455 发送数据
![2cd5f7f1ea1f832ebe3d6e472b483b01.png](https://i-blog.csdnimg.cn/blog_migrate/078383bf385d4d9801f0cac4b59aa432.jpeg)
程序会打印出接收到的数据:
![35ae11d412f1a1f1f95ff56832082b6f.png](https://i-blog.csdnimg.cn/blog_migrate/4f6ce04094706dd76c15517535e25319.jpeg)
里面有一个重要的数据结构说明如下:
/** * struct can_frame - basic CAN frame structure * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition * @can_dlc: frame payload length in byte (0 .. 8) aka data length code * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1 * mapping of the 'data length code' to the real payload length * @data: CAN frame payload (up to 8 byte) */struct can_frame {canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));};/* * Controller Area Network Identifier structure * * bit 0-28: CAN identifier (11/29 bit) * bit 29: error message frame flag (0 = data frame, 1 = error message) * bit 30: remote transmission request flag (1 = rtr frame) * bit 31: frame format flag (0 = standard 11 bit, 1 = extended 29 bit) */typedef __u32 canid_t;#define CAN_MAX_DLEN 8
6.结束语
本篇为大家介绍了Linux下CAN接口的简单使用,欢迎大家多交流,可以在下方留言讨论。
TopSemic 让芯片使用更简单