从 C# 向 PLC 发送 FINS 命令

Send FINS command from C# to PLC(从 C# 向 PLC 发送 FINS 命令)
本文介绍了从 C# 向 PLC 发送 FINS 命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试通过 UDP 从 PC (C#.NET) 向 PLC 以太网模块 (Omron) 发送 FINS 命令,但没有从 PLC 得到任何响应,也不知道从哪里开始疑难解答.

I try to send FINS commands through UDP from PC (C#.NET) to PLC Ethernet module (Omron), but is not getting any responds from the PLC and have no clue where I can start troubleshooting.

PLC 有一个非常简单的梯形逻辑如下:如果 DM100 的值为 #0001,则在输出 101.00 上触发.(这里Trigger"只是存储区D100的符号名,Output"是输出101.00的符号)

PLC has a very simple ladder logic as follow: If DM100 has value of #0001, then trigger on output 101.00. (Here, "Trigger" is just a symbol name for memory area D100, and "Output" is a symbol for output 101.00)

然后我写了一段C#,执行Memory Area Write"的FINS命令,命令代码为01 02,后跟起始地址、要写入的项目数和数据.C# 代码应将值 #0001 写入 PLC 的 D100 区域以在 101.00 上触发 ON.

Then I wrote a piece of C# that performs FINS command of "Memory Area Write" which has command code of 01 02, followed by beginning address, number of items to be written, and the data. The C# code should write a value of #0001 to PLC's D100 area to trigger ON on 101.00.

[删除的无效代码]..

输出 101.00 没有被触发,我也没有收到任何异常.我已经确定了以下几点:

The output 101.00 did not get triggered, nor I receive any exception. I have made sure the following:

  1. 端口、节点和地址配置正确,由 CX-Programmer 中的在线工作"确认.我还 ping 每个 IP 以确保节点已连接.
  2. UdpClient 代码是有效的,因为我编写了一个非常简单的服务器/客户端代码,可以成功发送和接收数据包.
  3. 梯形逻辑没有问题.我将梯形图传输到 PLC 并在 Monitor 模式下通过 Work Online 进行测试并手动设置 D100 值.
  1. Port, node and address configured correctly as confirmed by "Work Online" in CX-Programmer. I have also ping each IP to make sure nodes are connected.
  2. The UdpClient code is valid since I wrote a very simple server / client code that successfully send and receive packets.
  3. Ladder logic has no problem. I transfered the ladder to PLC and test out by Work Online in Monitor mode and setting D100 a value manually.

我怀疑 fins_cmnd 数组中存在错误,但从我的代码中可以看出,我已对每个值进行了尽可能详细的注释;我不可能发现自己缺少任何东西.我怀疑我可能没有正确解析十六进制,但同样,我没有例外来指导我.

I suspect there is mistake in the fins_cmnd array, but as seen in my code, I have commented as detail as possible on each value; I can't possibly find myself missing anything. I suspect I may not be parsing the hexadecimal correctly, but again, I have no exception to guide me.

我不知道在哪里以及如何进行故障排除.希望这里有FINS编程或PLC经验的人能给我一些帮助.

I have no idea where and how I can troubleshoot. Hope someone here with FINS programming or PLC experience can offer me some help.

[回答]
感谢 Porge 的链接 - 这让我发现了问题.经过几条小径终于让它工作了.工作代码见下文.

[ANSWER]
Thanks Porge for the link - that got me found out the problem. After a couple trails finally get it to work. See below for the working code.

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",但除非存在,否则不会将数字解析为十六进制.

None of those strings will be parsed as hexadecimal. NumberStyles.AllowHexSpecifier allows the hexadecimal prefix "0x" but doesn't parse the number as hex unless it is present.

所以你需要 (char)Int16.Parse("0x64", NumberStyles.AllowHexSpecifier).

但是,C# 中的数字文字可以是十六进制,因此您可以编写 0x64 来代替所有这些操作.

However, numeric literals in C# can be hexadecimal, so instead of doing all that you can just write 0x64 instead.

我刚刚查看了 此页面作为参考 用于协议,最好将消息直接创建为字节,而不是指定 Unicode 代码点并将其解码为 ASCII 字节.您还可以使用数组规范语法来消除很多混乱:

I've just looked at this page as a reference for the protocol, and it would also be better to create the message directly as bytes rather than specifying Unicode code points and decoding those to bytes as ASCII. You can also use the array specification syntax to remove a lot of clutter:

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 个字节.这些与您所拥有的不匹配,因此我扩展了该部分.

It also looks like there are some problems with your data section - according to the linked document the memory address should be 4 bytes, the write length 2 bytes, and the values 4 bytes each. These don't match with what you have, so I've expanded that section.

这篇关于从 C# 向 PLC 发送 FINS 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)