# CAN 通信使用说明

## 文件说明

1. **ControlCAN.h** - CAN 设备 API 头文件（位于 lib 目录）
2. **ControlCAN.dll** - CAN 设备动态链接库（位于 lib 目录）
3. **ControlCAN.lib** - 导入库（位于 lib 目录）
4. **CANController.h/cpp** - CAN 控制器封装类
5. **can_complete_example.cpp** - 完整使用示例

## 快速开始

### 1. 编译项目

使用 g++ 编译（MinGW）：

```bash
# 编译封装类
g++ -c CANController.cpp -o CANController.o -std=c++11

# 编译完整示例
g++ can_complete_example.cpp CANController.o -o can_demo.exe -Llib -lControlCAN -std=c++11

# 或者使用提供的编译脚本
./build_can.sh
```

使用 MSVC 编译：

```bash
cl /EHsc /std:c++17 can_complete_example.cpp CANController.cpp /link /LIBPATH:lib ControlCAN.lib
```

### 2. 运行示例

确保 ControlCAN.dll 在可执行文件同目录或系统路径中：

```bash
# 复制 DLL
copy lib\ControlCAN.dll .

# 运行示例
./can_demo.exe
```

## API 使用说明

### 初始化流程

```cpp
#include "CANController.h"

// 1. 创建 CAN 控制器对象
CANController can(VCI_USBCAN2, 0, 0);  // 设备类型、设备索引、CAN通道

// 2. 初始化（波特率 500Kbps）
if (!can.Initialize(0x00, 0x1C, 0)) {
    // 初始化失败处理
    return -1;
}

// 3. 发送数据
BYTE data[] = {0x11, 0x22, 0x33, 0x44};
can.SendStandardFrame(0x123, data, 4);

// 4. 接收数据
std::vector<VCI_CAN_OBJ> frames;
DWORD count = can.Receive(frames, 100);
for (const auto& frame : frames) {
    // 处理接收到的数据
}

// 5. 关闭（析构函数自动调用）
can.Close();
```

### 常用波特率配置

| 波特率 | Timing0 | Timing1 | 示例代码 |
|--------|---------|---------|----------|
| 1Mbps  | 0x00    | 0x14    | `can.Initialize(0x00, 0x14, 0)` |
| 800Kbps| 0x00    | 0x16    | `can.Initialize(0x00, 0x16, 0)` |
| 500Kbps| 0x00    | 0x1C    | `can.Initialize(0x00, 0x1C, 0)` |
| 250Kbps| 0x01    | 0x1C    | `can.Initialize(0x01, 0x1C, 0)` |
| 125Kbps| 0x03    | 0x1C    | `can.Initialize(0x03, 0x1C, 0)` |
| 100Kbps| 0x04    | 0x1C    | `can.Initialize(0x04, 0x1C, 0)` |

### 工作模式

| 模式值 | 说明 | 应用场景 |
|--------|------|----------|
| 0 | 正常模式 | 正常的 CAN 通信，可收发 |
| 1 | 只听模式 | 总线监控，不影响总线 |
| 2 | 自发自收 | 设备测试，环回模式 |

## AGV 控制示例

### 速度控制

```cpp
// AGV 速度控制函数
void sendAGVVelocity(CANController& can, int16_t left_speed, int16_t right_speed) {
    BYTE data[8] = {0};
    data[0] = 0x10;  // 速度控制命令
    data[1] = 0x00;
    data[2] = (left_speed >> 8) & 0xFF;   // 左轮速度高字节
    data[3] = left_speed & 0xFF;          // 左轮速度低字节
    data[4] = (right_speed >> 8) & 0xFF;  // 右轮速度高字节
    data[5] = right_speed & 0xFF;         // 右轮速度低字节
    data[6] = 0x00;
    data[7] = 0x00;

    can.SendStandardFrame(0x200, data, 8);
}

// 使用示例
sendAGVVelocity(can, 100, 100);  // 直行，速度 100
sendAGVVelocity(can, 50, 100);   // 左转
sendAGVVelocity(can, 100, 50);   // 右转
sendAGVVelocity(can, 0, 0);      // 停止
```

### 周期性心跳

```cpp
// 在独立线程中发送心跳
std::thread heartbeat_thread([&can]() {
    int counter = 0;
    while (running) {
        BYTE data[8] = {0xAA, 0x00, 0x00, 0x00};
        data[1] = (counter >> 8) & 0xFF;
        data[2] = counter & 0xFF;

        can.SendStandardFrame(0x100, data, 4);
        counter++;

        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
});
```

### 接收处理（回调方式）

```cpp
// 设置接收回调函数
can.SetReceiveCallback([](const VCI_CAN_OBJ& frame) {
    if (frame.ID == 0x201) {
        // 电机反馈
        int16_t speed = (frame.Data[0] << 8) | frame.Data[1];
        std::cout << "电机速度: " << speed << " RPM" << std::endl;
    }
    else if (frame.ID == 0x300) {
        // AGV 状态
        uint8_t status = frame.Data[0];
        std::cout << "AGV 状态: " << (int)status << std::endl;
    }
});

// 在主循环中接收数据
while (running) {
    std::vector<VCI_CAN_OBJ> frames;
    can.Receive(frames, 100);  // 会自动调用回调函数
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
```

## 故障排查

### 常见问题

1. **打开设备失败**
   - 检查 USB-CAN 设备是否正确连接
   - 检查设备驱动是否安装
   - 检查设备索引是否正确（从0开始）

2. **初始化失败**
   - 检查波特率参数是否正确
   - 确保设备未被其他程序占用

3. **发送/接收失败**
   - 检查 CAN 总线是否正常连接
   - 检查终端电阻是否正确
   - 使用示例3的监控模式检查总线通信

4. **DLL 加载失败**
   - 确保 ControlCAN.dll 在可执行文件目录
   - 或将 dll 路径添加到系统 PATH

## 进阶功能

### 智能滤波

```cpp
// 设置滤波器（仅接收特定 ID 范围）
VCI_FILTER_RECORD filter;
filter.ExtFrame = 0;      // 标准帧
filter.Start = 0x100;     // 起始 ID
filter.End = 0x1FF;       // 结束 ID

// 注意：需要直接调用 VCI_SetReference
VCI_SetReference(VCI_USBCAN2, 0, 0, 1, &filter);  // 添加滤波规则
VCI_SetReference(VCI_USBCAN2, 0, 0, 2, nullptr);  // 启用滤波
```

### 多设备支持

```cpp
// 查找所有 USB-CAN 设备
VCI_BOARD_INFO devices[50];
DWORD count = VCI_FindUsbDevice2(devices);

std::cout << "找到 " << count << " 个设备：" << std::endl;
for (DWORD i = 0; i < count; i++) {
    std::cout << "设备 " << i << ": " << devices[i].str_Serial_Num << std::endl;
}

// 打开特定设备
CANController can1(VCI_USBCAN2, 0, 0);  // 第一个设备
CANController can2(VCI_USBCAN2, 1, 0);  // 第二个设备
```

## 参考资料

- ControlCAN 接口函数库使用说明书（docs/protocol/CAN_Protocol.pdf）
- can_complete_example.cpp - 完整示例代码
- CANController.h/cpp - 封装类实现

## 技术支持

如有问题，请参考：
- 官方文档：docs/protocol/CAN_Protocol.pdf
- 邮箱：zhcxgd@163.com
