14 KiB
USB-CAN 接口函数库参考手册
概述
本技能文档提供 USB-CAN 接口函数库(ControlCAN.dll)版本 2.10 的参考信息,兼容周立功(ZLG)函数库。
库文件:
ControlCAN.dll- 主库文件ControlCAN.lib- 链接库ControlCAN.h- C/C++ 头文件ControlCAN.bas- VB 声明文件ControlCAN.pas- Delphi 声明文件ControlCAN.llb- LabVIEW 模块
支持设备: USBCAN-2A, USBCAN-2C, CANalyst-II, MiniPCIe-CAN
数据结构
设备类型
#define VCI_USBCAN2 4 // 用于 USBCAN-2A/2C/CANalyst-II 系列
VCI_BOARD_INFO
设备信息结构体:
typedef struct _VCI_BOARD_INFO {
USHORT hw_Version; // 硬件版本(如 0x0100 = V1.00)
USHORT fw_Version; // 固件版本
USHORT dr_Version; // 驱动版本
USHORT in_Version; // 接口库版本
USHORT irq_Num; // 保留
BYTE can_Num; // CAN 通道数量
CHAR str_Serial_Num[20]; // 序列号
CHAR str_hw_Type[40]; // 硬件类型字符串
USHORT Reserved[4];
} VCI_BOARD_INFO;
VCI_CAN_OBJ
CAN 帧结构体:
typedef struct _VCI_CAN_OBJ {
UINT ID; // CAN ID(右对齐)
UINT TimeStamp; // 时间戳(上电后 0.1ms 单位)
BYTE TimeFlag; // 1=时间戳有效(仅接收时)
BYTE SendType; // 0=正常发送,1=单次发送
BYTE RemoteFlag; // 0=数据帧,1=远程帧
BYTE ExternFlag; // 0=标准帧(11位),1=扩展帧(29位)
BYTE DataLen; // 数据长度(0-8)
BYTE Data[8]; // 数据字节
BYTE Reserved[3];
} VCI_CAN_OBJ;
SendType 取值:
0= 正常发送(失败自动重发,超时 1 秒)1= 单次发送(只发送一次,不重发)- ⚠️ 重要: 多节点通信时务必使用
SendType=0,否则会丢帧
VCI_INIT_CONFIG
CAN 初始化配置:
typedef struct _INIT_CONFIG {
DWORD AccCode; // 验收码
DWORD AccMask; // 屏蔽码(0xFFFFFFFF = 接收全部)
DWORD Reserved;
UCHAR Filter; // 滤波方式(1/2/3)
UCHAR Timing0; // 波特率定时器 0(BTR0)
UCHAR Timing1; // 波特率定时器 1(BTR1)
UCHAR Mode; // 0=正常,1=只听,2=自测
} VCI_INIT_CONFIG;
滤波模式:
1= 接收所有类型帧(标准帧 + 扩展帧)2= 只接收标准帧3= 只接收扩展帧
工作模式:
0= 正常模式1= 只听模式(只接收,不影响总线)2= 自测模式(环回模式)
VCI_FILTER_RECORD
智能滤波范围:
typedef struct _VCI_FILTER_RECORD {
DWORD ExtFrame; // 0=标准帧,1=扩展帧
DWORD Start; // 起始 ID
DWORD End; // 结束 ID
} VCI_FILTER_RECORD;
波特率配置
常用波特率设置(采样点 87.5%,SJW=0):
| 波特率 | Timing0 (BTR0) | Timing1 (BTR1) |
|---|---|---|
| 20 Kbps | 0x18 | 0x1C |
| 40 Kbps | 0x87 | 0xFF |
| 50 Kbps | 0x09 | 0x1C |
| 80 Kbps | 0x83 | 0xFF |
| 100 Kbps | 0x04 | 0x1C |
| 125 Kbps | 0x03 | 0x1C |
| 200 Kbps | 0x81 | 0xFA |
| 250 Kbps | 0x01 | 0x1C |
| 400 Kbps | 0x80 | 0xFA |
| 500 Kbps | 0x00 | 0x1C |
| 666 Kbps | 0x80 | 0xB6 |
| 800 Kbps | 0x00 | 0x16 |
| 1000 Kbps | 0x00 | 0x14 |
| 33.33 Kbps | 0x09 | 0x6F |
| 66.66 Kbps | 0x04 | 0x6F |
| 83.33 Kbps | 0x03 | 0x6F |
注意事项:
- 基于 SJA1000 控制器(16MHz)
- 最低支持波特率:10 Kbps(高速收发器)
- 非常规波特率请使用波特率计算工具
核心函数
VCI_OpenDevice
打开 USB-CAN 设备。每个设备只能打开一次。
DWORD VCI_OpenDevice(DWORD DevType, DWORD DevIndex, DWORD Reserved);
参数:
DevType:设备类型(VCI_USBCAN2 为 4)DevIndex:设备索引(第一个设备为 0,第二个为 1,依此类推)Reserved:保留参数(设为 0)
返回值: 1=成功,0=失败,-1=设备不存在或 USB 断开
示例:
int deviceType = 4; // USBCAN-2A/2C/CANalyst-II
int deviceIndex = 0; // 第一个设备
if (VCI_OpenDevice(deviceType, deviceIndex, 0) != 1) {
// 处理错误
}
VCI_CloseDevice
关闭 USB-CAN 设备。
DWORD VCI_CloseDevice(DWORD DevType, DWORD DevIndex);
返回值: 1=成功,0=失败,-1=设备不存在
VCI_InitCAN
初始化指定的 CAN 通道。每个通道调用一次。
DWORD VCI_InitCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
PVCI_INIT_CONFIG pInitConfig);
参数:
DevType:设备类型DevIndex:设备索引CANIndex:CAN 通道(0=CAN1,1=CAN2)pInitConfig:指向初始化配置的指针
返回值: 1=成功,0=失败,-1=设备不存在
示例:
VCI_INIT_CONFIG config;
config.AccCode = 0x80000008;
config.AccMask = 0xFFFFFFFF; // 接收全部
config.Filter = 1; // 接收所有类型
config.Timing0 = 0x00; // 1000 Kbps
config.Timing1 = 0x14;
config.Mode = 0; // 正常模式
if (VCI_InitCAN(deviceType, deviceIndex, 0, &config) != 1) {
VCI_CloseDevice(deviceType, deviceIndex);
// 处理错误
}
验收滤波示例:
// 只接收 ID 0x123(标准帧)
config.AccCode = 0x24600000; // 0x123 << 21
config.AccMask = 0x00000000; // 所有位都相关
// 接收 ID 范围 0x120-0x123
config.AccCode = 0x24600000; // 0x123 << 21
config.AccMask = 0x00600000; // 0x03 << 21,位 0-1 无关
VCI_StartCAN
启动 CAN 通道。初始化后调用。
DWORD VCI_StartCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
返回值: 1=成功,0=失败,-1=设备不存在
VCI_ResetCAN
复位 CAN 通道(例如从总线关闭状态恢复)。无需重新初始化。
DWORD VCI_ResetCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
返回值: 1=成功,0=失败,-1=设备不存在
VCI_Transmit
发送 CAN 帧。
DWORD VCI_Transmit(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
PVCI_CAN_OBJ pSend, DWORD Length);
参数:
pSend:指向 CAN 帧数组的指针Length:要发送的帧数(最大 1000,建议:1)
返回值: 实际发送的帧数,-1=设备不存在
示例:
VCI_CAN_OBJ frame;
frame.ID = 0x123;
frame.SendType = 0; // 正常发送(自动重试)
frame.RemoteFlag = 0; // 数据帧
frame.ExternFlag = 0; // 标准帧
frame.DataLen = 8;
for (int i = 0; i < 8; i++) {
frame.Data[i] = i;
}
DWORD sent = VCI_Transmit(deviceType, deviceIndex, 0, &frame, 1);
if (sent != 1) {
// 处理错误
}
VCI_Receive
从缓冲区接收 CAN 帧。
DWORD VCI_Receive(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
PVCI_CAN_OBJ pReceive, ULONG Len, INT WaitTime);
参数:
pReceive:指向接收缓冲区数组的指针Len:最多接收的帧数(缓冲区大小,建议:2500)WaitTime:保留参数(设为 0)
返回值: 接收到的帧数,-1=设备不存在
示例:
VCI_CAN_OBJ rxFrames[2500];
DWORD count = VCI_Receive(deviceType, deviceIndex, 0, rxFrames, 2500, 0);
if (count > 0) {
for (DWORD i = 0; i < count; i++) {
// 处理 rxFrames[i]
printf("ID: 0x%X, Data: ", rxFrames[i].ID);
for (int j = 0; j < rxFrames[i].DataLen; j++) {
printf("%02X ", rxFrames[i].Data[j]);
}
printf("\n");
}
} else if (count == -1) {
// USB 断开,尝试重新连接
VCI_CloseDevice(deviceType, deviceIndex);
VCI_OpenDevice(deviceType, deviceIndex, 0);
}
最佳实践: 在循环中持续调用 VCI_Receive。比使用 VCI_GetReceiveNum 更高效。
VCI_GetReceiveNum
获取接收缓冲区中未读取的帧数。
DWORD VCI_GetReceiveNum(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
返回值: 未读取的帧数,-1=设备不存在
注意: 如果持续调用 VCI_Receive,通常不需要此函数。
VCI_ClearBuffer
清除接收和发送缓冲区。
DWORD VCI_ClearBuffer(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
返回值: 1=成功,0=失败,-1=设备不存在
注意: 如果持续调用 VCI_Receive,通常不需要此函数。
VCI_ReadBoardInfo
读取设备信息。
DWORD VCI_ReadBoardInfo(DWORD DevType, DWORD DevIndex, PVCI_BOARD_INFO pInfo);
返回值: 1=成功,0=失败,-1=设备不存在
示例:
VCI_BOARD_INFO info;
if (VCI_ReadBoardInfo(deviceType, deviceIndex, &info) == 1) {
printf("硬件: %s\n", info.str_hw_Type);
printf("序列号: %s\n", info.str_Serial_Num);
printf("通道数: %d\n", info.can_Num);
}
扩展函数
VCI_FindUsbDevice2
查找所有已连接的 USB-CAN 设备并获取序列号。最多支持 50 个设备。
DWORD VCI_FindUsbDevice2(PVCI_BOARD_INFO pInfo);
参数:
pInfo:包含 50 个 VCI_BOARD_INFO 结构的数组
返回值: 找到的设备数量
示例:
VCI_BOARD_INFO devices[50];
int count = VCI_FindUsbDevice2(devices);
for (int i = 0; i < count; i++) {
printf("设备 %d: %s\n", i, devices[i].str_Serial_Num);
}
使用场景:
- 软硬件绑定: 将软件绑定到特定设备序列号
- 多设备管理: 将设备索引与序列号匹配
- 设备识别: 识别物理设备对应的索引
VCI_UsbDeviceReset
复位 USB 设备(相当于拔插一次)。
DWORD VCI_UsbDeviceReset(DWORD DevType, DWORD DevIndex, DWORD Reserved);
参数:
Reserved:保留参数(设为 0)
返回值: 1=成功,0=失败,-1=设备不存在
注意: 复位后必须重新调用 VCI_OpenDevice。
VCI_SetReference
配置智能滤波。允许精确控制接收哪些 ID。
DWORD VCI_SetReference(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
DWORD RefType, PVOID pData);
RefType 取值:
| RefType | pData | 说明 |
|---|---|---|
| 1 | PVCI_FILTER_RECORD |
添加滤波范围(每个范围调用一次) |
| 2 | NULL |
启用滤波表 |
| 3 | NULL |
清除滤波表 |
示例 - 接收特定 ID 范围:
VCI_FILTER_RECORD filters[4];
// 接收标准帧 ID 0x0001
filters[0].ExtFrame = 0;
filters[0].Start = 0x0001;
filters[0].End = 0x0001;
// 接收标准帧 ID 范围 0x0003-0x0005
filters[1].ExtFrame = 0;
filters[1].Start = 0x0003;
filters[1].End = 0x0005;
// 接收扩展帧 ID 0x00000002
filters[2].ExtFrame = 1;
filters[2].Start = 0x00000002;
filters[2].End = 0x00000002;
// 接收扩展帧 ID 范围 0x00000004-0x00000007
filters[3].ExtFrame = 1;
filters[3].Start = 0x00000004;
filters[3].End = 0x00000007;
// 清除现有滤波器(可选)
VCI_SetReference(21, deviceIndex, 0, 3, NULL);
// 添加滤波范围
for (int i = 0; i < 4; i++) {
VCI_SetReference(21, deviceIndex, 0, 1, &filters[i]);
}
// 启用滤波器
VCI_SetReference(21, deviceIndex, 0, 2, NULL);
重要提示:
- 滤波表只写(无法读回)
- 在启用前添加所有滤波器
- 要修改滤波器,需清除后重新添加
- 掉电后滤波设置丢失
- 在
VCI_InitCAN之后、操作期间调用
典型使用流程
1. [可选] VCI_FindUsbDevice2() // 查找设备和序列号
2. VCI_OpenDevice() // 打开设备
3. VCI_InitCAN() // 初始化 CAN 通道
4. [可选] VCI_SetReference() // 配置智能滤波器
- RefType=3: 清除滤波器
- RefType=1: 添加滤波范围(多次调用)
- RefType=2: 启用滤波器
5. VCI_StartCAN() // 启动 CAN
6. 主循环:
- VCI_Transmit() // 发送帧
- VCI_Receive() // 接收帧(持续循环)
- [可选] VCI_ResetCAN() // 总线关闭时复位
7. VCI_CloseDevice() // 完成时关闭设备
错误处理
所有函数返回:
1= 成功0= 操作失败-1= USB 设备未找到或断开
USB 热插拔支持:
当 VCI_Receive 返回 -1 时:
if (VCI_Receive(...) == -1) {
VCI_CloseDevice(deviceType, deviceIndex);
// 等待或重试
if (VCI_OpenDevice(deviceType, deviceIndex, 0) == 1) {
VCI_InitCAN(...);
VCI_StartCAN(...);
// 恢复操作
}
}
最佳实践
- 缓冲区大小: 接收缓冲区使用 2500 帧(匹配内部缓冲区)
- 接收循环: 持续调用
VCI_Receive;不要依赖VCI_GetReceiveNum - 发送类型: 多节点通信始终使用
SendType=0 - 滤波设置: 高负载总线使用智能滤波(
VCI_SetReference) - 错误恢复: 监控返回值并妥善处理 USB 断开
- 多通道: 分别初始化和启动每个通道
- 序列号: 多设备设置中使用
VCI_FindUsbDevice2进行设备识别
常见问题
问:无法接收帧?
- 检查
AccMask是否为 0xFFFFFFFF(接收全部) - 验证
Filter模式是否匹配帧类型 - 检查波特率是否匹配总线
- 确保已调用
VCI_StartCAN
问:多节点设置中发送失败?
- 始终使用
SendType=0(不是 1)进行正常通信 - 检查总线终端和线路
问:总线关闭状态?
- 调用
VCI_ResetCAN恢复 - 检查电气问题(终端、电缆质量)
问:如何过滤特定 ID?
- 使用带智能滤波表的
VCI_SetReference - 或使用
AccCode/AccMask进行简单滤波
参考文件
另请参阅:
附件1:ID对齐方式.pdf- ID 对齐详情附件2:CAN参数设置.pdf- CAN 参数设置波特率侦测工具使用说明书.pdf- 波特率检测工具
技术支持: zhcxgd@163.com