README_CANopen_Slave.md 11 KB

CANopen从站实现 - 项目总结

📋 项目概述

本项目基于创芯科技CAN卡底层库实现了一个完整的CANopen从站,可直接与PLC等CANopen主站设备进行通信。

✨ 核心特性

  • 完整的NMT状态机:支持初始化、预操作、运行、停止四种状态
  • SDO服务:支持对象字典的读写操作
  • PDO通信:支持4个TPDO和4个RPDO的配置和数据传输
  • 心跳机制:自动发送心跳报文告知主站从站状态
  • SYNC同步:支持同步对象处理
  • EDS文件生成:自动生成PLC可识别的配置文件
  • 灵活的对象字典:支持标准对象和自定义对象

📁 文件结构

CanTest/
├── CanOpenSlave.cs              # ⭐ CANopen从站核心类
├── ObjectDictionary.cs          # ⭐ 对象字典管理器
├── EdsFileGenerator.cs          # ⭐ EDS配置文件生成器
├── PdoMappingExample.cs         # PDO映射配置示例
├── CANopen从站使用指南.md       # 详细使用文档
├── README_CANopen_Slave.md      # 本文件
│
├── CanOpenManager.cs            # CANopen主站管理器(原有)
├── CanLibraryClass.cs           # 创芯科技CAN卡底层API
└── Program.cs                   # 主程序(包含从站示例)

🚀 快速开始

1. 基本用法

using CCDCount.DLL.CanBus;

// 创建从站(节点ID=5)
using (CanOpenSlave slave = new CanOpenSlave(5))
{
    // 初始化
    slave.Initialize(CanBaudRate.BaudRate_500K);
    
    // 配置PDO
    slave.ConfigureTpdo(1, true);  // 启用TPDO1
    slave.ConfigureRpdo(1, true);  // 启用RPDO1
    
    // 设置心跳
    slave.SetHeartbeatTime(1000);
    
    // 启动
    slave.Start();
    
    // 写入数据
    slave.SetObjectValue(0x6000, 0x01, (byte)0xAA);
    
    // 发送TPDO
    slave.SendTpdo(1);
    
    // 生成EDS文件
    slave.GenerateEdsFile("Device.eds");
}

2. 运行示例

Program.cs 中已包含完整示例,直接运行即可:

cd d:\work\WindowsFormsTest\CanTest
dotnet run

🔧 技术架构

核心组件

1. CanOpenSlave(从站核心)

职责:

  • NMT状态机管理
  • CAN帧接收和分发
  • SDO请求处理
  • PDO数据打包/解包
  • 心跳发送

关键方法:

Initialize()          // 初始化从站
Start()               // 启动接收线程
Stop()                // 停止从站
SetObjectValue()      // 写入对象字典
GetObjectValue()      // 读取对象字典
ConfigureTpdo()       // 配置TPDO
ConfigureRpdo()       // 配置RPDO
SendTpdo()            // 发送TPDO
SetHeartbeatTime()    // 设置心跳时间
GenerateEdsFile()     // 生成EDS文件

2. ObjectDictionary(对象字典)

职责:

  • 存储所有CANopen对象
  • 提供读写接口
  • 初始化标准对象

标准对象包括:

  • 设备信息(0x1000-0x1018)
  • PDO通信参数(0x1400-0x19FF)
  • PDO映射参数(0x1600-0x1BFF)
  • 制造商特定对象(0x6000-0x6410)

3. EdsFileGenerator(EDS生成器)

职责:

  • 根据对象字典生成EDS文件
  • 符合CiA标准格式
  • 可直接导入PLC配置软件

生成的EDS包含:

  • 设备基本信息
  • 支持的波特率
  • 所有对象定义
  • 数据类型和访问权限
  • PDO配置信息

📊 对象字典详解

标准对象区域(0x1000-0x1FFF)

索引 名称 类型 说明
0x1000:00 Device Type UINT32 设备类型代码
0x1001:00 Error Register UINT8 错误寄存器
0x1005:00 COB-ID SYNC UINT32 SYNC COB-ID
0x1008:00 Device Name STRING 设备名称
0x1009:00 Hardware Version STRING 硬件版本
0x100A:00 Software Version STRING 软件版本
0x1017:00 Heartbeat Time UINT16 心跳时间(ms)
0x1018:00-04 Identity RECORD 厂商ID、产品码等

PDO通信参数(0x1400-0x19FF)

RPDO通信参数(0x1400-0x1403):

  • 子索引01: COB-ID
  • 子索引02: 传输类型

TPDO通信参数(0x1800-0x1803):

  • 子索引01: COB-ID
  • 子索引02: 传输类型
  • 子索引03: 抑制时间
  • 子索引05: 事件定时器

PDO映射参数(0x1600-0x1BFF)

映射项格式(32位):

[索引 16位][子索引 8位][位数 8位]

示例:

// 映射 0x6000:01, 8位
uint mapping = (0x6000U << 16) | (0x01U << 8) | 0x08U;

制造商特定对象(0x6000-0x6410)

索引 名称 类型 说明
0x6000:01-08 Digital Input UINT8[8] 数字输入
0x6200:01-08 Digital Output UINT8[8] 数字输出
0x6400:01-04 Analog Input UINT16[4] 模拟输入
0x6410:01-02 Analog Output UINT16[2] 模拟输出

🔌 PLC集成指南

支持的PLC品牌

  • ✅ 西门子 S7-1200/1500
  • ✅ 三菱 FX/Q系列
  • ✅ 欧姆龙 CJ/CS系列
  • ✅ 倍福 TwinCAT
  • ✅ 其他支持CANopen的主站

配置步骤

步骤1:生成EDS文件

slave.GenerateEdsFile("MyDevice.eds");

步骤2:导入到PLC

TIA Portal为例:

  1. 打开硬件配置
  2. 右键"CANopen主站" → "导入GSD/EDS"
  3. 选择生成的 .eds 文件
  4. 拖放设备到网络拓扑
  5. 设置节点ID

步骤3:配置PDO映射

在PLC中配置映射关系,确保与从站一致:

TPDO1示例:

字节0: 0x6000:01 (Digital Input Bit 0)
字节1-2: 0x6400:01 (Analog Input Ch1)

RPDO1示例:

字节0: 0x6200:01 (Digital Output Bit 0)
字节1-2: 0x6410:01 (Analog Output Ch1)

步骤4:下载并运行

  1. 编译PLC程序
  2. 下载到PLC
  3. 启动PLC(自动发送NMT Start命令)
  4. 观察从站状态变化

📡 通信协议详解

COB-ID分配表

功能 基础ID 计算公式 节点5示例
NMT 0x000 固定 0x000
SYNC 0x080 固定 0x080
EMCY 0x080 0x080 + NodeID 0x085
SDO请求 0x600 0x600 + NodeID 0x605
SDO响应 0x580 0x580 + NodeID 0x585
TPDO1 0x180 0x180 + NodeID 0x185
TPDO2 0x280 0x280 + NodeID 0x285
TPDO3 0x380 0x380 + NodeID 0x385
TPDO4 0x480 0x480 + NodeID 0x485
RPDO1 0x200 0x200 + NodeID 0x205
RPDO2 0x300 0x300 + NodeID 0x305
RPDO3 0x400 0x400 + NodeID 0x405
RPDO4 0x500 0x500 + NodeID 0x505
Heartbeat 0x700 0x700 + NodeID 0x705

NMT状态转换

                    Reset Node (0x81)
                   ┌─────────────────┐
                   │                 │
                   ▼                 │
Initializing ──→ PreOperational ◄────┤
                   │        ▲        │
              Start│   Reset│Comm    │
              (0x01)│  (0x82)│       │
                   ▼        │        │
              Operational───┘        │
                   │                 │
              Stop│                  │
              (0x02)                 │
                   ▼                 │
              Stopped ───────────────┘

SDO协议格式

上传请求(读):

[40h][Index_L][Index_H][SubIndex][00][00][00][00]

上传响应:

[4Fh][Index_L][Index_H][SubIndex][Data][00][00][00]  // 1字节
[4Bh][Index_L][Index_H][SubIndex][Data_L][Data_H][00][00]  // 2字节
[43h][Index_L][Index_H][SubIndex][Data0][Data1][Data2][Data3]  // 4字节

下载请求(写):

[23h][Index_L][Index_H][SubIndex][Data0][Data1][Data2][Data3]  // 4字节

下载响应:

[60h][Index_L][Index_H][SubIndex][00][00][00][00]

🛠️ 调试技巧

1. 使用CAN分析仪

推荐使用以下工具抓包分析:

  • CANalyzer
  • PCAN-View
  • USBCAN Tools
  • SocketCAN (Linux)

2. 验证通信流程

1. PLC发送NMT Start (COB-ID: 0x000, Data: 01 05)
2. 从站回复Heartbeat (COB-ID: 0x705, Data: 05)
3. PLC配置PDO映射(通过SDO)
4. PLC发送SYNC (COB-ID: 0x080)
5. 从站发送TPDO (COB-ID: 0x185)
6. PLC发送RPDO (COB-ID: 0x205)

3. 常见问题排查

问题1:从站无响应

  • 检查CAN总线接线(CAN_H/CAN_L)
  • 验证波特率是否一致
  • 确认终端电阻(120Ω)已安装
  • 检查节点ID配置

问题2:PDO无数据

  • 确认从站处于Operational状态
  • 验证PDO已启用
  • 检查映射配置是否正确
  • 查看COB-ID是否匹配

问题3:心跳超时

  • 检查心跳时间设置
  • 确认从站未进入Stopped状态
  • 验证CAN通信正常

📚 参考资料

CANopen标准

  • CiA 301: CANopen应用层协议
  • CiA 302: CANopen行规
  • CiA 305: CANopen分层协议

相关文档

在线资源

💡 扩展开发

添加自定义对象

// 在ObjectDictionary.cs的InitializeStandardObjects()中添加
Write(0x2000, 0x00, (byte)0x12);  // 自定义参数

实现紧急消息

// 在CanOpenSlave.cs中添加
public void SendEmergency(ushort errorCode)
{
    byte[] emcyData = new byte[8];
    emcyData[0] = (byte)(errorCode & 0xFF);
    emcyData[1] = (byte)(errorCode >> 8);
    emcyData[2] = 0x00; // Error Register
    
    uint emcyCobId = 0x080 + m_nodeId;
    m_canManager.SendCanFrame(emcyCobId, emcyData);
}

实现SYNC消费者

// 在ProcessCanFrame()中添加SYNC处理
if (cobId == 0x080)
{
    // 收到SYNC,触发周期性TPDO
    if (m_currentState == NmtState.Operational)
    {
        for (byte pdo = 1; pdo <= 4; pdo++)
        {
            if (m_tpdoConfigs[pdo-1].TransmissionType > 0 && 
                m_tpdoConfigs[pdo-1].TransmissionType <= 240)
            {
                // 根据SYNC计数器决定是否发送
                m_syncCounter++;
                if (m_syncCounter % m_tpdoConfigs[pdo-1].TransmissionType == 0)
                {
                    SendTpdo(pdo);
                }
            }
        }
    }
}

📝 更新日志

v1.0.0 (2026-05-08)

  • ✅ 实现完整的CANopen从站功能
  • ✅ 支持NMT、SDO、PDO、心跳
  • ✅ 实现EDS文件生成器
  • ✅ 提供完整的使用示例和文档

📄 许可证

本项目仅供学习和测试使用。

👥 贡献

欢迎提交Issue和Pull Request!


祝使用愉快! 🎉

如有问题,请参考详细文档或查阅CANopen标准协议。