【C#】三菱PLC MC协议通信:1E帧与3E帧报文解析+C#上位机源码(附完整工程)
三菱PLC的MC协议(MELSEC Communication Protocol)是工业自动化领域最常用的通信协议之一,广泛应用于上位机、触摸屏、SCADA系统与FX系列、Q系列、L系列、iQ-R系列等PLC的数据交互。MC协议定义了多种帧格式,其中1E帧和3E帧是最具代表性的两种。理解这两种帧的报文结构,是掌握三菱PLC通信的核心基础。本文主要实现了D寄存器的读写功能。
一、MC协议概述
1.1 协议定位与特点
MC协议是三菱电机为其PLC产品家族开发的专用通信协议,属于请求-响应型协议。上位机(主站)主动发送请求报文,PLC(从站)接收解析后返回响应报文。协议工作在TCP/IP或串口(RS-232/RS-485)之上,具有标准化、结构化、可靠性高的特点。
MC协议的核心价值在于统一的地址访问模型。无论PLC内部是输入继电器X、输出继电器Y、内部继电器M、数据寄存器D,还是定时器T、计数器C,都可以通过标准化的报文格式进行读写操作。这种统一性使得上位机软件能够以一致的方式访问不同型号的三菱PLC。
1.2 帧格式的演进
三菱PLC的MC协议经历了多次演进,形成了多种帧格式:
- 1E帧:早期格式,结构简单,主要用于FX系列PLC的串口通信,功能相对基础
- 3E帧:扩展格式,功能更丰富,支持更多软元件类型和更大的数据量,适用于Q/L/iQ-R系列
- 4E帧:在3E帧基础上增加了路由功能,支持跨网络访问远程PLC
1E帧和3E帧是最常用的两种格式,本文将重点解析它们的报文结构。
二、1E帧报文结构详解
1E帧是MC协议中最简洁的帧格式,报文长度短、解析效率高,适合对通信效率要求较高的场景。
2.1 软元件分类及访问规则
注意这个操作方式中的bit和word,bit就是一个位,二进制中的位bit,0或1算一个位,word叫字,一个字就16位,就是2个字节,一个字节是8位,2个字节就是16位,也就是16个bit,在C#中就是2个ascii码,比如01就是2个字节,就是一个word,简单讲就是word占2个字节,另外0X是16进制的表示。
2.2 命令类型(功能码,副头部)
上述不管是读取还是写入的请求报文中,第一个字节是功能码,也就是指命令类型,A-1E的命令类型具体如下:
0x00 批量位读取
0x01 批量字读取
0x02 批量位写入
0x03 批量字写入
0x04 随机位写入
0x05 随机字写入
注意响应报文中的状态码00表示正常
2.3 读取数据的报文结构
2.4 写入数据的报文结构
2.5 1E帧的特点与局限
1E帧的最大优势是结构紧凑,报文开销小,在串口通信中能够有效节省带宽。但其功能也相对受限:
- 支持的软元件类型较少,主要覆盖常用的X、Y、M、D等
- 单次读写的数据量有限制
- 不支持路由功能,无法跨网络访问
- 错误信息较为简单,调试排错时需要更多经验
1E帧主要应用于FX系列PLC的串口通信场景,以及通信资源受限的嵌入式设备。
三、3E帧报文结构详解
3E帧是MC协议的主力帧格式,功能全面,是现代三菱PLC通信的首选。
3.1 存储区分类及访问规则
3.2 命令类型
命令由主命令+子命令组成
3.3 报文结构
注意:首地址应该是3字节
四、1E帧与3E帧的关键对比
| 对比维度 | 1E帧 | 3E帧 |
|---|---|---|
| 报文复杂度 | 结构简单,字段少 | 结构完整,字段丰富 |
| 数据长度字段 | 无显式长度字段 | 有显式数据长度字段 |
| 软元件支持 | 基础类型(X/Y/M/D等) | 全面支持,含扩展软元件 |
| 单次数据量 | 较小 | 较大 |
| 网络路由 | 不支持 | 支持多网络、多模块路由 |
| 错误信息 | 简单结束代码 | 详细的结束代码体系 |
| 随机访问 | 不支持 | 支持 |
| 适用PLC系列 | FX系列为主 | Q/L/iQ-R系列 |
| 适用通信介质 | 串口为主 | 以太网为主,也支持串口 |
五、关键代码实现
开发环境:Visual Studio 2022 + .NET 6.0 + Windows 10/11
5.1 1E阵协议组包
// <summary>/// 读组包/// </summary>/// <param></param>/// <param></param>/// <returns></returns>publicbyte[]Read(intaddr,intlength){byte[]sendData=null;try{intcount=0;byte[]bytes=newbyte[64];//1 请求副头部bytes[count++]=0x01;//1 PLC编号bytes[count++]=0xFF;//2 超时响应时间(每单位250毫秒)bytes[count++]=0x04;bytes[count++]=0x00;//2 首地址bytes[count++]=(byte)(addr&0xFF);bytes[count++]=(byte)((addr>>8)&0xFF);bytes[count++]=(byte)((addr>>16)&0xFF);bytes[count++]=(byte)((addr>>24)&0xFF);//Dbytes[count++]=0x20;bytes[count++]=0x44;//2 读取长度bytes[count++]=(byte