CAN(Controller Area Network,控制器局域网总线)是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。由德国博世公司在20世纪80年代专门为汽车行业开发。一组CAN上面可以支持多个节点。
在Linux下,CAN是网络设备,通过socket通信的方式来实现收发。
开发板上有一路CAN,对应的网卡设备为 CAN0。板上已经带了CAN收发器,引出的接口直接就是H和L差分。将板上的CANH和CANL分别和 CAN分析仪的CANH 和CANL连接即可进行收发测试。接线如下
Linux下使用canutil可以进行相关操作。
设置波特率为250k。目前板上是不具备canfd功能的,但是RK3568本身支持canfd,因此,这里必须同时要设置一个canfd的波特率
root@linaro-alip:~# ip link set can0 type can bitrate 250000 dbitrate 3000000 fd on
启动CAN0
root@linaro-alip:~# ip link set can0 up
发送标准帧 id 0x123 数据0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
root@linaro-alip:~# cansend can0 123#1122334455667788
发送扩展帧 id 0x12345678 数据0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
root@linaro-alip:~# cansend can0 12345678#1122334455667788
发送之后 CAN分析仪显示如下
接收数据
root@linaro-alip:~# candump can0
使用CAN分析仪发送标准帧id 0x234 数据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分析仪
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);
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;
}
运行结果如下