使用Python通过Modbus向Siemens Logo 8发送比特失败求助
如何通过Python的Modbus TCP触发西门子设备的BO31条件?
我尝试使用Python从IP为192.168.0.2的PC,向IP为192.168.0.11:504的西门子网络输入发送1比特数据,但未能成功实现。我的目标是通过Modbus连接发送比特以触发BO31条件,以下是我编写的Python代码:
import socket from umodbus import conf from umodbus.client import tcp # Enable values to be signed (default is False). conf.SIGNED_VALUES = True ### Creating connection sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('192.168.0.11', 504)) message = tcp.write_multiple_coils(slave_id=1, starting_address=1, values=[1, 0, 0, 0]) # Response depends on Modbus function code. This particular returns the # amount of coils written, in this case it is. response = tcp.send_message(message, sock) print(response) sock.close() print("Transfer finished")请协助排查问题并提供解决方案。
问题排查与解决方案
我来帮你一步步拆解可能的问题,并给出针对性的解决办法:
1. 先确认西门子设备的Modbus核心配置
西门子设备(比如S7系列)默认不会自动开启Modbus TCP服务,这是最常见的坑:
- 检查设备端是否启用了Modbus TCP服务器,端口是否确实是504(注意:标准Modbus TCP端口是502,504属于非标准端口,必须和设备配置完全一致)。
- 核对Slave ID(站号):你代码里写的是1,但西门子设备的Modbus站号可能不是默认值,一定要在TIA Portal或设备的通信配置界面里确认。
- 找到BO31对应的Modbus地址:你当前写的起始地址1不一定对应BO31。西门子的Modbus地址映射有规则,比如输入继电器I对应离散输入(功能码2),输出线圈Q对应线圈(功能码1/5/15),必须查设备的官方文档或配置工具里的地址映射表,确认BO31绑定的具体Modbus地址。
2. 修正代码中的冗余/错误参数
- 去掉
conf.SIGNED_VALUES = True:写入线圈是布尔值,完全不需要启用有符号值,这个设置可能干扰数据解析。 - 改用
write_single_coil更稳妥:你只需要触发1个比特,用单线圈写入函数比多线圈更直接,减少地址偏移出错的概率。 - 添加异常捕获:你的代码没有处理连接或发送失败的情况,根本不知道是哪一步出问题,比如连接失败直接崩溃,看不到错误信息。
3. 排查网络层面的问题
- 先ping设备:在CMD里执行
ping 192.168.0.11,确认PC和设备在同一网段且连通。 - 测试端口是否开放:用
telnet 192.168.0.11 504验证端口是否能正常访问,连接失败的话要么是设备端口没开,要么是防火墙拦截(包括PC端和设备端的防火墙)。
修正后的示例代码
假设你核对后,BO31对应的Modbus线圈地址是0,站号1,端口504,修正后的代码如下:
import socket from umodbus.client import tcp # 创建连接并添加错误处理 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect(('192.168.0.11', 504)) print("成功连接到设备") except Exception as e: print(f"连接失败: {str(e)}") sock.close() exit() # 写入单个线圈触发BO31 try: # 把address替换为BO31对应的实际Modbus地址 message = tcp.write_single_coil(slave_id=1, address=0, value=1) response = tcp.send_message(message, sock) print(f"线圈写入成功,响应: {response}") except Exception as e: print(f"发送消息出错: {str(e)}") sock.close() print("传输完成")
内容的提问来源于stack exchange,提问作者Paulius Ženčius
相关产品推荐
相关产品推荐

