using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CCDCount.DLL.CanBus { /// /// CANopen对象字典管理器 /// 存储和管理CANopen从站的所有对象 /// public class ObjectDictionary { private byte m_nodeId; private Dictionary> m_objects; public ObjectDictionary(byte nodeId) { m_nodeId = nodeId; m_objects = new Dictionary>(); InitializeStandardObjects(); } /// /// 初始化标准CANopen对象 /// private void InitializeStandardObjects() { // ========== 通信参数区域 (0x1000-0x1FFF) ========== // 0x1000:00 - 设备类型 (必须符合CANopen规范) // 格式: [0-15位: 设备轮廓] [16-31位: 附加信息] // 0x00000190 = 通用I/O设备 (Generic I/O Device) Write(0x1000, 0x00, (uint)0x00000190); // 0x1001:00 - 错误寄存器 Write(0x1001, 0x00, (byte)0x00); // 0x1005:00 - COB-ID SYNC Write(0x1005, 0x00, (uint)0x00000080); // 0x1006:00 - 同步窗口时间 Write(0x1006, 0x00, (uint)0); // 0x1007:00 - 同步溢出周期 Write(0x1007, 0x00, (uint)0); // 0x1008:00 - 制造商设备名称 Write(0x1008, 0x00, "CCDCount CANopen Slave Device"); // 0x1009:00 - 制造商硬件版本 Write(0x1009, 0x00, "1.0.0"); // 0x100A:00 - 制造商软件版本 Write(0x100A, 0x00, "1.0.0"); // 0x1017:00 - 生产者心跳时间 Write(0x1017, 0x00, (ushort)1000); // 0x1018:00 - 身份对象(子索引0表示条目数) Write(0x1018, 0x00, (byte)4); Write(0x1018, 0x01, (uint)0x00000133); // Vendor ID (示例值,实际应使用CiA分配的厂商ID) Write(0x1018, 0x02, (uint)0x00000001); // Product Code (产品代码,由厂商定义) Write(0x1018, 0x03, (uint)0x00010001); // Revision Number (版本号: Major.Minor) Write(0x1018, 0x04, (uint)((uint)m_nodeId)); // Serial Number (序列号) // ========== RPDO通信参数 (0x1400-0x15FF) ========== for (int i = 0; i < 4; i++) { ushort commIndex = (ushort)(0x1400 + i); Write(commIndex, 0x00, (byte)2); // 子条目数量 if (i < 2) { // 前两个RPDO启用(清除最高位0x80000000) Write(commIndex, 0x01, (uint)(0x200 + m_nodeId + i * 0x100)); // COB-ID (启用) } else { // 后两个RPDO禁用 Write(commIndex, 0x01, (uint)(0x200 + m_nodeId + i * 0x100 | 0x80000000)); // COB-ID (禁用) } Write(commIndex, 0x02, (byte)255); // 传输类型 } // ========== TPDO通信参数 (0x1800-0x19FF) ========== for (int i = 0; i < 4; i++) { ushort commIndex = (ushort)(0x1800 + i); Write(commIndex, 0x00, (byte)6); // 子条目数量 if (i < 2) { // 前两个TPDO启用(清除最高位0x80000000) Write(commIndex, 0x01, (uint)(0x180 + m_nodeId + i * 0x100)); // COB-ID (启用) } else { // 后两个TPDO禁用 Write(commIndex, 0x01, (uint)(0x180 + m_nodeId + i * 0x100 | 0x80000000)); // COB-ID (禁用) } Write(commIndex, 0x02, (byte)255); // 传输类型 Write(commIndex, 0x03, (ushort)0); // 抑制时间 Write(commIndex, 0x05, (ushort)0); // 事件定时器 Write(commIndex, 0x06, (byte)0); // SYNC启动值 } // ========== RPDO映射参数 (0x1600-0x17FF) ========== // RPDO 1: 映射数字输入状态 (0x6000:01-02) Write(0x1600, 0x00, (byte)2); // 映射条目数量 Write(0x1600, 0x01, (uint)0x60000108); // 0x6000:01, 8位 (DI1) Write(0x1600, 0x02, (uint)0x60000208); // 0x6000:02, 8位 (DI2) // RPDO 2: 映射数字输出控制 (0x6200:01-02) Write(0x1601, 0x00, (byte)2); // 映射条目数量 Write(0x1601, 0x01, (uint)0x62000108); // 0x6200:01, 8位 (DO1) Write(0x1601, 0x02, (uint)0x62000208); // 0x6200:02, 8位 (DO2) // RPDO 3: 未配置 Write(0x1602, 0x00, (byte)0); // 映射条目数量 // RPDO 4: 未配置 Write(0x1603, 0x00, (byte)0); // 映射条目数量 // ========== TPDO映射参数 (0x1A00-0x1BFF) ========== // TPDO 1: 映射模拟输入值 (0x6400:01-02) Write(0x1A00, 0x00, (byte)2); // 映射条目数量 Write(0x1A00, 0x01, (uint)0x64000110); // 0x6400:01, 16位 (AI1) Write(0x1A00, 0x02, (uint)0x64000210); // 0x6400:02, 16位 (AI2) // TPDO 2: 映射模拟输出值 (0x6410:01-02) Write(0x1A01, 0x00, (byte)2); // 映射条目数量 Write(0x1A01, 0x01, (uint)0x64100110); // 0x6410:01, 16位 (AO1) Write(0x1A01, 0x02, (uint)0x64100210); // 0x6410:02, 16位 (AO2) // TPDO 3: 未配置 Write(0x1A02, 0x00, (byte)0); // 映射条目数量 // TPDO 4: 未配置 Write(0x1A03, 0x00, (byte)0); // 映射条目数量 // ========== 制造商特定区域 (0x2000-0x5FFF) ========== // 这里可以添加自定义对象 // 示例:数字输入 Write(0x6000, 0x00, (byte)8); // 子条目数量 for (byte i = 1; i <= 8; i++) { Write(0x6000, i, (byte)0); // 数字输入状态 } // 示例:数字输出 Write(0x6200, 0x00, (byte)8); for (byte i = 1; i <= 8; i++) { Write(0x6200, i, (byte)0); // 数字输出控制 } // 示例:模拟输入 Write(0x6400, 0x00, (byte)4); for (byte i = 1; i <= 4; i++) { Write(0x6400, i, (ushort)0); // 模拟输入值 } // 示例:模拟输出 Write(0x6410, 0x00, (byte)2); for (byte i = 1; i <= 2; i++) { Write(0x6410, i, (ushort)0); // 模拟输出值 } } /// /// 读取对象字典值 /// public object Read(ushort index, byte subIndex) { if (!m_objects.ContainsKey(index)) return null; if (!m_objects[index].ContainsKey(subIndex)) return null; return m_objects[index][subIndex]; } /// /// 写入对象字典值 /// public bool Write(ushort index, byte subIndex, object value) { if (!m_objects.ContainsKey(index)) { m_objects[index] = new Dictionary(); } m_objects[index][subIndex] = value; return true; } /// /// 获取所有对象 /// public Dictionary> GetAllObjects() { return m_objects; } /// /// 检查对象是否存在 /// public bool Exists(ushort index, byte subIndex) { return m_objects.ContainsKey(index) && m_objects[index].ContainsKey(subIndex); } } }