前言
在上一篇文章中,我们介绍了使用通信所需的 McpX 的各种设置(通信方式、帧格式、协议等)。
🔗 第2篇在这里
这次我们将重点介绍 McpX 所支持的 设备读取类命令,并配以示例代码进行说明。
使用的库
支持的设备读取命令一览
名称 | 说明 | 同步方法 | 异步方法 |
---|---|---|---|
单一读取 | 获取一个设备的值 | Read<T>(Prefix prefix, string address) | ReadAsync<T>(...) |
批量读取 | 从连续的设备中批量读取指定数量的数据 | BatchRead<T>(Prefix prefix, string address, ushort length) | BatchReadAsync<T>(...) |
随机读取 | 从不连续的地址中按字/双字读取 | RandomRead<T1, T2>((Prefix, string)[] wordAddresses, (Prefix, string)[] doubleWordAddresses) | RandomReadAsync<T1, T2>(...) |
设备地址的指定方法
在 McpX 中,指定PLC设备时,需要组合使用 Prefix
(设备类型)和 Address
(地址)。
Prefix
是一个枚举类型,例如要指定内部继电器(M),则使用 Prefix.M
,指定数据寄存器(D)时则使用 Prefix.D
。
Address
使用字符串表示。 指定十进制地址时,例如 "1234"
;指定十六进制地址时,例如 "4D2"
。
设备类型(Prefix)一览
名称 | 键值 |
---|---|
输入 | X |
输出 | Y |
内部继电器 | M |
保持继电器 | L |
报警器 | F |
边沿继电器 | V |
链路继电器 | B |
数据寄存器 | D |
链路寄存器 | W |
定时器接点 | TS |
定时器线圈 | TC |
定时器当前值 | TN |
累计定时器接点 | SS |
累计定时器线圈 | SC |
累计定时器当前值 | SN |
计数器接点 | CS |
计数器线圈 | CC |
计数器当前值 | CN |
链路特殊继电器 | SB |
链路特殊寄存器 | SW |
步进继电器 | S |
直接访问输入 | DX |
直接访问输出 | DY |
特殊继电器 | SM |
特殊寄存器 | SD |
索引寄存器 | Z |
文件寄存器(块) | R |
文件寄存器(连续) | ZR |
若设备地址指定错误,将抛出异常
DeviceAddressException
。异常条件:
对于十进制设备,地址中包含非数字字符
对于十六进制设备,地址中包含无法转换为十六进制的字符
指定读取数据类型的方法
McpX 使用泛型来指定读取的数据类型,通过方法的泛型参数 T
指定。 例如要读取 short
类型的单个值,使用 Read<short>(...)
即可。
支持的类型一览
类型 | 分类 |
---|---|
bool | 布尔值(真/假) |
short | 16位有符号整数 |
ushort | 16位无符号整数 |
int | 32位有符号整数 |
uint | 32位无符号整数 |
long | 64位有符号整数 |
ulong | 64位无符号整数 |
float | 单精度浮点数 |
double | 双精度浮点数 |
若指定了不支持的类型,将抛出
NotSupportedException
异常。
指定读取点数的方法
McpX 会根据指定的数据类型,自动计算所需的读取点数(字数)。
因此,各方法中的 length
参数应指定你希望在C#端获取的值的个数(数组元素数)。
例如读取2个 float
类型的值,每个值在PLC中占2个字(如 D0-D1, D2-D3),此时 length
设为 2
即可。 McpX 会根据类型自动处理字数,因此只需关注“类型”和“数量”。
各类型所需的字数
类型 | 占用字数 |
---|---|
bool | 1位(位设备) |
short | 1个字 |
int | 2个字 |
float | 2个字 |
double | 4个字 |
MC协议的批量读取命令对一次读取的最大点数有限制。
但 McpX 提供了自动拆包机制,即使超过协议限制,也会自动分包发送,因此无需用户关心协议细节。
但请注意:读取数量越多,通信负载越大,可能影响性能。
单一读取
读取指定的一个设备,并返回指定类型的值。
同步方法示例
从 D0 读取 16位有符号整数
short shortValue = mcpx.Read<short>(Prefix.D, "0");
异步方法示例
从 D10 读取 32位有符号整数
int intValue = await mcpx.ReadAsync<int>(Prefix.D, "10");
批量读取
从连续的设备中批量读取指定数量的数据,并以数组形式返回。
同步方法示例
从 D0 开始读取 100 个 short
值
short[] shortValues = mcpx.BatchRead<short>(Prefix.D, "0", 100);
异步方法示例
从 D10 开始读取 200 个 int
值
int[] intValues = await mcpx.BatchReadAsync<int>(Prefix.D, "10", 200);
随机读取
按字/双字单位读取指定的非连续设备,并返回各自类型的数组。
异步方法示例
从 D100, D110 读取 short
,从 D120, D130 读取 int
var drrArr = await mcpx.RandomReadAsync<short, int>(
wordAddresses: [
(Prefix.D, "100"),
(Prefix.D, "110")
],
doubleWordAddresses: [
(Prefix.D, "120"),
(Prefix.D, "130")
]
);
Console.WriteLine($"D100: { drrArr.wordValues[0] }");
Console.WriteLine($"D110: { drrArr.wordValues[1] }");
Console.WriteLine($"D120: { drrArr.doubleValues[0] }");
Console.WriteLine($"D130: { drrArr.doubleValues[1] }");
同步方法示例
从 D200, D210 读取 short
,从 D220, D230 读取 int
var drrArr = mcpx.RandomRead<short, int>(
wordAddresses: [
(Prefix.D, "200"),
(Prefix.D, "210")
],
doubleWordAddresses: [
(Prefix.D, "220"),
(Prefix.D, "230")
]
);
Console.WriteLine($"D200: { drrArr.wordValues[0] }");
Console.WriteLine($"D210: { drrArr.wordValues[1] }");
Console.WriteLine($"D220: { drrArr.doubleValues[0] }");
Console.WriteLine($"D230: { drrArr.doubleValues[1] }");
如何选择同步/异步方法
McpX 为所有读取命令都提供了同步和异步两种版本。
选择标准如下
适合使用同步方法的场景
-
控制台应用或批处理流程
-
不在意通信等待时的阻塞
-
希望保持逻辑简单(例如学习或调试阶段)
适合使用异步方法的场景
-
WPF、WinForms、ASP.NET 等需保持UI响应或服务器并发
-
通信过程中需保证应用不被阻塞
-
并行处理多个PLC或长时间通信
总结
本文介绍了用于与三菱PLC通信的 McpX 库中读取类命令的使用方法:
-
如何使用 Prefix + Address 指定设备
-
如何指定读取数量
-
如何使用
Read
,BatchRead
,RandomRead
方法 -
同步与异步方法的选用原则
另外,我们在 GitHub 上提供了示例项目,欢迎参考
👉 https://github.com/YudaiKitamura/McpX/tree/main/Example
下回我们将介绍 McpX 所支持的设备写入命令及其使用方法,并附带具体示例代码。
参考链接
如果你觉得这个项目对你有帮助,欢迎在 GitHub 上点个 ⭐Star 支持一下!
👉 GitHub地址:https://github.com/YudaiKitamura/McpX