S7Comm(S7 Communication)是西门子专有的协议,是西门子S7通讯协议簇里的一种。
S7通信协议是西门子S7系列PLC内部集成的一种通信协议,是S7系列PLC的精髓所在。 它是一种运行在传输层之上的(会话层/表示层/应用层)、经过特殊优化的通信协议,其信息传输可以基于MPI网络、PROFIBUS网络或者以太网
S7在TCP连接上后还需要进行两次握手
S7协议的TCP/IP实现依赖于面向块的ISO传输服务。S7协议被封装在TPKT和ISO-COTP协议中,这使得PDU(协议数据单元)能够通过TCP传送。
s7协议
1需要通过socket三次握手,不用写握手过程
目前提供设备型号s71200 cpu:1212c
电压是24vDC
建立连接过程
TcpClient client = new TcpClient();
client.Connect("ip地址",端口号);//连接PLC网络地址
// 2第一次请求连接 发送请求帧为
// 总共22字节
byte[] bs1 = new byte[]
{
0x03,//1字节版本号 默认是03
0x00,//保留值默认为0
0x00,0x16,//2字节 报文的总长度
0x11,// 1字节 从该字节往后字节个数 十进制是17
0xE0,//PDU 类型
0x00,0x00,//DST引用 默认值
0x00,0x01,//src引用
0x00,//采用默认值
0xc1,// 上位机参数
0x02,// 参数长度
0x10,0x00,//0x10代表双边通信 0x00机架号和插槽号
0xC2,//plc参数
0x02,//长度
0x03,0x01,//0x01和0x00共同控制机架号和插槽
0xC0,
0x01,
0x0A,//TPDU长度
};
client.GetStream().Write(bs1,0,bs1.Length);
//第二次请求连接 发送请求帧为
bs1 = new byte[]
{
0x03,//版本号
0x00,//保留值默认为0
0x00,0x19,//整个报文的长度
0x02,//COTP当前字节后的字节数
0xF0,//PUD类型
0x80,//最高十进制128
0x32,//协议ID,固定值
0x01,//工作类型 0x01主站发送请求
0x00,0x00,
0x00,0x00,
0x00,0x08,//参数长度
0x00,0x00,//数据长度
0xF0,//功能码
0x00,//保留值
0x00,0x03,//允许操作最大工作队列
0x00,0x03,
0x03,0xc0//允许处理最大字节数
};
client.GetStream().Write(bs1,0,bs1.Length);
MessageBox.Show("连接成功");
读取过程
读取数据必须知道:
1 plc存储那个区里面
0x83 M存储之间
0x84 DB块
0x81 I存储空间
0x82 Q输出存储空间
2数据存储在那个地址上 00 03 20
3读取数据的长度
03 00 00 1F 02 F0 80 30 01 0 00 00 01 00 0E 00 00 04 01 012 0A 10 02 00 02 00 00 83 00 03 20
先连接进行socket三次握手在判断是否连接成功 在进行读取显示label
Socket socket;
//连接按钮事件
private void button1_Click(object sender, EventArgs e)
{
//socket三次握手
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("ip地址", 端口号);
if (socket.Connected)//连接成功
{
StartReceive();//接收数据
}
//两次连接请求
//第一次连接请求
byte[]bs=new byte[]
{
0x03,// 1字节版本号 默认是03
0x00,// 1字节 保留值 默认0
0x00, 0x16,//2字节 报文的总长度
0x11,//1字节从该字节往后字节个数 十进制是17
0xE0,//PDU 类型
0x00,0x00,// DST引用 默认值
0x00,0x01,//src引用
0x00,//采用默认值
0xc1,// 上位机参数
0x02,// 参数长度
0x10,0x00, // 0x10 代表双边通信 0x00机架号和插槽号
0xC2, // plc参数
0x02 ,// 长度
0x03,0x01,// 0x01和0x00 共同控制机架号和插槽
0xC0,
0x01,
0x0A //TPDU长度
};
socket.Send(bs);//第一次发送
bs = new byte[]
{
0x03,///1字节版本号 默认是03
0x00,// 1字节 保留值 默认0
0x00, 0x19,//2字节 报文的总长度
0x02,//当前字节后的字节数
0xF0,//PDU类型 数据传输
0x80,//最高是十进制128
0x32,//协议ID,固定值
0x01,//工作类型 0x01 主站发送请求
0x00,0x00,
0x00,0x00,
0x00,0x08,//参数长度
0x00,0x00,//数据长度
0xF0,//功能码
0x00,//Reserved保留值
0x00,0x03,// 允许操作最大工作队列
0x00,0x03,
0x03,0xc0 //运行处理最大字节数组
};
socket.Send(bs);//第二次发送
MessageBox.Show("连接成功");
}
//读取
private void button2_Click(object sender, EventArgs e)
{
//发送请求帧 请求M14数据 地址从14开始 读取一个数据
byte[] data = new byte[]
{
//TPKT:版本号 预留号 总字节长度
0x03,//版本号
0x00,//预留号
0x00,0x1F,//总长度
//COTP块:
0x02,//往下的长度
0xF0,//PDU类型 数据传输
0x80,//目标引用
//s7-header s7头
0x32,//协议id默认
0x01,//主站开始发请求
0x00,0x00,//预留位置
0x03,0x7d,//随机生成的数字 每次在基础之上递增
0x00,0x0e,//参数长度
0x00,0x00,//数据长度
//s7-参数部分
0x04,//功能码 读取功能
0x01,//如果涉及多读的时候 设置为1
0x12,//结构标识 一般默认12
0x0a,//往后的字节长度
0x10,//寻址模式
0x02,//读取的数据类型 02是字节类型
0x00,0x01,//读取长度
0x00,0x00,//读取不是DB区
0x83,//0x83M存储区 ,0x84DB块
0x00,0x00,0x70//开始数据的地址
//例如 M3000,实际地址是30000*8=2400000 把转成三个字节 转成16进制3a980 对应三个地址,0x03,0xA9 0x80
//例如数据DB块的数据,DB21234.4000,其中DB号是21234 转成16进制0x52F2,DB区改为0x52,02 F2
//4000*8=32000,转成16进制7d00转成三个字节变成 0x00,0x7d,0x00
};
socket.Send(data);
}
void StartReceive()
{
Task.Run(() =>
{
byte[] bs1 = new byte[1024];
while (true)
{
int count= socket.Receive(bs1);
if (count == 0)
{
break;
}
//前两次弹出的是连接的响应
//读取的响应 FF(读取成功的标志) 04(读取数据的类型) 00 08(数据的长度) 0C(数据)
MessageBox.Show(BitConverter.ToString(bs1, 0, count));
label1.Invoke((Action)(() =>
{
label1.Text = bs1[25].ToString();
}));
}
});
}
写入数据 如写M14地址1个字节 M2000地址4字节
byte[] value = BitConverter.GetBytes(int.Parse(textBox1.Text));
//写入M14地址 写一个字节36
//写入M2000地址 写入4个字节
//生成写的报文
byte[] bs = new byte[]
{
//会话层
0x03,//版本号
0x00,//预留号
0x00,0x24,//M14地1个字节址 报文总长度36
0x00,0x27,//M2000地址 4个字节报文长度为39
//COPT 表示层
0x02,//长度
0xF0,//PDU类型 数据传输
0x80,//目标引用
//s7-header
0x32,//协议id
0x01,//主站开始请求
0x00,0x00,//预留部分
0x03,0x7d,//随机生成
0x00,0x0E,//参数长度
// 0x00,0x05,//参数数据长度 M14
0x00,0x08,//参数数据长度
//s7-参数
0x05,//功能码 05代表写, 04代表读取
0x01,//通信项数 可以支持多写
0x12,//变量指定
0x0A,//后面长度
0x10,
0x02,//传输的数据类型 字节
// 0x00,0x01,M14 //操作数据的长度
0x00,0x04,//写入M2000
0x00,0x00,//M区 不是DB区
0x83,//M区
//0x00,0x00,0x70,//开始写入M14地址
0x00,0x3E,0x80,//2000写入地址
0x00,
0x04,//字节类型
// 0x00,0x08, M14// 写入数据的长度 8位一个
0x00,0x20,//M2000 写入数据的长度 8位一个 4*8=32 16进制20
// byte.Parse(this.textBox1.Text),//写入数据
value[3],value[2],value[1],value[0]//写入M2000写入4个
};
tcp.Send(bs);
type = RequestType.Write;