# CANopen从站使用指南 ## 概述 本实现基于创芯科技CAN卡底层库(`CanLibraryClass`)构建了一个完整的CANopen从站,支持: - ✅ NMT状态机管理(初始化→预操作→运行→停止) - ✅ SDO服务数据对象(读写对象字典) - ✅ PDO过程数据对象(TPDO发送/RPDO接收) - ✅ 心跳机制(Heartbeat) - ✅ SYNC同步对象 - ✅ EDS配置文件生成(用于PLC识别) ## 文件结构 ``` CanTest/ ├── CanOpenManager.cs # CANopen协议管理器(主站功能) ├── CanOpenSlave.cs # CANopen从站核心类 ⭐ ├── ObjectDictionary.cs # 对象字典管理器 ⭐ ├── EdsFileGenerator.cs # EDS文件生成器 ⭐ └── Program.cs # 使用示例 ``` ## 快速开始 ### 1. 创建从站实例 ```csharp using CCDCount.DLL.CanBus; // 创建节点ID为5的从站 byte nodeId = 5; CanOpenSlave slave = new CanOpenSlave( nodeId: 5, // 节点ID (1-127) deviceType: 4, // USBCAN2 deviceIndex: 0, // 设备索引 canIndex: 0 // CAN通道 ); ``` ### 2. 初始化并启动 ```csharp // 初始化(波特率500kbps) if (!slave.Initialize(CanBaudRate.BaudRate_500K)) { Console.WriteLine("初始化失败"); return; } // 配置PDO slave.ConfigureTpdo(1, enabled: true, transmissionType: 0xFF); // TPDO1事件驱动 slave.ConfigureRpdo(1, enabled: true); // RPDO1启用 // 设置心跳时间(1000ms) slave.SetHeartbeatTime(1000); // 启动从站 slave.Start(); ``` ### 3. 读写数据 ```csharp // 写入对象字典 slave.SetObjectValue(0x6000, 0x01, (byte)0xAA); // 数字输入 slave.SetObjectValue(0x6400, 0x01, (ushort)1234); // 模拟输入 // 读取对象字典 var value = slave.GetObjectValue(0x6200, 0x01); // 读取数字输出 ``` ### 4. 发送TPDO ```csharp // 发送TPDO1(自动从对象字典打包数据) slave.SendTpdo(1); ``` ### 5. 生成EDS文件 ```csharp // 生成EDS配置文件(供PLC导入) string edsPath = "CanOpenSlave_Node5.eds"; slave.GenerateEdsFile(edsPath); ``` ### 6. 停止并释放 ```csharp slave.Stop(); slave.Dispose(); ``` ## 完整示例 参见 `Program.cs` 中的 `RunCanOpenSlave()` 方法。 ## 对象字典说明 ### 标准对象(自动初始化) | 索引 | 名称 | 类型 | 访问 | 说明 | |------|------|------|------|------| | 0x1000 | Device Type | UINT32 | RO | 设备类型 | | 0x1001 | Error Register | UINT8 | RO | 错误寄存器 | | 0x1008 | Device Name | STRING | RO | 设备名称 | | 0x1017 | Heartbeat Time | UINT16 | RW | 心跳时间(ms) | | 0x1018 | Identity | RECORD | RO | 身份对象 | ### PDO通信参数 | 索引范围 | 名称 | 说明 | |----------|------|------| | 0x1400-0x1403 | RPDO1-4 Communication | RPDO通信参数 | | 0x1800-0x1803 | TPDO1-4 Communication | TPDO通信参数 | ### PDO映射参数 | 索引范围 | 名称 | 说明 | |----------|------|------| | 0x1600-0x1603 | RPDO1-4 Mapping | RPDO映射参数 | | 0x1A00-0x1A03 | TPDO1-4 Mapping | TPDO映射参数 | ### 制造商特定对象(示例) | 索引 | 名称 | 类型 | 访问 | 说明 | |------|------|------|------|------| | 0x6000 | Digital Input | UINT8[8] | RO | 数字输入(8位) | | 0x6200 | Digital Output | UINT8[8] | RW | 数字输出(8位) | | 0x6400 | Analog Input | UINT16[4] | RO | 模拟输入(4通道) | | 0x6410 | Analog Output | UINT16[2] | RW | 模拟输出(2通道) | ## PLC配置步骤 ### 步骤1:生成EDS文件 ```csharp slave.GenerateEdsFile("MyDevice.eds"); ``` ### 步骤2:在PLC中导入EDS 以**西门子S7-1200/1500**为例: 1. 打开 TIA Portal 2. 进入"硬件配置" → "PROFINET/CANopen" 3. 右键"CANopen主站" → "导入GSD/EDS文件" 4. 选择生成的 `.eds` 文件 5. 将设备拖放到网络拓扑中 6. 设置节点ID(与代码中一致) 7. 配置PDO映射关系 ### 步骤3:配置PDO映射 在PLC中配置PDO映射时,需要指定: **TPDO映射示例(从站到PLC):** ``` TPDO1 映射: - 0x6000:01 (Digital Input Bit 0) - 8位 - 0x6400:01 (Analog Input Ch1) - 16位 ``` **RPDO映射示例(PLC到从站):** ``` RPDO1 映射: - 0x6200:01 (Digital Output Bit 0) - 8位 - 0x6410:01 (Analog Output Ch1) - 16位 ``` ### 步骤4:下载并运行 1. 编译PLC程序 2. 下载到PLC 3. 启动PLC(会自动发送NMT启动命令) 4. 从站进入Operational状态 5. 开始周期性PDO通信 ## NMT状态机 ``` Initializing ──→ PreOperational ──→ Operational ↑ ↑ │ │ │ │ └──── Reset ─────┘ │ ↓ Stopped ``` ### 状态转换命令 | 命令码 | 功能 | 说明 | |--------|------|------| | 0x01 | Start Node | 预操作/停止 → 运行 | | 0x02 | Stop Node | 运行 → 停止 | | 0x80 | Enter PreOperational | 任何状态 → 预操作 | | 0x81 | Reset Node | 任何状态 → 初始化 → 预操作 | | 0x82 | Reset Communication | 任何状态 → 预操作 | ## 常见问题 ### Q1: 从站无法被PLC识别? **检查清单:** - [ ] CAN波特率是否与PLC一致? - [ ] 节点ID是否正确配置? - [ ] EDS文件是否正确导入PLC? - [ ] CAN总线接线是否正确(CAN_H/CAN_L)? - [ ] 终端电阻是否已安装(120Ω)? ### Q2: PDO通信无数据? **排查步骤:** 1. 确认从站处于 **Operational** 状态 2. 检查PDO是否已启用:`ConfigureTpdo(1, true)` 3. 验证PDO映射配置是否正确 4. 使用CAN分析仪抓包验证COB-ID ### Q3: 如何修改对象字典? ```csharp // 添加自定义对象 slave.SetObjectValue(0x2000, 0x00, (byte)0x12); // 注意:需要在EDS生成前添加,否则EDS中不会包含 ``` ### Q4: 心跳超时如何处理? PLC会监测心跳报文,如果超时: - 检查 `SetHeartbeatTime()` 设置值 - 确认从站未进入 Stopped 状态 - 验证CAN总线通信正常 ## 技术细节 ### COB-ID分配 | 功能 | COB-ID计算公式 | 示例(节点5) | |------|----------------|-------------| | NMT | 0x000 | 0x000 | | SYNC | 0x080 | 0x080 | | EMCY | 0x080 + NodeID | 0x085 | | SDO请求 | 0x600 + NodeID | 0x605 | | SDO响应 | 0x580 + NodeID | 0x585 | | TPDO1 | 0x180 + NodeID | 0x185 | | TPDO2 | 0x280 + NodeID | 0x285 | | RPDO1 | 0x200 + NodeID | 0x205 | | RPDO2 | 0x300 + NodeID | 0x305 | | Heartbeat | 0x700 + NodeID | 0x705 | ### 传输类型(Transmission Type) | 值 | 含义 | |----|------| | 0 | SYNC同步触发(每个SYNC发送) | | 1-240 | SYNC同步触发(每N个SYNC发送) | | 252 | RTR远程请求触发 | | 253 | 事件驱动+定时器 | | 254 | 事件驱动 | | 255 | 制造商特定 | ## 依赖项 - .NET Framework 4.8 - 创芯科技CAN卡驱动 (`controlcan.dll`) - CanLibraryClass.cs(底层CAN API) ## 许可证 本项目仅供学习和测试使用。 ## 联系方式 如有问题,请查阅: 1. CANopen标准协议 CiA 301 2. 创芯科技CAN卡开发手册 3. PLC厂商的CANopen主站配置指南