|
|
1 lună în urmă | |
|---|---|---|
| .. | ||
| Dll | 1 lună în urmă | |
| Properties | 1 lună în urmă | |
| App.config | 1 lună în urmă | |
| CanLibraryClass.cs | 1 lună în urmă | |
| CanOpenManager.cs | 1 lună în urmă | |
| CanOpenSlaveDevice.cs | 1 lună în urmă | |
| CanOpenSlaveTest.csproj | 1 lună în urmă | |
| CanOpenSlaveTest.sln | 1 lună în urmă | |
| FIX_CHINESE_ENCODING.md | 1 lună în urmă | |
| FIX_DESIGNER_ERROR.md | 1 lună în urmă | |
| FIX_TYPE_CONVERSION.md | 1 lună în urmă | |
| IMPLEMENTATION_SUMMARY.md | 1 lună în urmă | |
| PROJECT_OVERVIEW.md | 1 lună în urmă | |
| Program.cs | 1 lună în urmă | |
| QUICKSTART.md | 1 lună în urmă | |
| README.md | 1 lună în urmă | |
| SlaveTestForm.cs | 1 lună în urmă | |
| SlaveTestForm.resx | 1 lună în urmă | |
本项目实现了一个基于Nameless.eds文件的CANopen从站设备,支持以下功能:
CanOpenSlaveDevice - 从站设备主类
CanOpenSlaveDevice.csCanOpenManager - CAN底层管理器
CanOpenManager.csCanLibraryClass - CAN卡驱动接口
CanLibraryClass.csNmtState - NMT状态枚举PdoConfig - PDO配置PdoMapping - PDO映射IdentityObject - 身份对象(1018h)TpdoCommParam - TPDO通信参数RpdoCommParam - RPDO通信参数using CCDCount.DLL.CanBus;
// 创建从站设备 (节点ID=1)
var slave = new CanOpenSlaveDevice(nodeId: 1);
// 注册事件
slave.OnRpdoReceived += (nodeId, pdoNum, data) => {
Console.WriteLine($"收到RPDO{pdoNum}");
};
slave.OnNmtStateChanged += (oldState, newState) => {
Console.WriteLine($"状态改变: {oldState} -> {newState}");
};
// 启动从站 (1Mbps波特率)
slave.Start(CanBaudRate.BaudRate_1M);
// 配置心跳 (100ms)
slave.ConfigureHeartbeat(100);
// 发送TPDO
slave.SendTpdo(1);
// 停止从站
slave.Stop();
slave.Dispose();
# 编译项目
msbuild CanOpenSlaveTest.sln
# 运行程序
cd bin\Debug
CanOpenSlaveTest.exe
根据Nameless.eds文件,从站设备配置如下:
| PDO编号 | 索引范围 | COB-ID公式 | 默认传输类型 |
|---|---|---|---|
| RPDO1 | 0x1400/0x1600 | 0x200 + nodeId | 0xFF (事件驱动) |
| RPDO2 | 0x1401/0x1601 | 0x300 + nodeId | 0xFF (事件驱动) |
| RPDO3 | 0x1402/0x1602 | 0x400 + nodeId | 0xFF (事件驱动) |
| RPDO4 | 0x1403/0x1603 | 0x500 + nodeId | 0xFF (事件驱动) |
| PDO编号 | 索引范围 | COB-ID公式 | 默认传输类型 |
|---|---|---|---|
| TPDO1 | 0x1800/0x1A00 | 0x180 + nodeId | 0xFF (事件驱动) |
| TPDO2 | 0x1801/0x1A01 | 0x280 + nodeId | 0xFF (事件驱动) |
| TPDO3 | 0x1802/0x1A02 | 0x380 + nodeId | 0xFF (事件驱动) |
| TPDO4 | 0x1803/0x1A03 | 0x480 + nodeId | 0xFF (事件驱动) |
public CanOpenSlaveDevice(
byte nodeId = 1, // 节点ID (1-127)
UInt32 deviceType = 4, // 设备类型 (4=USBCAN2)
UInt32 deviceIndex = 0, // 设备索引
UInt32 canIndex = 0 // CAN通道索引
)
Start() - 启动从站
public bool Start(CanBaudRate baudRate = CanBaudRate.BaudRate_1M)
Stop() - 停止从站
public void Stop()
SendTpdo() - 发送TPDO
public void SendTpdo(byte pdoNumber) // pdoNumber: 1-4
SendAllTpdos() - 发送所有启用的TPDO
public void SendAllTpdos()
ConfigureHeartbeat() - 配置心跳
public void ConfigureHeartbeat(ushort heartbeatTimeMs) // 0表示禁用
OnRpdoReceived - RPDO接收事件
public event Action<byte, byte, byte[]> OnRpdoReceived
// 参数: nodeId, pdoNumber, data
OnNmtStateChanged - NMT状态改变事件
public event Action<NmtState, NmtState> OnNmtStateChanged
// 参数: oldState, newState
OnSdoReadRequest - SDO读取请求事件
public event Action<byte, ushort, byte> OnSdoReadRequest
// 参数: nodeId, index, subIndex
OnSdoWriteRequest - SDO写入请求事件
public event Action<byte, ushort, byte, uint> OnSdoWriteRequest
// 参数: nodeId, index, subIndex, value
public byte NodeId { get; } // 节点ID
public NmtState CurrentState { get; } // 当前NMT状态
public bool IsRunning { get; } // 是否正在运行
Initializing (0x00)
↓ [NMT Reset]
PreOperational (0x7F) ←→ Operational (0x05)
↑ ↓ [NMT Stop]
└── Stopped (0x04)
A: 在构造函数中指定:
var slave = new CanOpenSlaveDevice(nodeId: 5); // 节点ID=5
A: 在Start()方法中指定:
slave.Start(CanBaudRate.BaudRate_500K); // 500kbps
A: 注册OnRpdoReceived事件:
slave.OnRpdoReceived += (nodeId, pdoNum, data) => {
// 处理data数组
int value = data[0] | (data[1] << 8);
};
A: 需要扩展CanOpenSlaveDevice类,添加自定义数据填充逻辑。
A: 使用ConfigureHeartbeat()方法:
slave.ConfigureHeartbeat(100); // 100ms心跳
slave.ConfigureHeartbeat(0); // 禁用心跳
程序会自动输出关键事件到控制台:
推荐使用以下工具监控CAN总线:
确保主站和从站的COB-ID配置一致:
在InitializeObjectDictionary()方法中添加:
// 例如: 添加0x2000自定义对象
m_objectDictionary[0x2000] = new MyCustomObject();
目前PDO映射功能为框架级别,需要根据实际应用完善:
// 在ProcessRpdo()中解析映射表
// 在SendTpdo()中根据映射表构建数据
可以扩展EMCY处理:
public void SendEmergency(ushort errorCode, byte errorRegister)
{
byte[] emcyData = new byte[8];
emcyData[0] = (byte)(errorCode & 0xFF);
emcyData[1] = (byte)((errorCode >> 8) & 0xFF);
emcyData[2] = errorRegister;
uint emcyCobId = 0x080 + m_nodeId;
m_canManager.SendCanFrame(emcyCobId, emcyData);
}
如有问题,请参考: