3. S7comm 西门子PLC数据采集
任务目标
本案例实现一个基于 snap7 库的 Python 客户端,通过 S7comm 协议连接西门子 S7-1200 PLC,读取 DB1 块中偏移量为 0.0(Real)、4.0(Real)、8.0(Int)和 10.0(Bool)的生产数据,并在控制台输出。该案例覆盖从 TCP 连接到数据解析的完整最小闭环。
环境与依赖
- Python 3.8+
- 安装 snap7:
pip install python-snap7 - PLC 侧需开放 S7 通信(默认端口 102),并确保 DB1 为非优化访问(允许通过偏移读写)
完整实现代码
import snap7
from snap7.util import get_real, get_int, get_bool
from snap7.types import Areas
PLC_IP = "192.168.0.1" # 按实际 PLC IP 修改
RACK = 0 # S7-1200 通常为 0
SLOT = 1 # S7-1200 通常为 1
DB_NUMBER = 1 # 读取 DB1
START_OFFSET = 0 # 从 DB1.DBB0 开始读取
READ_LENGTH = 12 # 读取 12 字节(覆盖 0.0~11.7)
def read_plc_data():
"""连接 PLC 并读取 DB1 中的生产数据"""
client = snap7.client.Client()
try:
client.connect(PLC_IP, RACK, SLOT)
if not client.get_connected():
raise ConnectionError("无法连接到 PLC,请检查 IP、机架/槽位及网络")
# 一次性读取 12 字节,避免多次请求
data = client.db_read(DB_NUMBER, START_OFFSET, READ_LENGTH)
# 按偏移解析数据
temp_value = get_real(data, 0) # DB1.DBD0 - Real 温度值
pressure = get_real(data, 4) # DB1.DBD4 - Real 压力值
speed = get_int(data, 8) # DB1.DBW8 - Int 转速
alarm_flag = get_bool(data, 10, 0) # DB1.DBX10.0 - Bool 报警标志
print(f"温度: {temp_value:.2f} °C")
print(f"压力: {pressure:.2f} bar")
print(f"转速: {speed} rpm")
print(f"报警标志: {alarm_flag}")
except snap7.snap7exceptions.Snap7Exception as e:
print(f"S7 通信错误: {e}")
except Exception as e:
print(f"发生错误: {e}")
finally:
client.disconnect()
if __name__ == "__main__":
read_plc_data()
运行与验证
- 将代码中
PLC_IP修改为实际 PLC 地址。 - 在 PLC 侧创建 DB1,定义变量:
DB1.DBD0: Real(温度)、DB1.DBD4: Real(压力)、DB1.DBW8: Int(转速)、DB1.DBX10.0: Bool(报警标志)。 - 确保 DB1 的属性中关闭“优化的块访问”(即支持寻址)。
- 运行脚本:
python s7_read.py
通过条件:控制台输出 4 行数据,且数值与 PLC 监控表中当前值一致。若输出 S7 通信错误,检查 IP、机架/槽位、DB 号及 PLC 访问权限。
常见问题
- 连接超时:确认 PLC 的 PUT/GET 通信已允许(在 PLC 属性中勾选“允许来自远程对象的 PUT/GET 通信访问”)。
- 数据解析错误:检查 DB1 是否为优化访问——优化 DB 无法通过偏移读取,需在 DB 属性中取消勾选“优化的块访问”。
- 字节序:snap7 默认按大端解析,与 S7-1200 默认一致,无需额外处理。