您的位置:首页 > 文旅 > 旅游 > 今日乌鲁木齐好消息_有创意的宣传方式有哪些_网站优化方案案例_香飘飘奶茶软文

今日乌鲁木齐好消息_有创意的宣传方式有哪些_网站优化方案案例_香飘飘奶茶软文

2025/4/2 14:35:21 来源:https://blog.csdn.net/lu2023_8_6/article/details/146602903  浏览:    关键词:今日乌鲁木齐好消息_有创意的宣传方式有哪些_网站优化方案案例_香飘飘奶茶软文
今日乌鲁木齐好消息_有创意的宣传方式有哪些_网站优化方案案例_香飘飘奶茶软文

目录

西门子s7协议

西门子PLC数据类型

PLC中类型与C#对应类型

特殊说明:

S7协议帧结构

示例代码(C#访问PLC数据):

上位机和西门子PLC的通讯

西门子PLC的存储区

S7协议通讯网络模型

S7协议栈基于ISO/OSI模型,但主要实现以下4层:

S7协议的主要通信方式

s7协议通讯流程

COTP连接(第一次握手)报文

完整报文示例(Hex格式) 

S7连接(第二次握手)报文

读取格式

关键差异说明

写入格式

关键差异说明

 完整代码


 

西门子S7通信协议(S7 Communication Protocol)是西门子为其SIMATIC S7系列PLC(如S7-200、S7-300、S7-400、S7-1200、S7-1500)开发的一套工业自动化通信协议,主要用于PLC与HMI(人机界面)、SCADA系统、上位机(如PC)、其他PLC或工业设备之间的数据交换。

西门子s7协议

S7Comm(S7 Communication)是西门子专有的协议,是西门子S7通讯协议簇里的一种。
S7通信协议是西门子S7系列PLC内部集成的一种通信协议,是S7系列PLC的精髓所在。它是一种运行在传输层之上的(会话层/表示层/应用层)、经过特殊优化的通信协议,其信息传输可以基于MPI网络、PROFIBUS网络或者以太网S7在TCP连接上后还需要进行两次握手,S7协议的TCP/IP实现依赖于面向块的ISO传输服务。S7协议被封装在TPKT和ISO-COTP协议中,这使得PDU(协议数据单元) 能够通过TCP传送。

西门子PLC数据类型

PLC 数据类型

基本数据类型:包括位、位字符串、整数、浮点数、定时器、日期&时间、字符、数组和结构

PLC中类型与C#对应类型

PLC数据类型
PLC数据类型 (西门子)C# 对应类型存储大小值范围示例
BOOL (位)bool1 bittrue/falseI0.0, Q1.1
BYTE (字节)byte8 bits0-255IB0
WORD (字)ushort16 bits0-65535MW10
DWORD (双字)uint32 bits0-4,294,967,295MD20
INT (短整数)short16 bits-32,768~32,767DB1.DBW0
DINT (双整数)int32 bits-2,147,483,648~2,147,483,647DB2.DBD4
USINT (无符号短整数)byte8 bits0-255-
UINT (无符号整数)ushort16 bits0-65,535-
UDINT (无符号双整数)uint32 bits0-4,294,967,295-
REAL (浮点数)float32 bits±1.5×10⁻⁴⁵~±3.4×10³⁸DB3.DBD8
LREAL (长浮点数)double64 bits±5.0×10⁻³²⁴~±1.7×10³⁰⁸DB4.DBD12
CHAR (字符)char8 bitsASCII字符'A'
STRING (字符串)string可变长度最大254字符"Hello"
TIME (时间间隔)TimeSpan32 bits0~2,147,483,647 msT#1D2H3M4S
DATE_AND_TIME (日期时间)DateTime64 bits1970-01-01~2106-02-07DT#2023-10-01-14:30:00

特殊说明:

  1. PLC数组 → C#数组(如 REAL[10] → float[]

  2. PLC结构体(STRUCT) → C# class 或 struct

  3. TIME 类型在西门子PLC中以毫秒存储,C#用 TimeSpan 表示时间间隔

  4. DATE_AND_TIME 在C#中对应完整的 DateTime 结构

  5. 字符串处理需注意:西门子STRING前2字节存储长度信息(如 [长度][最大长度][字符数据]

S7协议帧结构

1 TPKT 会话层  主要设置版本号 预留号 报文总长度
2  COPT 表示层  设置PDU类型
3  s7协议 应用层 设置协议头和协议参数等

示例代码(C#访问PLC数据):

// 使用S7.Net库读取不同类型数据
var plc = new Plc(CpuType.S71500, "192.168.1.10", 0, 1);
plc.Open();// 读取不同类型
bool boolVal = plc.Read("I0.0");          // BOOL
byte byteVal = plc.Read("MB0");           // BYTE
ushort wordVal = plc.Read("MW2");         // WORD
int intVal = plc.Read("DB1.DBW4");        // INT
float realVal = plc.Read("DB1.DBD8");     // REAL
DateTime dtVal = plc.Read("DB1.DBD12");   // DATE_AND_TIMEplc.Close();

上位机和西门子PLC的通讯

西门子PLC的存储区

  • I:输入

  • Q:输出

  • AI:模拟量输入

  • V/DB:变量存储区

可以使用modbus协议和s7协议和plc进行通讯,但是modbus协议只能请求上面四个区,西门子plc还有M:位区、T:定时器...​,使用S7协议可以操作所有的区

S7协议通讯网络模型

S7协议栈基于ISO/OSI模型,但主要实现以下4层:

  1. 物理层(第1层)

    • 支持多种物理介质:RS485、工业以太网(PROFINET)、MPI等

    • 典型传输速率:9.6Kbps-100Mbps(取决于具体实现)

  2. 数据链路层(第2层)

    • 对于MPI/PROFIBUS网络使用西门子专有的第2层协议

    • 对于PROFINET/工业以太网使用标准的IEEE 802.3协议

  3. 网络层(第3层)

    • 使用西门子专有的网络层协议

    • 处理设备寻址和路由

  4. 传输层(第4层)

    • 使用西门子专有的传输协议

    • 提供可靠的端到端数据传输

  5. 应用层(第7层)

    • S7通信协议本身

    • 包含多种服务功能如读写变量、控制PLC等

S7协议的主要通信方式

  1. S7基本通信

    • 用于简单的数据交换

    • 基于OSI模型的第1-3层

  2. S7通信(扩展通信)

    • 更复杂的数据交换

    • 基于OSI模型的第1-4层

    • 提供更多服务功能

  3. S7函数通信

    • 用于远程函数调用

    • 基于OSI模型的完整7层

s7协议通讯流程

 TCP三次握手(TCP连接时进行) => COTP连接(第一次握手连接) => S7连接(第二次握手) => 数据的读写

COTP连接(第一次握手)报文

第一次连接握手
字段分类字段名称字节位置长度(字节)示例值(Hex)说明
TPKT头部版本号010x03

TPKT协议版本,固定为

0x03

保留位110x00保留字段,默认为0
报文总长度2-320x0016整个报文长度(22字节)
COTP会话层COTP数据长度410x11

后续COTP数据长度(17字

节)

PDU类型510xE00xE0表示连接请求(CR)
目标引用6-720x0000初始为0,由服务器分配
源引用8-920x0001客户端生成的标识
扩展格式1010x00

流控制标志(默认0)

COTP参数部分源TSAP标识1110xC1

0xC1表示源TSAP(上位机)

源TSAP长度1210x02

源TSAP参数长度(2字节)

源TSAP值13-1420x1000

连接模式:0x10(S7双边通信)

目标TSAP标识1510xC2

0xC2表示目标TSAP(PLC)

目标TSAP长度1610x02

目标TSAP参数长度(2字节)

目标TSAP值17-1820x0301

机架号0x03(0),槽

号0x01(1)

TPDU大小标识1910xC0

0xC0表示TPDU大小参数

TPDU大小长度2010x01

TPDU大小参数长度(1字节)

TPDU大小值2110x0A

2^10=1024字节(最大传

输单元)

完整报文示例(Hex格式) 

03 00 00 16 11 E0 00 00 00 01 00 C1 02 10 00 C2 02 03 01 C0 01 0A

S7连接(第二次握手)报文

使用tcp五次握手链接

public partial class Form1 : Form
{public Form1(){InitializeComponent();}/// <summary>/// 五次握手/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button1_Click(object sender, EventArgs e){// s7协议// 1 需要通过socket三次握手,不用写握手过程// 目前提供设备型号s71200  cpu:1212c    电压是24vDCTcpClient client = new TcpClient();client.Connect("192.168.107.202",102); // 连接服务器receiveData(client);// 2 第一请求连接  发送请求帧为// 总共22个字节byte[] bs1 = new byte[]{0x03, // 1字节版本号 默认是030x00, // 1字节 保留值 默认00x00, 0x16, // 2 字节 报文的总长度0x11, // 1字节从该字节往后字节个数 十进制是170xE0, // PDU 类型0x00,0x00, // DST引用 默认值0x00,0x01, // src引用0x00, // 采用默认值0xc1, // 上位机擦书0x02, // 上位机长度0x10,0x00, // 0x01代表双边通信 0x00机架号和插槽号0xC2, // plc参数0x02, // 长度0x03,0x01, // 0x01和0x00 共同控制机架号和插槽0xC0,0x01,0x0a};client.GetStream().Write(bs1,0,bs1.Length); // 发送第一次请求帧 // 3 第二次请求连接 发送请求帧为bs1 = new byte[]{0x03, // 1字节版本号 默认是030x00, // 1字节 保留值 默认00x00, 0x19, // 2 字节 报文的总长度0x02, // 当前字节后的字节数0xF0, // PUD类型 数据传输0x80, // 最高是十进制1280x32, // 协议ID,固定值0x01, // 工作类型 0x01 主站发送请求0x00,0x00,0x00,0x00,0x00,0x08, // 参数长度0x00,0x00, // 数据长度0xF0, // 功能码0x00, // Reserved保留值0x00,0x03, // 允许操作最大工作队列0x00,0x03, 0x03,0xc0, // 允许处理最大字节数组};client.GetStream().Write(bs1,0,bs1.Length);MessageBox.Show("连接成功");}/// <summary>/// 接收响应数据集/// </summary>/// <param name="tcpClient"></param>public void receiveData(TcpClient tcpClient){Task.Run(() =>{byte[] bytes = new byte[1024];while (tcpClient.Connected){// ONEint count = tcpClient.GetStream().Read(bytes,0,bytes.Length);if (count == 0) return;Console.WriteLine(BitConverter.ToString(bytes, 0, count) + "\r\n");// TWObyte[] s = new byte[count];Array.Copy(bytes,s,count);Console.WriteLine(string.Join(",",s));}});}
}

读取格式

读取报文

关键差异说明
  1. 报文长度

    • 请求报文总长度为31字节(0x001F),响应报文为29字节(0x001D)。

  2. ROSCTR字段

    • 请求报文为作业请求(0x01),响应报文为确认响应(0x03)。

  3. 数据长度

    • 请求报文数据长度为0(0x0000),响应报文为8字节(0x0008)。

  4. 返回数据

    • 响应报文包含实际读取的数据(0x000000-N),长度为32字节(0x0020)。

/// <summary>
/// 读取M区
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{// 发送请求帧 请求M区地址从00开始 读取一个数据// 读取数据时的请求帧byte[] data = new byte[] {// TPKT: 版本号 预留号 总字节长度0x03, // 版本号 0x00, // 预留号0x00,0x01F, // 总字节长度// COTP: 0x02, // 往下的长度0xF0, // PDU类型0x80, // 目标引用// s7-header s7头0x32, // 协议ID 默认0x01, // 主站开始发请求0x00,0x00, // 预留位置0x03,0x7b, // 随机生成的数字 每次在基础之上递增0x00,0x0e, // 参数长度0x00,0x00, // 数据长度// s7-参数部分0x04, // 功能码 读取功能                 重点0x01, // 如果涉及多读时候 设置为1,0x12, // 结构表示 一般默认120x0a, // 往后的字节长度0x10, // 寻址模式0x02, // 读取的数据类型 02是字节类型0x00,0x01, // 读取长度                   重点0x00,0x00, // 读取不是DB区               重点0x83, // 0x83 M存储区,0x84DB块          重点0x00,0x00,0x70, // 开始数据起始地址      重点// 列如M30000, 实际地址是30000*8=24 00000,把转成山歌字节,转成16进制3a980 对应三个地址,0x03,0xA9 0x80// 列如数据DB块的数据,DB21234,4000,其中DB号是21234 转成16进制0x52F2,DB区改为0x52,0xF2// 40000*8=,2000,转成16进制7d00 转成三个字节变成 0x00,0x7d,0x00};socket.Send(data);
}

 收取数据响应

/// <summary>
/// 接收响应数据
/// </summary>
void startReceive()
{Task.Run(() =>{byte[] bytes = new byte[1024];while (true){int count = socket.Receive(bytes);if (count == 0) break;// 转为16进制的字符串Console.WriteLine("十六进制打印:"+BitConverter.ToString(bytes,0,count));// 转为十进制打印byte[] datas = new byte[count];Array.Copy(bytes,datas,count);Console.WriteLine("十进制打印:" + string.Join(",",datas));Invoke(new Action(() =>{try{this.label1.Text = datas[25].ToString();}catch (Exception ex){Console.WriteLine(ex);}}));/* 响应的数据* 连接的响应* 03-00-00-16-11-D0-00-01-00-08-00-C0-01-0A-C1-02-10-00-C2-02-03-01* 03-00-00-1B-02-F0-80-32-03-00-00-00-00-00-08-00-00-00-00-F0-00-00-03-00-03-00-F0* * 读取数据的响应* 03-00-00-1A-02-F0-80-32-03-00-00-03-7B-00-02-00-05-00-00-04-01-FF(读取成功的标志)-04(读取的数据类型)-00-08(数据的长度)-0C(数据)*/}});
}

写入格式

写入报文

关键差异说明
  1. 报文长度

    • 请求报文总长度为36字节(0x0024),响应报文为29字节(0x001D)。

  2. 功能码

    • 请求报文为写入操作(0x05),响应报文可能复用读取功能码(0x04)或应为写入响应(需确认协议规范)。

  3. 数据内容

    • 请求报文包含写入地址(0x000000)和数据(0xFF),响应报文返回操作状态和可能的回读数据。

数据写入

/// <summary>
/// 写入M14
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{byte[] value = BitConverter.GetBytes(uint.Parse(textBox1.Text));// 生成写的报文byte[] bs = new byte[]{// TPKT部分0x03, // 版本号0x00, // 预留号// 0x00,0x24, // 报文总长度360x00,0x27, // 报文总长度39// TOPT0x02, // 长度0xF0, // PDU类型0xB0, // 目标引用// s7 header0x32, // 协议id0x01, // 主站开始请求0x00,0x00, // 预留部分0x03,0x7d, // 随机生成0x00,0x0E, // 参数长度0x00,0x08, // 参数数据长度// s7 参数0x05, // 05代表写入,04代表读取0x01, // 通信项数 可以支持多写0x12, // 变量指定0x0A, // 后面的长度0x10,0x02, // 传输数据类型 字节// 0x00,0x01, // 操作数据的长度0x00,0x04, // 操作数据的长度0x00,0x00, // M区 不是DB区0x83, // M区// 0x00,0x00,0x70, // 开始写入的地址M140x00,0x3e,0x80, // 开始写入的地址M20000x00,0x04, // 字节类型// 0x00,0x80, // 写入的长度  8位=1字节0x00,0x20, // 写入的长度  8位=1字节 (写入4个数据 4*8=32转16进制为20)//byte.Parse(textBox1.Text)value[3],value[2],value[1],value[0]};tcp.Send(bs);Type = RequestType.Write;
}

 完整代码

public partial class Form1 : Form
{TcpClientHelper tcp;public Form1(){InitializeComponent();}private void Tcp_OnClose(TcpClientHelper obj){MessageBox.Show("客户端关闭");}enum RequestType{Write,  // 写入请求Read,   // 读取请求Connect // 连接的请求}RequestType Type;private void Tcp_OnMessage(byte[] arg1, TcpClientHelper arg2){// 获取数据即可 自动触发BeginInvoke(new Action(() =>{switch (Type){case RequestType.Write:// 写入数据的响应Console.WriteLine("写入数据的响应"+BitConverter.ToString(arg1) );break;case RequestType.Read:// 读取数据的响应Console.WriteLine("读取数据的响应" + BitConverter.ToString(arg1));this.label1.Text = arg1[arg1.Length-1].ToString();break;case RequestType.Connect:Console.WriteLine("连接时的响应" + BitConverter.ToString(arg1));break;}}));}/// <summary>/// 写入M14/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button1_Click(object sender, EventArgs e){byte[] value = BitConverter.GetBytes(uint.Parse(textBox1.Text));// 生成写的报文byte[] bs = new byte[]{// TPKT部分0x03, // 版本号0x00, // 预留号// 0x00,0x24, // 报文总长度360x00,0x27, // 报文总长度39// TOPT0x02, // 长度0xF0, // PDU类型0xB0, // 目标引用// s7 header0x32, // 协议id0x01, // 主站开始请求0x00,0x00, // 预留部分0x03,0x7d, // 随机生成0x00,0x0E, // 参数长度0x00,0x08, // 参数数据长度// s7 参数0x05, // 05代表写入,04代表读取0x01, // 通信项数 可以支持多写0x12, // 变量指定0x0A, // 后面的长度0x10,0x02, // 传输数据类型 字节// 0x00,0x01, // 操作数据的长度0x00,0x04, // 操作数据的长度0x00,0x00, // M区 不是DB区0x83, // M区// 0x00,0x00,0x70, // 开始写入的地址M140x00,0x3e,0x80, // 开始写入的地址M20000x00,0x04, // 字节类型// 0x00,0x80, // 写入的长度  8位=1字节0x00,0x20, // 写入的长度  8位=1字节 (写入4个数据 4*8=32转16进制为20)//byte.Parse(textBox1.Text)value[3],value[2],value[1],value[0]};tcp.Send(bs);Type = RequestType.Write;}/// <summary>/// 读取M14/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button2_Click(object sender, EventArgs e){// 读取的报文31字节byte[] bs = new byte[]{0x03,0x00,0x00,0x1f,0x02,0xf0,0xb0,// 协议参数0x32,0x01,0x00,0x00,0x03,0x7d,0x00,0x0e,0x00,0x00, // 读取操作 为00x04,0x01,0x12,0x0a,0x10,0x02,//0x00,0x01, // 读取长度0x00,0x04, // M2000 读取四个字节0x00,0x00,0x83,// 0x00, 0x00,0x700x00,0x3e,0x80,};tcp.Send(bs);Type = RequestType.Read;}/// <summary>/// 连接/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Form1_Load(object sender, EventArgs e){// 1 创建客户端对象tcp = new TcpClientHelper();tcp.Connect("192.168.107.202", 102); // 连接服务器// 2 获取数据tcp.OnMessage += Tcp_OnMessage;// 3 关闭连接tcp.OnClose += Tcp_OnClose;// 第一次连接请求byte[] bs = new byte[]{0x03, // 1字节版本号 默认是030x00, // 1字节 保留值 默认00x00, 0x16, // 2 字节 报文的总长度0x11, // 1字节从该字节往后字节个数 十进制是170xE0, // PDU 类型0x00,0x00, // DST引用 默认值0x00,0x01, // src引用0x00, // 采用默认值0xc1, // 上位机擦书0x02, // 上位机长度0x10,0x00, // 0x01代表双边通信 0x00机架号和插槽号0xC2, // plc参数0x02, // 长度0x03,0x01, // 0x01和0x00 共同控制机架号和插槽0xC0,0x01,0x0a};tcp.Send(bs);// 第二次请求连接bs = new byte[]{0x03, // 1字节版本号 默认是030x00, // 1字节 保留值 默认00x00, 0x19, // 2 字节 报文的总长度0x02, // 当前字节后的字节数0xF0, // PUD类型 数据传输0x80, // 最高是十进制1280x32, // 协议ID,固定值0x01, // 工作类型 0x01 主站发送请求0x00,0x00,0x00,0x00,0x00,0x08, // 参数长度0x00,0x00, // 数据长度0xF0, // 功能码0x00, // Reserved保留值0x00,0x03, // 允许操作最大工作队列0x00,0x03,0x03,0xc0, // 允许处理最大字节数组};tcp.Send(bs);Type = RequestType.Connect;MessageBox.Show("连接成功");}
}

本文部分借鉴于网络,如有侵权请联系删除!!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com