CAN(Controller Area Network,控制器局域网总线)是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。由德国博世公司在20世纪80年代专门为汽车行业开发。一组CAN上面可以支持多个节点。
在Linux下,CAN是网络设备,通过socket通信的方式来实现收发。
开发板上有一路CAN,对应的引脚位置如下
对应的网卡设备为 CAN0。板上未带CAN收发器,引出的接口是CAN TX、CAN RX。还需要一个CAN收发器的模块,电平为3.3V的,可以选择TI的SN65HVD230。将板上的CAN TX、CAN RX分别和SN65HVD230模块的CAN TX、CAN RX连接,将SN65HVD230的CANH、CANL分别和 CAN分析仪的CANH 和CANL连接即可进行收发测试。接线如下
Linux下使用canutil可以进行相关操作。
设置波特率为250k。
ip link set can0 type can bitrate 250000
启动CAN0
ifconfig can0 up
发送标准帧 id 0x123 数据0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
cansend can0 123#1122334455667788
发送扩展帧 id 0x12345678 数据0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
cansend can0 12345678#1122334455667788
发送之后 CAN分析仪显示如下
接收数据
candump can0
使用CAN分析仪发送标准帧id 0x123 数据0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
通过连接 libperipheral_api.a 静态库,可以使用C语言调用以下接口来操作CAN
/**
* @name: user_can_init
* @description: 初始化CAN
* @param can_name: can网卡设备名 如can0
* @param can_baud: 波特率 如250000
* @param canfd_baud: canfd波特率 如3000000
* @return 大于等于0 - 成功 小于0 - 失败
*/
int user_can_init(char *can_name, int can_baud, int canfd_baud);
/**
* @name: user_can_deinit
* @description: 反初始化CAN
* @param can_name: can网卡设备名 如can0
* @return 大于等于0 - 成功 小于0 - 失败
*/
int user_can_deinit(char *can_name);
/**
* @name: user_can_send
* @description: 发送一帧CAN数据
* @param can_name: can网卡设备名 如can0
* @param frame: Linux下的CAN结构体
* @return 大于0 - 成功 小于0 - 失败 等于0 - 暂时无法发送,有可能缓冲区满
*/
int user_can_send(char *can_name, struct can_frame frame);
/**
* @name: user_can_recv
* @description: 接收一帧CAN数据
* @param can_name: can网卡设备名 如can0
* @param frame: Linux下的CAN结构体
* @return 大于0 - 成功 小于0 - 失败 等于0 - 未收到数据,接收缓冲区空
*/
int user_can_recv(char *can_name, struct can_frame *frame);
测试demo如下,以操作 CAN0为例,外接 CAN分析仪
#include "peripheral_api.h"
void can_api_test(void)
{
struct can_frame frame_tx = {0};
struct can_frame frame_rx = {0};
int nbytes = 0;
user_can_init("can0",250000,3000000);
//标准帧
frame_tx.can_id = 0x123;
frame_tx.can_dlc = 8;
frame_tx.data[0] = 0x11;
frame_tx.data[1] = 0x22;
frame_tx.data[2] = 0x33;
frame_tx.data[3] = 0x44;
frame_tx.data[4] = 0x55;
frame_tx.data[5] = 0x66;
frame_tx.data[6] = 0x77;
frame_tx.data[7] = 0x88;
nbytes = user_can_send("can0",frame_tx);
//扩展帧
frame_tx.can_id = 0x12345678 | CAN_EFF_FLAG;
frame_tx.can_dlc = 8;
frame_tx.data[0] = 0x11;
frame_tx.data[1] = 0x22;
frame_tx.data[2] = 0x33;
frame_tx.data[3] = 0x44;
frame_tx.data[4] = 0x55;
frame_tx.data[5] = 0x66;
frame_tx.data[6] = 0x77;
frame_tx.data[7] = 0x88;
nbytes = user_can_send("can0",frame_tx);
sleep(1);
nbytes = user_can_recv("can0",&frame_rx);
/* printf the received frame */
if (nbytes > 0) {
printf("%#x [%d] ", frame_rx.can_id, frame_rx.can_dlc);
for (unsigned char i = 0; i < frame_rx.can_dlc; i++)
printf("%#x ", frame_rx.data[i]);
printf("\n");
}
user_can_deinit("can0");
return;
}
int main()
{
can_api_test();
return 0;
}
将peripheral_api.a静态库、peripheral_api.h和测试demo源码test.c放到同一路径下,编译命令如下
aarch64-none-linux-gnu-gcc test.c peripheral_api.a -I. -o cantest
运行结果如下