问题描述
我尝试通过 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:
- 端口、节点和地址配置正确,由 CX-Programmer 中的在线工作"确认.我还 ping 每个 IP 以确保节点已连接.
UdpClient
代码是有效的,因为我编写了一个非常简单的服务器/客户端代码,可以成功发送和接收数据包.- 梯形逻辑没有问题.我将梯形图传输到 PLC 并在 Monitor 模式下通过 Work Online 进行测试并手动设置
D100
值.
- 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.
- The
UdpClient
code is valid since I wrote a very simple server / client code that successfully send and receive packets. - 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 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!