Files
agv-control-slam/docs/can/CAN_API_Reference.cpp
CaiXiang af65c2425d initial
2025-11-14 16:09:58 +08:00

247 lines
7.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 间隔
}
}
// 场景4AGV 速度控制
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. 使用完毕后记得关闭设备
*/