news 2026/4/16 12:52:04

灯的远程控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
灯的远程控制

已知虚拟仿真电路如图所示:用Python编程实现在窗口中通过开关控制灯的开关。

import tkinter as tk from tkinter import messagebox import serial # 定义ADAM4150各通道开关指令 DO_COMMANDS = { "DO0": {"开": "01 05 00 10 FF 00 8D FF", "关": "01 05 00 10 00 00 CC 0F"}, "DO1": {"开": "01 05 00 11 FF 00 DC 3F", "关": "01 05 00 11 00 00 9D CF"}, "DO2": {"开": "01 05 00 12 FF 00 2C 3F", "关": "01 05 00 12 00 00 6D CF"}, "DO3": {"开": "01 05 00 13 FF 00 7D FF", "关": "01 05 00 13 00 00 3C 0F"}, "DO4": {"开": "01 05 00 14 FF 00 CC 3E", "关": "01 05 00 14 00 00 8D CE"}, "DO5": {"开": "01 05 00 15 FF 00 9D FE", "关": "01 05 00 15 00 00 DC 0E"}, "DO6": {"开": "01 05 00 16 FF 00 6D FE", "关": "01 05 00 16 00 00 2C 0E"}, "DO7": {"开": "01 05 00 17 FF 00 3C 3E", "关": "01 05 00 17 00 00 7D CE"} } class Adam4150Controller: def __init__(self, root): self.root = root self.root.title("ADAM4150 继电器控制器") self.ser = None self.setup_ui() def setup_ui(self): # 串口设置区域 port_frame = tk.Frame(self.root, padx=10, pady=10) port_frame.pack(fill=tk.X) tk.Label(port_frame, text="串口:").grid(row=0, column=0, padx=5, pady=5) self.port_entry = tk.Entry(port_frame, width=10) self.port_entry.grid(row=0, column=1, padx=5, pady=5) self.port_entry.insert(0, "COM100") tk.Label(port_frame, text="波特率:").grid(row=0, column=2, padx=5, pady=5) self.baud_entry = tk.Entry(port_frame, width=10) self.baud_entry.grid(row=0, column=3, padx=5, pady=5) self.baud_entry.insert(0, "9600") self.connect_btn = tk.Button(port_frame, text="打开串口", command=self.connect_serial) self.connect_btn.grid(row=0, column=4, padx=10, pady=5) # 继电器控制区域 control_frame = tk.Frame(self.root, padx=10, pady=10) control_frame.pack(fill=tk.BOTH, expand=True) self.buttons = {} for i, do in enumerate(DO_COMMANDS.keys()): row = i // 4 col = i % 4 * 3 tk.Label(control_frame, text=do).grid(row=row, column=col, padx=5, pady=5) on_btn = tk.Button(control_frame, text="开", width=5, command=lambda d=do: self.send_command(d, "开")) on_btn.grid(row=row, column=col+1, padx=2, pady=5) off_btn = tk.Button(control_frame, text="关", width=5, command=lambda d=do: self.send_command(d, "关")) off_btn.grid(row=row, column=col+2, padx=2, pady=5) self.buttons[do] = (on_btn, off_btn) def connect_serial(self): """打开或关闭串口连接""" if self.ser and self.ser.is_open: self.ser.close() self.connect_btn.config(text="打开串口") messagebox.showinfo("提示", "串口已关闭") return try: port = self.port_entry.get() baud = int(self.baud_entry.get()) self.ser = serial.Serial(port, baud, timeout=1) self.connect_btn.config(text="关闭串口") messagebox.showinfo("提示", "串口连接成功") except Exception as e: messagebox.showerror("错误", f"串口打开失败: {str(e)}") def send_command(self, channel, action): """发送Modbus控制命令""" if not self.ser or not self.ser.is_open: messagebox.showwarning("警告", "请先打开串口") return try: # 转换十六进制字符串为字节 cmd_str = DO_COMMANDS[channel][action] cmd_bytes = bytes.fromhex(cmd_str) self.ser.write(cmd_bytes) # 读取返回值(可选) response = self.ser.read(8) if response: messagebox.showinfo("成功", f"{channel} {action} 命令已发送") else: messagebox.showwarning("警告", "未收到设备响应") except Exception as e: messagebox.showerror("错误", f"发送命令失败: {str(e)}") if __name__ == "__main__": root = tk.Tk() app = Adam4150Controller(root) root.mainloop()

运行结果如下:

ADAM4150 继电器控制器代码详细解释
该代码是一个基于 Python Tkinter 的图形化界面(GUI)程序,核心功能是通过串口 + Modbus RTU 协议控制研华 ADAM4150 数字量输出模块的 8 路继电器,实现各通道的独立 “开 / 关” 控制,同时包含串口配置、连接 / 断开、指令发送状态反馈等完整交互逻辑。
一、前置依赖与安装
代码依赖两个核心库,其中tkinter是 Python 自带的 GUI 库,serial(实际为pyserial)是第三方串口通信库,需手动安装:
bash
运行
pip install pyserial
二、代码整体结构
代码分为 4 个核心部分:
库导入:引入 GUI、串口通信相关依赖;
Modbus 指令字典定义:预存 ADAM4150 各通道的开 / 关标准指令;
核心控制类Adam4150Controller:封装界面搭建、串口管理、指令发送所有逻辑(面向对象设计,解耦且易扩展);
主程序入口:创建 GUI 根窗口,实例化控制类并启动事件循环。
下面逐部分详细解析:
三、逐段代码解析
1. 库导入部分
python
运行
import tkinter as tk
from tkinter import messagebox
import serial
tkinter as tk:引入 Tkinter 库,用于构建图形化界面,简写为tk简化代码;
messagebox:从 Tkinter 中导入弹窗组件,用于实现成功提示、错误警告、信息提醒等交互反馈;
serial:引入 pyserial 库,实现电脑与 ADAM4150 之间的串口数据传输(发送 Modbus 指令、接收设备响应)。
2. Modbus 指令字典DO_COMMANDS
python
运行
DO_COMMANDS = {
"DO0": {"开": "01 05 00 10 FF 00 8D FF", "关": "01 05 00 10 00 00 CC 0F"},
# ... 其余DO1-DO7通道略
}
这是 ADAM4150 的标准 Modbus RTU 协议指令,预计算并存储为十六进制字符串格式,核心说明:
键:通道名DO0-DO7,对应模块的 8 路数字量输出通道;
子键:开/关,对应继电器的吸合 / 断开动作;
指令格式(以 DO0 开为例):01 05 00 10 FF 00 8D FF,各段含义符合 Modbus RTU 标准:
01:从站地址(ADAM4150 出厂默认地址为 1);
05:功能码(单线圈写指令,专门用于控制单个继电器的开 / 关);
00 10:寄存器地址(ADAM4150 的 DO0 对应 Modbus 寄存器地址 0x0010);
FF 00:置 1 指令(控制继电器 “开”,00 00为置 0 指令,控制 “关”);
8D FF:CRC16 校验码(Modbus RTU 协议必备,用于校验指令传输是否出错,已预计算好);
优势:无需实时计算指令和校验码,直接通过通道 + 动作快速取值,简化发送逻辑。
3. 核心控制类Adam4150Controller
该类是程序的核心,所有功能都封装在类中,通过实例化调用,包含初始化方法、界面搭建方法、串口管理方法、指令发送方法4 个核心方法。
(1)初始化方法__init__
python
运行
def __init__(self, root):
self.root = root # 接收Tkinter根窗口对象
self.root.title("ADAM4150 继电器控制器") # 设置窗口标题
self.ser = None # 初始化串口对象,默认无连接
self.setup_ui() # 调用界面搭建方法,初始化GUI
作用:接收 GUI 根窗口,初始化窗口基础属性,定义串口对象(self.ser是整个类的全局串口变量),并触发界面搭建;
设计思路:将窗口对象作为参数传入,解耦类与窗口,提高复用性。
(2)界面搭建方法setup_ui
python
运行
def setup_ui(self):
# 1. 串口设置区域:包含串口、波特率输入框,连接/关闭按钮
port_frame = tk.Frame(self.root, padx=10, pady=10)
port_frame.pack(fill=tk.X) # 横向填充窗口,自适应宽度
# 串口标签+输入框(默认值COM100,用户可根据实际修改)
tk.Label(port_frame, text="串口:").grid(row=0, column=0)
self.port_entry = tk.Entry(port_frame, width=10)
self.port_entry.grid(row=0, column=1)
self.port_entry.insert(0, "COM100")
# 波特率标签+输入框(ADAM4150出厂默认9600,无需修改)
tk.Label(port_frame, text="波特率:").grid(row=0, column=2)
self.baud_entry = tk.Entry(port_frame, width=10)
self.baud_entry.grid(row=0, column=3)
self.baud_entry.insert(0, "9600")
# 串口连接/关闭按钮,绑定connect_serial方法
self.connect_btn = tk.Button(port_frame, text="打开串口", command=self.connect_serial)
self.connect_btn.grid(row=0, column=4)

# 2. 继电器控制区域:8通道,各通道含「标签+开按钮+关按钮」
control_frame = tk.Frame(self.root, padx=10, pady=10)
control_frame.pack(fill=tk.BOTH, expand=True) # 横竖都填充,自适应窗口大小
self.buttons = {} # 存储所有通道的按钮对象,方便后续扩展
# 遍历8个通道,按「4个一行」布局(共2行)
for i, do in enumerate(DO_COMMANDS.keys()):
row = i // 4 # 计算行号(0,0,0,0,1,1,1,1)
col = i % 4 * 3 # 计算列号(0,3,6,9,0,3,6,9),每个通道占3列(标签+开+关)
# 通道标签(如DO0)
tk.Label(control_frame, text=do).grid(row=row, column=col)
# 开按钮,绑定send_command方法(lambda传参:当前通道+动作)
on_btn = tk.Button(control_frame, text="开", width=5, command=lambda d=do: self.send_command(d, "开"))
on_btn.grid(row=row, column=col+1)
# 关按钮,绑定send_command方法
off_btn = tk.Button(control_frame, text="关", width=5, command=lambda d=do: self.send_command(d, "关"))
off_btn.grid(row=row, column=col+2)
self.buttons[do] = (on_btn, off_btn) # 存储按钮对象
核心关键点:
布局方式:结合pack和grid——pack用于整体区域(串口区、控制区)的上下排列,grid用于区域内控件的行列精准布局,是 Tkinter 的经典布局组合;
lambda 闭包陷阱解决:循环创建按钮时,若直接写lambda: self.send_command(do, "开"),会导致所有按钮绑定最后一个通道(循环结束后 do 的最终值)。代码中用lambda d=do: ...,将当前循环的do值提前绑定到参数d,避免该问题;
自适应布局:fill=tk.BOTH+expand=True让控制区域随窗口缩放而自适应,提升交互体验。
(3)串口管理方法connect_serial
python
运行
def connect_serial(self):
"""打开或关闭串口连接,实现按钮的「一键切换」功能"""
# 若串口已打开,执行关闭操作
if self.ser and self.ser.is_open:
self.ser.close() # 关闭串口
self.connect_btn.config(text="打开串口") # 修改按钮文字
messagebox.showinfo("提示", "串口已关闭")
return
# 若串口未打开,执行打开操作
try:
port = self.port_entry.get() # 获取输入的串口名(如COM3)
baud = int(self.baud_entry.get()) # 获取波特率并转为整数
# 创建串口对象,timeout=1:读数据时超时1秒(避免程序卡死)
self.ser = serial.Serial(port, baud, timeout=1)
self.connect_btn.config(text="关闭串口") # 修改按钮文字为“关闭串口”
messagebox.showinfo("提示", "串口连接成功")
except Exception as e:
# 捕获所有串口打开错误(如串口不存在、被占用、波特率非法等)
messagebox.showerror("错误", f"串口打开失败: {str(e)}")
核心功能:实现串口的打开 / 关闭一键切换,无需单独设置两个按钮,交互更友好:
状态判断:通过self.ser and self.ser.is_open判断串口是否已连接;
异常处理:捕获串口打开过程中的所有可能错误(如 COM 口不存在、串口被其他程序占用、波特率输入非数字等),并通过弹窗反馈错误信息。
(4)指令发送方法send_command
python
运行
def send_command(self, channel, action):
"""发送Modbus控制指令,实现继电器开/关"""
# 第一步:校验串口状态,未打开则弹窗警告并返回
if not self.ser or not self.ser.is_open:
messagebox.showwarning("警告", "请先打开串口")
return
try:
# 第二步:从字典中获取对应通道+动作的十六进制指令字符串
cmd_str = DO_COMMANDS[channel][action]
# 第三步:将十六进制字符串转为字节流(串口通信只能发送字节,不能发送字符串)
# bytes.fromhex()会自动忽略字符串中的空格,无需额外处理
cmd_bytes = bytes.fromhex(cmd_str)
# 第四步:发送字节流指令到ADAM4150
self.ser.write(cmd_bytes)
# 第五步:读取设备响应(ADAM4150响应为8字节,与发送指令长度一致)
response = self.ser.read(8)
# 根据响应反馈状态
if response:
messagebox.showinfo("成功", f"{channel} {action} 命令已发送")
else:
messagebox.showwarning("警告", "未收到设备响应")
except Exception as e:
# 捕获发送过程中的错误(如串口突然断开、指令字典键错误等)
messagebox.showerror("错误", f"发送命令失败: {str(e)}")
核心技术点:
串口状态前置校验:所有指令发送前先检查串口是否打开,避免无效操作和程序报错;
十六进制字符串转字节流:bytes.fromhex(cmd_str)是 Python 内置方法,可直接将空格分隔的十六进制字符串转为串口可识别的字节流(如"01 05"转为b'\x01\x05');
设备响应判断:发送指令后读取 8 字节响应,若有响应说明指令传输成功,无响应则提示(如模块未连接、串口波特率不匹配等);
异常兜底:捕获所有发送过程中的错误,保证程序不会崩溃。
4. 主程序入口
python
运行
if __name__ == "__main__":
root = tk.Tk() # 创建Tkinter根窗口(GUI程序的主容器)
app = Adam4150Controller(root) # 实例化核心控制类,传入根窗口
root.mainloop() # 启动GUI事件循环(阻塞式,保持窗口显示并响应用户操作)
if __name__ == "__main__":保证该段代码仅在直接运行本文件时执行,若作为模块导入则不执行,是 Python 的规范写法;
root.mainloop():Tkinter 的核心事件循环,负责监听用户的鼠标、键盘操作(如点击按钮、输入文字),并触发对应的绑定方法,直到用户关闭窗口才退出。
四、核心设计亮点与关键注意事项
1. 设计亮点
面向对象封装:将界面、串口、指令发送逻辑封装在一个类中,变量和方法全局可调用,代码结构清晰、易维护、易扩展(如新增通道、添加状态显示);
友好的交互反馈:所有操作(串口连接 / 关闭、指令发送)都有明确的弹窗提示,用户可清晰知道操作结果;
鲁棒性强:多处增加状态校验(串口是否打开)和异常捕获,避免程序因误操作(如未开串口就发指令)而崩溃;
布局合理:采用 “分区布局 + 自适应缩放”,界面整洁且适配不同屏幕大小。
2. 关键使用注意事项
修改串口名:代码中默认串口为COM100,需根据电脑实际连接的 ADAM4150 串口修改(可在电脑「设备管理器 - 端口」中查看,如 COM3、COM4);
波特率匹配:ADAM4150 出厂默认波特率为 9600,若手动修改过模块波特率,需同步修改代码中波特率输入框的默认值;
硬件连接:确保 ADAM4150 通过串口(RS232/RS485)与电脑正常连接,模块供电正常;
权限问题:部分系统(如 Windows)打开串口需要管理员权限,若串口打开失败,可尝试以管理员身份运行程序;
Modbus 地址匹配:代码中 Modbus 从站地址为 1(指令首字节01),若修改过 ADAM4150 的从站地址,需同步更新DO_COMMANDS中所有指令的首字节。
五、程序运行流程
运行代码,弹出 GUI 窗口,默认显示串口COM100、波特率9600,8 个通道的开 / 关按钮;
用户根据实际情况修改串口名,点击「打开串口」,若成功则弹窗提示 “串口连接成功”,按钮变为「关闭串口」;若失败则弹窗显示具体错误;
串口连接成功后,点击任意通道的「开 / 关」按钮,程序发送对应的 Modbus 指令到 ADAM4150;
若收到设备响应,弹窗提示 “命令已发送”;若未收到响应,弹窗提示 “未收到设备响应”;
操作完成后,点击「关闭串口」,弹窗提示 “串口已关闭”,按钮恢复为「打开串口」。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:11:52

Ubuntu 产品与服务整合报告

文章目录Ubuntu 产品与服务整合报告一、内容概述二、核心产品与服务详解1. Ubuntu Pro - 企业级安全与支持解决方案主要功能特性:支持范围:2. 扩展安全维护(ESM)详情支持周期对比:仓库覆盖:3. Landscape - …

作者头像 李华
网站建设 2026/4/16 10:49:45

C语言数据类型、内存布局与变量常量精品教程

文章目录 C语言数据类型、内存布局与变量常量精品教程 一、核心概念精要 1.1 变量与常量本质 1.2 基本数据类型体系 二、内存布局深度解析 2.1 内存地址模型 2.2 补码表示原理 三、数据类型实战应用 3.1 安全类型转换 3.2 浮点数精度控制 四、内存操作高级工具 4.1 内存查看器 …

作者头像 李华
网站建设 2026/4/16 12:43:10

计算机小程序毕设实战-基于springboot+Android的高校食堂点餐配送系统小程序基于Android的高校食堂点餐系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华