/** * CAN API 快速参考 * 基于 ControlCAN 接口函数库 */ // ============================================ // 1. 基本数据结构 // ============================================ // CAN 帧结构 typedef struct { UINT ID; // CAN ID UINT TimeStamp; // 时间戳(0.1ms) BYTE TimeFlag; // 时间标志 BYTE SendType; // 0=正常发送, 1=单次发送 BYTE RemoteFlag; // 0=数据帧, 1=远程帧 BYTE ExternFlag; // 0=标准帧(11位), 1=扩展帧(29位) BYTE DataLen; // 数据长度(0-8) BYTE Data[8]; // 数据 } VCI_CAN_OBJ; // 初始化配置 typedef struct { DWORD AccCode; // 验收码 DWORD AccMask; // 屏蔽码(0xFFFFFFFF=接收所有) DWORD Reserved; BYTE Filter; // 滤波方式(1=所有类型) BYTE Timing0; // 波特率 T0 BYTE Timing1; // 波特率 T1 BYTE Mode; // 0=正常, 1=只听, 2=自发自收 } VCI_INIT_CONFIG; // 设备信息 typedef struct { USHORT hw_Version; // 硬件版本 USHORT fw_Version; // 固件版本 BYTE can_Num; // CAN 通道数 CHAR str_Serial_Num[20]; // 序列号 } VCI_BOARD_INFO; // ============================================ // 2. 核心 API 函数 // ============================================ // 打开设备 DWORD VCI_OpenDevice(DWORD DevType, DWORD DevIndex, DWORD Reserved); // 参数:DevType=4(USBCAN2), DevIndex=设备索引(0,1,2...) // 返回:1=成功, 0=失败, -1=设备不存在 // 关闭设备 DWORD VCI_CloseDevice(DWORD DevType, DWORD DevIndex); // 初始化 CAN DWORD VCI_InitCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_INIT_CONFIG pInitConfig); // 参数:CANIndex=CAN通道(0=CAN0, 1=CAN1) // 启动 CAN DWORD VCI_StartCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex); // 复位 CAN DWORD VCI_ResetCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex); // 发送数据 DWORD VCI_Transmit(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_CAN_OBJ pSend, DWORD Len); // 返回:实际发送的帧数 // 接收数据 DWORD VCI_Receive(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_CAN_OBJ pReceive, DWORD Len, INT WaitTime); // 返回:实际接收的帧数 // 获取接收数量 DWORD VCI_GetReceiveNum(DWORD DevType, DWORD DevIndex, DWORD CANIndex); // 清空缓冲区 DWORD VCI_ClearBuffer(DWORD DevType, DWORD DevIndex, DWORD CANIndex); // 读取设备信息 DWORD VCI_ReadBoardInfo(DWORD DevType, DWORD DevIndex, PVCI_BOARD_INFO pInfo); // ============================================ // 3. 常用波特率配置 // ============================================ // 波特率 Timing0 Timing1 // 1000 Kbps 0x00 0x14 // 800 Kbps 0x00 0x16 // 500 Kbps 0x00 0x1C // 推荐 // 250 Kbps 0x01 0x1C // 125 Kbps 0x03 0x1C // 100 Kbps 0x04 0x1C // ============================================ // 4. 完整使用流程 // ============================================ void CAN_Example() { // 步骤1:打开设备 if (VCI_OpenDevice(VCI_USBCAN2, 0, 0) != 1) { printf("打开设备失败\n"); return; } // 步骤2:配置并初始化 VCI_INIT_CONFIG config; config.AccCode = 0x00000000; config.AccMask = 0xFFFFFFFF; // 接收所有 config.Filter = 1; config.Timing0 = 0x00; // 500Kbps config.Timing1 = 0x1C; config.Mode = 0; // 正常模式 if (VCI_InitCAN(VCI_USBCAN2, 0, 0, &config) != 1) { printf("初始化失败\n"); VCI_CloseDevice(VCI_USBCAN2, 0); return; } // 步骤3:启动 CAN if (VCI_StartCAN(VCI_USBCAN2, 0, 0) != 1) { printf("启动失败\n"); VCI_CloseDevice(VCI_USBCAN2, 0); return; } // 步骤4:清空缓冲区 VCI_ClearBuffer(VCI_USBCAN2, 0, 0); // 步骤5:发送数据 VCI_CAN_OBJ send_frame; memset(&send_frame, 0, sizeof(VCI_CAN_OBJ)); send_frame.ID = 0x123; send_frame.SendType = 0; send_frame.RemoteFlag = 0; send_frame.ExternFlag = 0; // 标准帧 send_frame.DataLen = 8; send_frame.Data[0] = 0x11; send_frame.Data[1] = 0x22; // ... DWORD ret = VCI_Transmit(VCI_USBCAN2, 0, 0, &send_frame, 1); printf("发送 %d 帧\n", ret); // 步骤6:接收数据 VCI_CAN_OBJ recv_frames[100]; ret = VCI_Receive(VCI_USBCAN2, 0, 0, recv_frames, 100, 0); printf("接收 %d 帧\n", ret); for (DWORD i = 0; i < ret; i++) { printf("ID=0x%03X, 数据=[", recv_frames[i].ID); for (int j = 0; j < recv_frames[i].DataLen; j++) { printf("%02X ", recv_frames[i].Data[j]); } printf("]\n"); } // 步骤7:关闭设备 VCI_CloseDevice(VCI_USBCAN2, 0); } // ============================================ // 5. 常见应用场景 // ============================================ // 场景1:发送标准帧 void Send_StandardFrame(UINT id, BYTE* data, BYTE len) { VCI_CAN_OBJ frame = {0}; frame.ID = id; frame.SendType = 0; frame.RemoteFlag = 0; frame.ExternFlag = 0; // 标准帧 frame.DataLen = len; memcpy(frame.Data, data, len); VCI_Transmit(VCI_USBCAN2, 0, 0, &frame, 1); } // 场景2:发送扩展帧 void Send_ExtendedFrame(UINT id, BYTE* data, BYTE len) { VCI_CAN_OBJ frame = {0}; frame.ID = id; frame.SendType = 0; frame.RemoteFlag = 0; frame.ExternFlag = 1; // 扩展帧 frame.DataLen = len; memcpy(frame.Data, data, len); VCI_Transmit(VCI_USBCAN2, 0, 0, &frame, 1); } // 场景3:循环接收 void Receive_Loop() { VCI_CAN_OBJ frames[2500]; while (running) { DWORD count = VCI_Receive(VCI_USBCAN2, 0, 0, frames, 2500, 0); if (count > 0) { // 处理接收到的数据 for (DWORD i = 0; i < count; i++) { Process_Frame(&frames[i]); } } Sleep(10); // 10ms 间隔 } } // 场景4:AGV 速度控制 void AGV_SetVelocity(int16_t left_rpm, int16_t right_rpm) { BYTE data[8] = {0}; data[0] = 0x10; // 速度命令 data[1] = 0x00; data[2] = (left_rpm >> 8) & 0xFF; // 左轮高字节 data[3] = left_rpm & 0xFF; // 左轮低字节 data[4] = (right_rpm >> 8) & 0xFF; // 右轮高字节 data[5] = right_rpm & 0xFF; // 右轮低字节 Send_StandardFrame(0x200, data, 8); } // ============================================ // 6. 错误处理 // ============================================ // 检查返回值 DWORD ret = VCI_OpenDevice(VCI_USBCAN2, 0, 0); if (ret == 0) { printf("操作失败\n"); } else if (ret == (DWORD)-1) { printf("设备不存在或 USB 掉线\n"); } else { printf("操作成功\n"); } // ============================================ // 7. 注意事项 // ============================================ /* 1. 一个设备只能打开一次 2. 发送帧数建议每次 1 帧,提高效率 3. 接收缓冲区建议 2500 帧 4. 多节点通信时 SendType 必须为 0 5. 扩展帧 ID 为 29 位,标准帧为 11 位 6. 数据长度最大 8 字节 7. 波特率配置要与总线其他设备一致 8. 使用完毕后记得关闭设备 */