我尝试通过 UDP 从 PC (C#.NET) 向 PLC 以太网模块 (Omron) 发送 FINS 命令,但没有从 PLC 获得任何响应,也不知道从哪里开始故障排除。
PLC 有一个非常简单的梯形图逻辑如下:
如果 DM100
的值为 #0001
,则触发输出 101.00
。 (这里,“Trigger”只是存储区D100
的符号名,“Output”是输出101.00
的符号名)
然后我写了一段C#,执行“内存区域写入”的FINS命令,命令代码为01 02
,后面是起始地址、要写入的项目数和数据. C# 代码应将值 #0001
写入 PLC 的 D100
区域以在 101.00
触发 ON。
[删除了不起作用的代码]..
输出 101.00
没有被触发,我也没有收到任何异常。
我已确定以下内容:
- CX-Programmer 中的“在线工作”确认端口、节点和地址配置正确。我还对每个 IP 执行了 ping 操作,以确保节点已连接。
UdpClient
代码是有效的,因为我编写了一个非常简单的服务器/客户端代码,可以成功发送和接收数据包。- 梯形图逻辑没问题。我将梯形图传输到 PLC 并通过 Work Online 在监控模式下进行测试并手动设置
D100
一个值。
我怀疑 fins_cmnd
数组有误,但正如在我的代码中看到的那样,我已经对每个值进行了尽可能详细的注释;我不可能发现自己错过任何东西。我怀疑我可能没有正确解析十六进制,但同样,我也不异常(exception)地指导我。
我不知道在哪里以及如何解决问题。希望这里有 FINS
编程或 PLC 经验的人能给我一些帮助。
[答案]
感谢 Porge 提供的链接 - 这让我找到了问题所在。经过几次尝试后,终于让它开始工作了。请参阅下面的工作代码。
string SERV_IP_ADDR = "192.168.250.1";
const int FINS_UDP_PORT = 9600;
byte[] sendPacket = new byte[]
{
// Full UDP packet: 80 00 02 00 00 00 00 05 00 19 01 02 82 00 64 00 00 01 00 01
// Header
0x80, //0.(ICF) Display frame information: 1000 0001
0x00, //1.(RSV) Reserved by system: (hex)00
0x02, //2.(GCT) Permissible number of gateways: (hex)02
0x00, //3.(DNA) Destination network address: (hex)00, local network
0x00, //4.(DA1) Destination node address: (hex)00, local PLC unit
0x00, //5.(DA2) Destination unit address: (hex)00, PLC
0x00, //6.(SNA) Source network address: (hex)00, local network
0x05, //7.(SA1) Source node address: (hex)05, PC's IP is 192.168.250.5
0x00, //8.(SA2) Source unit address: (hex)00, PC only has one ethernet
0x19, //9.(SID) Service ID: just give a random number 19
// Command
0x01, //10.(MRC) Main request code: 01, memory area write
0x02, //11.(SRC) Sub-request code: 02, memory area write
// PLC Memory Area
0x82, //12.Memory area code (1 byte): 82(DM)
// Address information
0x00, //13.Write start address (2 bytes): D100
0x64,
0x00, //15.Bit address (1 byte): Default 0
0x00, //16.No. of items (2 bytes): only one address which is D100
0x01,
// Write Data
0x00, //18.Data to write (2 bytes): value is 1
0x01,
};
UdpClient client = new UdpClient(); //create a UdpClient instance
try
{
client.Send(sendPacket, sendPacket.Length, SERV_IP_ADDR, FINS_UDP_PORT);
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
}
client.Close();
最佳答案
这些字符串都不会被解析为十六进制。 NumberStyles.AllowHexSpecifier
允许十六进制前缀“0x”但不将数字解析为十六进制,除非它存在。
所以你需要 (char)Int16.Parse("0x64", NumberStyles.AllowHexSpecifier)
。
但是,C# 中的数字文字可以是十六进制的,因此您可以编写 0x64
而不是执行所有操作。
我刚看过 this page as a reference对于协议(protocol),最好直接将消息创建为字节而不是指定 Unicode 代码点并将它们解码为字节作为 ASCII。您还可以使用数组规范语法来消除大量困惑:
var message = new byte[]
{
// header
0x80, //(ICF) Display frame information: 1000 0001
0x00, //(RSV) Reserved by system: (hex)00
0x02, //(GCT) Permissible number of gateways: (hex)02
0x00, //(DNA) Destination network address: (hex)00, local network
0x00, //(DA1) Destination node address: (hex)00, local PLC unit
0x00, //(DA2) Destination unit address: (hex)00, PLC
0x00, //(SNA) Source network address: (hex)00, local network
0x05, //(SA1) Source node address: (hex)05, PC's IP is 192.168.250.5
0x00, //(SA2) Source unit address: (hex)00, PC only has one ethernet
0x19, //(SID) Service ID: just give a random number 19
// command
0x01, //(MRC) Main request code: 01, memory area write
0x02, //(SRC) Sub-request code: 02, memory area write
// data
0x82, //Memory area code, 2 bytes: 82(DM)
0x00, //Write start address DM100
0x64,
0x00,
0x00, //Word write: only one address
0x01,
0x00, //Write value of 1 to address DM100 (0000 0000 0000 0001)
0x01, // - this value is 0xaabbccdd -> cc dd aa bb
0x00,
0x00,
};
您的数据部分似乎也存在一些问题 - 根据链接文档,内存地址应为 4 字节,写入长度应为 2 字节,每个值应为 4 字节。这些与您拥有的不匹配,因此我扩展了该部分。
关于c# - 从 C# 向 PLC 发送 FINS 命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9695639/