initial
This commit is contained in:
551
.claude/skills/can-protocol.md
Normal file
551
.claude/skills/can-protocol.md
Normal file
@@ -0,0 +1,551 @@
|
||||
# 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
|
||||
|
||||
---
|
||||
|
||||
## 数据结构
|
||||
|
||||
### 设备类型
|
||||
```c
|
||||
#define VCI_USBCAN2 4 // 用于 USBCAN-2A/2C/CANalyst-II 系列
|
||||
```
|
||||
|
||||
### VCI_BOARD_INFO
|
||||
设备信息结构体:
|
||||
```c
|
||||
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 帧结构体:
|
||||
```c
|
||||
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 初始化配置:
|
||||
```c
|
||||
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
|
||||
智能滤波范围:
|
||||
```c
|
||||
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 设备。每个设备只能打开一次。
|
||||
|
||||
```c
|
||||
DWORD VCI_OpenDevice(DWORD DevType, DWORD DevIndex, DWORD Reserved);
|
||||
```
|
||||
|
||||
**参数:**
|
||||
- `DevType`:设备类型(VCI_USBCAN2 为 4)
|
||||
- `DevIndex`:设备索引(第一个设备为 0,第二个为 1,依此类推)
|
||||
- `Reserved`:保留参数(设为 0)
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在或 USB 断开
|
||||
|
||||
**示例:**
|
||||
```c
|
||||
int deviceType = 4; // USBCAN-2A/2C/CANalyst-II
|
||||
int deviceIndex = 0; // 第一个设备
|
||||
if (VCI_OpenDevice(deviceType, deviceIndex, 0) != 1) {
|
||||
// 处理错误
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VCI_CloseDevice
|
||||
关闭 USB-CAN 设备。
|
||||
|
||||
```c
|
||||
DWORD VCI_CloseDevice(DWORD DevType, DWORD DevIndex);
|
||||
```
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在
|
||||
|
||||
---
|
||||
|
||||
### VCI_InitCAN
|
||||
初始化指定的 CAN 通道。每个通道调用一次。
|
||||
|
||||
```c
|
||||
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=设备不存在
|
||||
|
||||
**示例:**
|
||||
```c
|
||||
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);
|
||||
// 处理错误
|
||||
}
|
||||
```
|
||||
|
||||
**验收滤波示例:**
|
||||
```c
|
||||
// 只接收 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 通道。初始化后调用。
|
||||
|
||||
```c
|
||||
DWORD VCI_StartCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
|
||||
```
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在
|
||||
|
||||
---
|
||||
|
||||
### VCI_ResetCAN
|
||||
复位 CAN 通道(例如从总线关闭状态恢复)。无需重新初始化。
|
||||
|
||||
```c
|
||||
DWORD VCI_ResetCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
|
||||
```
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在
|
||||
|
||||
---
|
||||
|
||||
### VCI_Transmit
|
||||
发送 CAN 帧。
|
||||
|
||||
```c
|
||||
DWORD VCI_Transmit(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
|
||||
PVCI_CAN_OBJ pSend, DWORD Length);
|
||||
```
|
||||
|
||||
**参数:**
|
||||
- `pSend`:指向 CAN 帧数组的指针
|
||||
- `Length`:要发送的帧数(最大 1000,建议:1)
|
||||
|
||||
**返回值:** 实际发送的帧数,-1=设备不存在
|
||||
|
||||
**示例:**
|
||||
```c
|
||||
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 帧。
|
||||
|
||||
```c
|
||||
DWORD VCI_Receive(DWORD DevType, DWORD DevIndex, DWORD CANIndex,
|
||||
PVCI_CAN_OBJ pReceive, ULONG Len, INT WaitTime);
|
||||
```
|
||||
|
||||
**参数:**
|
||||
- `pReceive`:指向接收缓冲区数组的指针
|
||||
- `Len`:最多接收的帧数(缓冲区大小,建议:2500)
|
||||
- `WaitTime`:保留参数(设为 0)
|
||||
|
||||
**返回值:** 接收到的帧数,-1=设备不存在
|
||||
|
||||
**示例:**
|
||||
```c
|
||||
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
|
||||
获取接收缓冲区中未读取的帧数。
|
||||
|
||||
```c
|
||||
DWORD VCI_GetReceiveNum(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
|
||||
```
|
||||
|
||||
**返回值:** 未读取的帧数,-1=设备不存在
|
||||
|
||||
**注意:** 如果持续调用 `VCI_Receive`,通常不需要此函数。
|
||||
|
||||
---
|
||||
|
||||
### VCI_ClearBuffer
|
||||
清除接收和发送缓冲区。
|
||||
|
||||
```c
|
||||
DWORD VCI_ClearBuffer(DWORD DevType, DWORD DevIndex, DWORD CANIndex);
|
||||
```
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在
|
||||
|
||||
**注意:** 如果持续调用 `VCI_Receive`,通常不需要此函数。
|
||||
|
||||
---
|
||||
|
||||
### VCI_ReadBoardInfo
|
||||
读取设备信息。
|
||||
|
||||
```c
|
||||
DWORD VCI_ReadBoardInfo(DWORD DevType, DWORD DevIndex, PVCI_BOARD_INFO pInfo);
|
||||
```
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在
|
||||
|
||||
**示例:**
|
||||
```c
|
||||
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 个设备。
|
||||
|
||||
```c
|
||||
DWORD VCI_FindUsbDevice2(PVCI_BOARD_INFO pInfo);
|
||||
```
|
||||
|
||||
**参数:**
|
||||
- `pInfo`:包含 50 个 VCI_BOARD_INFO 结构的数组
|
||||
|
||||
**返回值:** 找到的设备数量
|
||||
|
||||
**示例:**
|
||||
```c
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
**使用场景:**
|
||||
1. **软硬件绑定:** 将软件绑定到特定设备序列号
|
||||
2. **多设备管理:** 将设备索引与序列号匹配
|
||||
3. **设备识别:** 识别物理设备对应的索引
|
||||
|
||||
---
|
||||
|
||||
### VCI_UsbDeviceReset
|
||||
复位 USB 设备(相当于拔插一次)。
|
||||
|
||||
```c
|
||||
DWORD VCI_UsbDeviceReset(DWORD DevType, DWORD DevIndex, DWORD Reserved);
|
||||
```
|
||||
|
||||
**参数:**
|
||||
- `Reserved`:保留参数(设为 0)
|
||||
|
||||
**返回值:** 1=成功,0=失败,-1=设备不存在
|
||||
|
||||
**注意:** 复位后必须重新调用 `VCI_OpenDevice`。
|
||||
|
||||
---
|
||||
|
||||
### VCI_SetReference
|
||||
配置智能滤波。允许精确控制接收哪些 ID。
|
||||
|
||||
```c
|
||||
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 范围:**
|
||||
```c
|
||||
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` 时:
|
||||
```c
|
||||
if (VCI_Receive(...) == -1) {
|
||||
VCI_CloseDevice(deviceType, deviceIndex);
|
||||
// 等待或重试
|
||||
if (VCI_OpenDevice(deviceType, deviceIndex, 0) == 1) {
|
||||
VCI_InitCAN(...);
|
||||
VCI_StartCAN(...);
|
||||
// 恢复操作
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **缓冲区大小:** 接收缓冲区使用 2500 帧(匹配内部缓冲区)
|
||||
2. **接收循环:** 持续调用 `VCI_Receive`;不要依赖 `VCI_GetReceiveNum`
|
||||
3. **发送类型:** 多节点通信始终使用 `SendType=0`
|
||||
4. **滤波设置:** 高负载总线使用智能滤波(`VCI_SetReference`)
|
||||
5. **错误恢复:** 监控返回值并妥善处理 USB 断开
|
||||
6. **多通道:** 分别初始化和启动每个通道
|
||||
7. **序列号:** 多设备设置中使用 `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
|
||||
Reference in New Issue
Block a user