华荣三照明、合信、荣欣八组合馈电
This commit is contained in:
BIN
Test/10K 热敏电阻对照表(25°为基准).doc
Normal file
BIN
Test/10K 热敏电阻对照表(25°为基准).doc
Normal file
Binary file not shown.
34
Test/Temperature.py
Normal file
34
Test/Temperature.py
Normal file
@ -0,0 +1,34 @@
|
||||
import numpy as np
|
||||
from scipy.optimize import curve_fit
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
# 读取数据
|
||||
data = np.genfromtxt('10K 热敏电阻对照表(25°为基准).csv', delimiter=',', skip_header=1,
|
||||
usecols=(0, 2), names=['Temperature', 'Rnor'])
|
||||
# 提取温度和Rnor数据
|
||||
temperature = data['Temperature']
|
||||
r_nor = data['Rnor']
|
||||
|
||||
|
||||
# 定义拟合函数,这里采用二次函数作为示例
|
||||
def fit_function(x, a, b, c):
|
||||
return a * x ** 2 + b * x + c
|
||||
|
||||
|
||||
# 进行曲线拟合
|
||||
p0 = [1, 1, 1] # 初始猜测值
|
||||
popt, pcov = curve_fit(fit_function, temperature, r_nor, p0=p0)
|
||||
|
||||
# 生成用于绘图的拟合数据
|
||||
x_fit = np.linspace(-30, 300, 400)
|
||||
y_fit = fit_function(x_fit, *popt)
|
||||
|
||||
# 绘制原始数据和拟合曲线
|
||||
plt.scatter(temperature, r_nor, label='Original Data')
|
||||
plt.plot(x_fit, y_fit, 'r-', label='Fitted Curve')
|
||||
plt.xlabel('Temperature (°C)')
|
||||
plt.ylabel('Rnor (k Ohms)')
|
||||
plt.title('Thermistor Resistance vs Temperature Fitting')
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
23
Test/bmp_jpg.py
Normal file
23
Test/bmp_jpg.py
Normal file
@ -0,0 +1,23 @@
|
||||
import os
|
||||
from PIL import Image
|
||||
|
||||
# 输入目录和输出目录
|
||||
input_directory = 'E:/Jfen_work/DWIN/GUI_PUMP_ICL/132-mode'
|
||||
output_directory = 'E:/Jfen_work/DWIN/GUI_PUMP_ICL/132-mode-new'
|
||||
|
||||
# 确保输出目录存在
|
||||
if not os.path.exists(output_directory):
|
||||
os.makedirs(output_directory)
|
||||
|
||||
# 遍历输入目录中的所有文件
|
||||
for filename in os.listdir(input_directory):
|
||||
if filename.endswith('.bmp'):
|
||||
# 打开 .bmp 文件
|
||||
bmp_image_path = os.path.join(input_directory, filename)
|
||||
with Image.open(bmp_image_path) as img:
|
||||
# 创建 .jpg 文件路径
|
||||
jpg_image_path = os.path.join(output_directory, os.path.splitext(filename)[0] + '.jpg')
|
||||
# 将图片转换为 RGB 模式并保存为 .jpg 文件
|
||||
img.convert('RGB').save(jpg_image_path, 'JPEG')
|
||||
|
||||
print("转换完成!")
|
||||
112
Test/test.py
Normal file
112
Test/test.py
Normal file
@ -0,0 +1,112 @@
|
||||
import sys
|
||||
import logging
|
||||
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QLineEdit
|
||||
from PyQt5.QtCore import Qt
|
||||
import modbus_tk.defines as cst
|
||||
from modbus_tk import modbus_tcp
|
||||
|
||||
# 配置日志以十六进制形式显示报文
|
||||
logging.basicConfig()
|
||||
log = logging.getLogger('modbus_tk')
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class ModbusControlWindow(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setWindowTitle("Modbus Control Window")
|
||||
self.setGeometry(100, 140, 400, 200)
|
||||
|
||||
self.label_ip = QLabel("IP Address:", self)
|
||||
self.label_ip.move(20, 20)
|
||||
self.text_ip = QLineEdit("192.168.1.181", self)
|
||||
self.text_ip.setGeometry(120, 20, 200, 20)
|
||||
|
||||
self.label_device_id = QLabel("Device ID:", self)
|
||||
self.label_device_id.move(20, 60)
|
||||
self.text_device_id = QLineEdit("1", self)
|
||||
self.text_device_id.setGeometry(120, 60, 200, 20)
|
||||
|
||||
self.btn_addr646 = QPushButton("向上", self)
|
||||
self.btn_addr646.move(20, 100)
|
||||
self.btn_addr646.clicked.connect(lambda: self.send_modbus_command(646))
|
||||
|
||||
self.btn_addr647 = QPushButton("向下", self)
|
||||
self.btn_addr647.move(120, 100)
|
||||
self.btn_addr647.clicked.connect(lambda: self.send_modbus_command(647))
|
||||
|
||||
self.btn_addr648 = QPushButton("确定", self)
|
||||
self.btn_addr648.move(220, 100)
|
||||
self.btn_addr648.clicked.connect(lambda: self.send_modbus_command(648))
|
||||
|
||||
self.btn_addr649 = QPushButton("复位", self)
|
||||
self.btn_addr649.move(320, 100)
|
||||
self.btn_addr649.clicked.connect(lambda: self.send_modbus_command(649))
|
||||
|
||||
self.bin_addr628 = QPushButton("短路试验", self)
|
||||
self.bin_addr628.move(20, 140)
|
||||
self.bin_addr628.clicked.connect(lambda: self.send_modbus_command(628))
|
||||
|
||||
self.bin_addr629 = QPushButton("漏电试验", self)
|
||||
self.bin_addr629.move(120, 140)
|
||||
self.bin_addr629.clicked.connect(lambda: self.send_modbus_command(629))
|
||||
|
||||
self.bin_addr641 = QPushButton("过压试验", self)
|
||||
self.bin_addr641.move(220, 140)
|
||||
self.bin_addr641.clicked.connect(lambda: self.send_modbus_command(641))
|
||||
|
||||
self.bin_addr642 = QPushButton("电流断相试验", self)
|
||||
self.bin_addr642.move(320, 140)
|
||||
self.bin_addr642.clicked.connect(lambda: self.send_modbus_command(642))
|
||||
|
||||
self.bin_addr636 = QPushButton("小车进", self)
|
||||
self.bin_addr636.move(20, 180)
|
||||
self.bin_addr636.clicked.connect(lambda: self.send_modbus_command(636))
|
||||
|
||||
self.bin_addr637 = QPushButton("小车退", self)
|
||||
self.bin_addr637.move(120, 180)
|
||||
self.bin_addr637.clicked.connect(lambda: self.send_modbus_command(637))
|
||||
|
||||
def send_modbus_command(self, addr):
|
||||
ip_address = self.text_ip.text()
|
||||
device_id = int(self.text_device_id.text())
|
||||
|
||||
# 连接Modbus设备
|
||||
try:
|
||||
master = modbus_tcp.TcpMaster(host=ip_address, port=502)
|
||||
master.set_timeout(5.0)
|
||||
except Exception as exc:
|
||||
print(f"Failed to connect to Modbus device: {exc}")
|
||||
return
|
||||
|
||||
# 发送Modbus功能码0x05
|
||||
try:
|
||||
master.execute(device_id, cst.WRITE_SINGLE_COIL, addr, output_value=1)
|
||||
print(f"Modbus command to address {addr} sent successfully.")
|
||||
except Exception as exc:
|
||||
print(f"Failed to send Modbus command to address {addr}: {exc}")
|
||||
finally:
|
||||
master.close()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == Qt.Key_Up:
|
||||
self.send_modbus_command(646)
|
||||
elif event.key() == Qt.Key_Down:
|
||||
self.send_modbus_command(647)
|
||||
elif event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
|
||||
self.send_modbus_command(648)
|
||||
elif event.key() == Qt.Key_Space:
|
||||
self.send_modbus_command(649)
|
||||
elif event.key() == Qt.Key_A:
|
||||
self.send_modbus_command(628)
|
||||
else:
|
||||
super().keyPressEvent(event)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
window = ModbusControlWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
285
Test/test_cuver.py
Normal file
285
Test/test_cuver.py
Normal file
@ -0,0 +1,285 @@
|
||||
import sys
|
||||
import serial
|
||||
from serial.tools import list_ports
|
||||
import struct
|
||||
import threading
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QLineEdit, QPushButton,
|
||||
QComboBox, QLabel, QCheckBox
|
||||
)
|
||||
from PyQt5.QtCore import QTimer
|
||||
|
||||
# 定义ZBUS命令类型
|
||||
class ZBUS_CMD:
|
||||
ZBUS_FRAME_NODE_INFO_REQUEST = 0
|
||||
ZBUS_FRAME_NODE_ID_LOCK = 1 # 地址锁定命令
|
||||
ZBUS_FRAME_NODE_ID_UNLOCK = 2
|
||||
ZBUS_FRAME_ENTER_AUTO_BAUD = 3
|
||||
ZBUS_FRAME_FLUSH_GLOBAL_STATUS = 4
|
||||
ZBUS_FRAME_FLUSH_OUTPUT = 5
|
||||
ZBUS_FRAME_FLUSH_INPUT = 6
|
||||
ZBUS_FRAME_TOKEN_PASS = 7 # 令牌传递
|
||||
ZBUS_FRAME_MODBUS = 8 # Modbus RTU数据
|
||||
ZBUS_FRAME_CONFIG_TOKEN = 9
|
||||
ZBUS_FRAME_PATH_TO_NEXT = 10
|
||||
ZBUS_FRAME_TRANSMIT_AUTO_BAUD = 11 # 发送自动波特率帧, 方便从机配置波特率
|
||||
|
||||
ZBUS_FRAME_FILE_OPEN = 16 # 打开文件
|
||||
ZBUS_FRAME_FILE_WRITE = 17 # 写入文件数据
|
||||
ZBUS_FRAME_FILE_READ = 18 # 读取文件数据
|
||||
ZBUS_FRAME_FILE_CLOSE = 19 # 文件关闭
|
||||
|
||||
ZBUS_FRAME_CUSTOM_COMMAND = 20 # 可以自定义命令
|
||||
|
||||
# ZBUS常量
|
||||
ZBUS_LEAD_FLAG1 = 0x55
|
||||
ZBUS_LEAD_FLAG2 = 0xAA
|
||||
ZBUS_LEAD_FLAG_TOKEN = 0xDC
|
||||
|
||||
NODE_ID_GLOBAL = 0
|
||||
NODE_ID_CONFIG = 1
|
||||
NODE_ID_MODULE_AC12 = 2
|
||||
|
||||
STR_FORMAT_NAME = "name:"
|
||||
STR_FORMAT_MODE = "mode:"
|
||||
STR_FORMAT_WRITE = "write:"
|
||||
|
||||
# 定义ZBUS通讯类
|
||||
class ZBUS:
|
||||
def __init__(self) -> None:
|
||||
self.SelfNodeId = NODE_ID_CONFIG # 配置节点Id
|
||||
self.tx_frame_index = 0 # 发送帧索引
|
||||
|
||||
def ZBUS_CalculateLRC(self, buf_list):
|
||||
lrc = sum(buf_list) # 使用 sum 函数简化计算
|
||||
return lrc & 0xFFFF
|
||||
|
||||
def ZBUS_AssembleTxFrame(self, dest_node_id: int, source_node_id: int, frame_type: int, tx_buf: list):
|
||||
# 组装一个发送帧
|
||||
frame_index = self.tx_frame_index
|
||||
self.tx_frame_index += 1
|
||||
|
||||
tx_list = []
|
||||
if frame_type == ZBUS_CMD.ZBUS_FRAME_TRANSMIT_AUTO_BAUD:
|
||||
tx_list = [0x55] * 32
|
||||
return bytes(tx_list)
|
||||
|
||||
if frame_type == ZBUS_CMD.ZBUS_FRAME_TOKEN_PASS:
|
||||
tx_list = struct.pack("BBB", ZBUS_LEAD_FLAG_TOKEN, dest_node_id, source_node_id)
|
||||
return tx_list
|
||||
|
||||
cmd = frame_type # 获取枚举值
|
||||
tx_list = struct.pack("BBBBBB", ZBUS_LEAD_FLAG1, ZBUS_LEAD_FLAG2, dest_node_id, source_node_id, cmd, frame_index)
|
||||
if tx_buf is not None:
|
||||
frame_size = len(tx_buf)
|
||||
else:
|
||||
frame_size = 0
|
||||
tx_list += struct.pack("B", frame_size)
|
||||
if tx_buf is not None:
|
||||
tx_list += bytes(tx_buf)
|
||||
|
||||
lrc = self.ZBUS_CalculateLRC(tx_list)
|
||||
tx_list += struct.pack("<H", lrc)
|
||||
return tx_list
|
||||
|
||||
# GUI 类
|
||||
class SerialGUI(QWidget):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.setWindowTitle("ZBUS 串口通讯")
|
||||
self.setGeometry(100, 100, 800, 600)
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.text_area = QTextEdit()
|
||||
self.layout.addWidget(self.text_area)
|
||||
|
||||
self.receive_area = QTextEdit()
|
||||
self.layout.addWidget(self.receive_area)
|
||||
|
||||
self.hex_data_buffer = [] # 存储接收到的Hex数据
|
||||
self.ascii_data_buffer = [] # 存储接收到的ASCII数据
|
||||
|
||||
self.display_mode = QCheckBox("显示Hex数据")
|
||||
self.display_mode.stateChanged.connect(self.switch_display_mode)
|
||||
self.layout.addWidget(self.display_mode)
|
||||
|
||||
self.create_widgets()
|
||||
|
||||
self.bus = ZBUS()
|
||||
self.ser = None # 串口对象
|
||||
self.serial_thread = None # 串口线程
|
||||
|
||||
self.timer = QTimer(self)
|
||||
self.timer.timeout.connect(self.check_serial_insertion)
|
||||
self.timer.start(1000)
|
||||
|
||||
self.available_ports = set() # 用于存储当前可用的串口设备
|
||||
self.timer = QTimer(self)
|
||||
self.timer.timeout.connect(self.check_serial_insertion)
|
||||
self.timer.start(1000)
|
||||
|
||||
self.check_serial_insertion()
|
||||
|
||||
self.ThreadStop = False
|
||||
|
||||
def switch_display_mode(self):
|
||||
self.receive_area.clear()
|
||||
if self.display_mode.isChecked(): # 显示Hex数据
|
||||
for line in self.hex_data_buffer:
|
||||
self.receive_area.append(line)
|
||||
else: # 显示ASCII数据
|
||||
for line in self.ascii_data_buffer:
|
||||
self.receive_area.append(line)
|
||||
|
||||
def create_widgets(self):
|
||||
self.serial_port = QComboBox()
|
||||
self.layout.addWidget(self.serial_port)
|
||||
|
||||
self.baud_rate = QLineEdit("115200")
|
||||
self.layout.addWidget(self.baud_rate)
|
||||
|
||||
self.timeout = QLineEdit("0.5")
|
||||
self.layout.addWidget(self.timeout)
|
||||
|
||||
self.send_hello_btn = QPushButton("发送 Hello")
|
||||
self.send_hello_btn.clicked.connect(self.send_hello)
|
||||
self.layout.addWidget(self.send_hello_btn)
|
||||
|
||||
self.send_auto_baud_btn = QPushButton("发送自动波特率帧")
|
||||
self.send_auto_baud_btn.clicked.connect(self.send_auto_baud)
|
||||
self.layout.addWidget(self.send_auto_baud_btn)
|
||||
|
||||
self.send_lock_btn = QPushButton("发送节点ID锁定帧")
|
||||
self.send_lock_btn.clicked.connect(self.send_lock)
|
||||
self.layout.addWidget(self.send_lock_btn)
|
||||
|
||||
self.get_node_status_btn = QPushButton("获取节点状态")
|
||||
self.get_node_status_btn.clicked.connect(self.get_node_status)
|
||||
self.layout.addWidget(self.get_node_status_btn)
|
||||
|
||||
self.zbus_file_open_btn = QPushButton("打开文件")
|
||||
self.zbus_file_open_btn.clicked.connect(self.zbus_file_open_test)
|
||||
self.layout.addWidget(self.zbus_file_open_btn)
|
||||
|
||||
self.send_custom_command_btn = QPushButton("发送自定义命令")
|
||||
self.send_custom_command_btn.clicked.connect(self.send_custom_command)
|
||||
self.layout.addWidget(self.send_custom_command_btn)
|
||||
|
||||
self.open_serial_btn = QPushButton("打开串口")
|
||||
self.open_serial_btn.clicked.connect(self.open_serial)
|
||||
self.layout.addWidget(self.open_serial_btn)
|
||||
|
||||
self.close_serial_btn = QPushButton("关闭串口")
|
||||
self.close_serial_btn.clicked.connect(self.close_serial)
|
||||
self.layout.addWidget(self.close_serial_btn)
|
||||
|
||||
def detect_serial_ports(self):
|
||||
return set(port.device for port in list_ports.comports())
|
||||
|
||||
def check_serial_insertion(self):
|
||||
current_ports = self.detect_serial_ports()
|
||||
if current_ports != self.available_ports:
|
||||
self.available_ports = current_ports
|
||||
self.serial_port.clear()
|
||||
self.serial_port.addItems(sorted(self.available_ports))
|
||||
|
||||
def open_serial(self):
|
||||
try:
|
||||
if not self.serial_port.currentText():
|
||||
raise ValueError("请先选择一个串口")
|
||||
|
||||
self.ser = serial.Serial(
|
||||
port=self.serial_port.currentText(),
|
||||
baudrate=int(self.baud_rate.text()),
|
||||
timeout=float(self.timeout.text())
|
||||
)
|
||||
self.ThreadStop = False
|
||||
|
||||
self.serial_thread = threading.Thread(target=self.serial_thread_func)
|
||||
self.serial_thread.start()
|
||||
|
||||
self.log_text(f"成功打开串口: {self.serial_port.currentText()}")
|
||||
|
||||
except Exception as e:
|
||||
self.log_text(f"打开串口失败: {str(e)}")
|
||||
|
||||
def close_serial(self):
|
||||
try:
|
||||
if self.ser and self.ser.is_open:
|
||||
self.ThreadStop = True
|
||||
self.serial_thread.join()
|
||||
self.ser.close()
|
||||
self.log_text("串口已关闭")
|
||||
|
||||
except Exception as e:
|
||||
self.log_text(f"关闭串口失败: {str(e)}")
|
||||
|
||||
def serial_thread_func(self):
|
||||
while not self.ThreadStop:
|
||||
try:
|
||||
if self.ser.in_waiting > 0:
|
||||
data = self.ser.readline()
|
||||
decoded_data = data.decode('utf-8', errors='replace').replace('\x00', '')
|
||||
self.ascii_data_buffer.append(decoded_data)
|
||||
hex_data = ' '.join(f'{byte:02X}' for byte in data)
|
||||
self.hex_data_buffer.append(hex_data)
|
||||
|
||||
self.update_receive_area(decoded_data, hex_data)
|
||||
except Exception as e:
|
||||
self.log_text(f"读取串口数据失败: {str(e)}")
|
||||
break
|
||||
|
||||
def update_receive_area(self, ascii_data, hex_data):
|
||||
if self.display_mode.isChecked(): # 显示Hex数据
|
||||
self.receive_area.append(hex_data)
|
||||
else: # 显示ASCII数据
|
||||
self.receive_area.append(ascii_data)
|
||||
|
||||
def send_data(self, data):
|
||||
try:
|
||||
if self.ser and self.ser.is_open:
|
||||
self.ser.write(data)
|
||||
self.log_text(f"发送数据: {data}")
|
||||
else:
|
||||
self.log_text("串口未打开")
|
||||
except Exception as e:
|
||||
self.log_text(f"发送数据失败: {str(e)}")
|
||||
|
||||
def send_hello(self):
|
||||
data = b'Hello'
|
||||
self.send_data(data)
|
||||
|
||||
def send_auto_baud(self):
|
||||
data = self.bus.ZBUS_AssembleTxFrame(0, 1, ZBUS_CMD.ZBUS_FRAME_TRANSMIT_AUTO_BAUD, None)
|
||||
self.send_data(data)
|
||||
|
||||
def send_lock(self):
|
||||
data = self.bus.ZBUS_AssembleTxFrame(0, 1, ZBUS_CMD.ZBUS_FRAME_NODE_ID_LOCK, None)
|
||||
self.send_data(data)
|
||||
|
||||
def get_node_status(self):
|
||||
data = self.bus.ZBUS_AssembleTxFrame(0, 1, ZBUS_CMD.ZBUS_FRAME_NODE_INFO_REQUEST, None)
|
||||
self.send_data(data)
|
||||
|
||||
def zbus_file_open_test(self):
|
||||
filename = "example.txt"
|
||||
data = list(f"{STR_FORMAT_NAME}{filename}\n".encode())
|
||||
assembled_data = self.bus.ZBUS_AssembleTxFrame(0, 1, ZBUS_CMD.ZBUS_FRAME_FILE_OPEN, data)
|
||||
self.send_data(assembled_data)
|
||||
|
||||
def send_custom_command(self):
|
||||
data = b'Custom Command'
|
||||
self.send_data(data)
|
||||
|
||||
def log_text(self, text):
|
||||
self.text_area.append(text)
|
||||
|
||||
# 启动 GUI
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
gui = SerialGUI()
|
||||
gui.show()
|
||||
sys.exit(app.exec_())
|
||||
343
Test/test_modscan.py
Normal file
343
Test/test_modscan.py
Normal file
@ -0,0 +1,343 @@
|
||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
|
||||
QLineEdit, QMessageBox, QComboBox, QTableWidget, QTableWidgetItem, QSpinBox, QGroupBox, QFormLayout, QAction, QMenuBar)
|
||||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtGui import QFont, QIcon
|
||||
from modbus_tk import modbus_tcp, modbus_rtu
|
||||
import serial
|
||||
from modbus_tk.defines import *
|
||||
|
||||
class ModbusClient(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.init_ui()
|
||||
self.master = None
|
||||
self.timer = QTimer()
|
||||
self.timer.timeout.connect(self.update_data)
|
||||
|
||||
def init_ui(self):
|
||||
self.setWindowTitle("Modbus 客户端")
|
||||
self.setGeometry(100, 100, 900, 700)
|
||||
self.setStyleSheet("""
|
||||
QWidget {
|
||||
background-color: #2e2e2e;
|
||||
color: #ffffff;
|
||||
font-family: Arial;
|
||||
font-size: 14px;
|
||||
}
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
border: 1px solid #555;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top left;
|
||||
padding: 10px;
|
||||
}
|
||||
QLabel {
|
||||
font-size: 14px;
|
||||
}
|
||||
QLineEdit, QComboBox, QSpinBox {
|
||||
padding: 5px;
|
||||
border: 1px solid #555;
|
||||
border-radius: 5px;
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
}
|
||||
QPushButton {
|
||||
background-color: #555;
|
||||
border: 1px solid #444;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #777;
|
||||
}
|
||||
QTableWidget {
|
||||
background-color: #444;
|
||||
alternate-background-color: #555;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
QHeaderView::section {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
""")
|
||||
|
||||
# 创建菜单栏
|
||||
menu_bar = self.menuBar()
|
||||
file_menu = menu_bar.addMenu('文件')
|
||||
connection_menu = menu_bar.addMenu('连接')
|
||||
action_menu = menu_bar.addMenu('操作')
|
||||
|
||||
# 创建文件菜单项
|
||||
exit_action = QAction('退出', self)
|
||||
exit_action.triggered.connect(self.close)
|
||||
file_menu.addAction(exit_action)
|
||||
|
||||
# 创建连接菜单项
|
||||
connect_action = QAction('连接', self)
|
||||
connect_action.triggered.connect(self.connect_modbus)
|
||||
connection_menu.addAction(connect_action)
|
||||
|
||||
disconnect_action = QAction('断开连接', self)
|
||||
disconnect_action.triggered.connect(self.disconnect_modbus)
|
||||
connection_menu.addAction(disconnect_action)
|
||||
|
||||
# 创建操作菜单项
|
||||
execute_action = QAction('执行', self)
|
||||
execute_action.triggered.connect(self.execute_action)
|
||||
action_menu.addAction(execute_action)
|
||||
|
||||
monitor_action = QAction('开始监视', self)
|
||||
monitor_action.triggered.connect(self.toggle_monitoring)
|
||||
action_menu.addAction(monitor_action)
|
||||
|
||||
# 创建中心小部件
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
|
||||
# 连接部分
|
||||
connection_group = QGroupBox("连接设置")
|
||||
connection_layout = QFormLayout()
|
||||
|
||||
self.mode_combo = QComboBox()
|
||||
self.mode_combo.addItem("TCP", "TCP")
|
||||
self.mode_combo.addItem("RTU", "RTU")
|
||||
self.mode_combo.currentIndexChanged.connect(self.toggle_mode)
|
||||
connection_layout.addRow(QLabel("模式选择:"), self.mode_combo)
|
||||
|
||||
self.ip_edit = QLineEdit()
|
||||
self.ip_edit.setPlaceholderText("输入 IP 地址")
|
||||
connection_layout.addRow(QLabel("IP 地址 / 串口端口:"), self.ip_edit)
|
||||
|
||||
self.port_edit = QLineEdit()
|
||||
self.port_edit.setPlaceholderText("输入端口号 / 波特率")
|
||||
connection_layout.addRow(QLabel("端口号 / 波特率:"), self.port_edit)
|
||||
|
||||
self.connect_button = QPushButton("连接")
|
||||
self.connect_button.clicked.connect(self.connect_modbus)
|
||||
connection_layout.addRow(self.connect_button)
|
||||
|
||||
self.disconnect_button = QPushButton("断开连接")
|
||||
self.disconnect_button.clicked.connect(self.disconnect_modbus)
|
||||
self.disconnect_button.setEnabled(False)
|
||||
connection_layout.addRow(self.disconnect_button)
|
||||
|
||||
connection_group.setLayout(connection_layout)
|
||||
main_layout.addWidget(connection_group)
|
||||
|
||||
# 功能部分
|
||||
function_group = QGroupBox("功能选择")
|
||||
function_layout = QFormLayout()
|
||||
|
||||
self.function_combo = QComboBox()
|
||||
self.function_combo.addItem("读线圈 (0)", READ_COILS)
|
||||
self.function_combo.addItem("读输入 (1)", READ_DISCRETE_INPUTS)
|
||||
self.function_combo.addItem("读保持寄存器 (3)", READ_HOLDING_REGISTERS)
|
||||
self.function_combo.addItem("读输入寄存器 (4)", READ_INPUT_REGISTERS)
|
||||
self.function_combo.addItem("写单个线圈 (5)", WRITE_SINGLE_COIL)
|
||||
self.function_combo.addItem("写单个寄存器 (6)", WRITE_SINGLE_REGISTER)
|
||||
self.function_combo.addItem("写多个寄存器 (16)", WRITE_MULTIPLE_REGISTERS)
|
||||
|
||||
self.function_combo.currentIndexChanged.connect(self.update_function_description)
|
||||
function_layout.addRow(QLabel("功能码:"), self.function_combo)
|
||||
|
||||
self.function_description = QLabel()
|
||||
function_layout.addRow(QLabel("功能描述:"), self.function_description)
|
||||
|
||||
self.device_edit = QLineEdit()
|
||||
self.device_edit.setPlaceholderText("输入设备地址")
|
||||
function_layout.addRow(QLabel("设备地址:"), self.device_edit)
|
||||
|
||||
self.address_edit = QLineEdit()
|
||||
self.address_edit.setPlaceholderText("输入寄存器地址")
|
||||
function_layout.addRow(QLabel("寄存器地址:"), self.address_edit)
|
||||
|
||||
self.value_edit = QLineEdit()
|
||||
self.value_edit.setPlaceholderText("输入写入值")
|
||||
function_layout.addRow(QLabel("写入值:"), self.value_edit)
|
||||
|
||||
self.execute_button = QPushButton("执行")
|
||||
self.execute_button.clicked.connect(self.execute_action)
|
||||
function_layout.addRow(self.execute_button)
|
||||
|
||||
function_group.setLayout(function_layout)
|
||||
main_layout.addWidget(function_group)
|
||||
|
||||
# 数据部分
|
||||
data_group = QGroupBox("数据")
|
||||
data_layout = QVBoxLayout()
|
||||
|
||||
self.data_table = QTableWidget()
|
||||
self.data_table.setColumnCount(2)
|
||||
self.data_table.setHorizontalHeaderLabels(["地址", "值"])
|
||||
data_layout.addWidget(self.data_table)
|
||||
|
||||
data_group.setLayout(data_layout)
|
||||
main_layout.addWidget(data_group)
|
||||
|
||||
# 实时监视部分
|
||||
monitor_group = QGroupBox("实时监视")
|
||||
monitor_layout = QFormLayout()
|
||||
self.monitor_interval_edit = QSpinBox()
|
||||
self.monitor_interval_edit.setRange(100, 5000) # 设置监视间隔范围
|
||||
self.monitor_interval_edit.setValue(1000) # 设置默认值
|
||||
monitor_layout.addRow(QLabel("监视间隔(ms):"), self.monitor_interval_edit)
|
||||
|
||||
self.start_address_edit = QLineEdit()
|
||||
self.start_address_edit.setPlaceholderText("输入开始地址")
|
||||
monitor_layout.addRow(QLabel("监视开始地址:"), self.start_address_edit)
|
||||
|
||||
self.length_edit = QSpinBox()
|
||||
self.length_edit.setRange(1, 100)
|
||||
monitor_layout.addRow(QLabel("长度:"), self.length_edit)
|
||||
|
||||
self.monitor_button = QPushButton("开始监视")
|
||||
self.monitor_button.clicked.connect(self.toggle_monitoring)
|
||||
monitor_layout.addRow(self.monitor_button)
|
||||
|
||||
monitor_group.setLayout(monitor_layout)
|
||||
main_layout.addWidget(monitor_group)
|
||||
|
||||
self.update_function_description()
|
||||
|
||||
def toggle_mode(self):
|
||||
mode = self.mode_combo.currentData()
|
||||
if mode == "TCP":
|
||||
self.ip_edit.setPlaceholderText("输入 IP 地址")
|
||||
self.port_edit.setPlaceholderText("输入端口号")
|
||||
elif mode == "RTU":
|
||||
self.ip_edit.setPlaceholderText("输入串口端口")
|
||||
self.port_edit.setPlaceholderText("输入波特率")
|
||||
|
||||
def connect_modbus(self):
|
||||
mode = self.mode_combo.currentData()
|
||||
try:
|
||||
if mode == "TCP":
|
||||
ip = self.ip_edit.text()
|
||||
port = int(self.port_edit.text())
|
||||
self.master = modbus_tcp.TcpMaster(ip, port)
|
||||
self.master.open()
|
||||
elif mode == "RTU":
|
||||
port = self.ip_edit.text()
|
||||
baudrate = int(self.port_edit.text())
|
||||
self.master = modbus_rtu.RtuMaster(serial.Serial(port, baudrate))
|
||||
self.master.open()
|
||||
QMessageBox.information(self, "连接", f"成功连接到 Modbus {mode} 设备。")
|
||||
self.connect_button.setEnabled(False)
|
||||
self.disconnect_button.setEnabled(True)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "连接错误", f"无法连接到 Modbus 设备: {e}")
|
||||
|
||||
def disconnect_modbus(self):
|
||||
if self.master:
|
||||
self.master.close()
|
||||
self.master = None
|
||||
QMessageBox.information(self, "断开连接", "已断开与 Modbus 设备的连接。")
|
||||
self.connect_button.setEnabled(True)
|
||||
self.disconnect_button.setEnabled(False)
|
||||
|
||||
def update_function_description(self):
|
||||
descriptions = {
|
||||
READ_COILS: "读线圈状态",
|
||||
READ_DISCRETE_INPUTS: "读离散输入状态",
|
||||
READ_HOLDING_REGISTERS: "读保持寄存器值",
|
||||
READ_INPUT_REGISTERS: "读输入寄存器值",
|
||||
WRITE_SINGLE_COIL: "写单个位",
|
||||
WRITE_SINGLE_REGISTER: "写单个寄存器",
|
||||
WRITE_MULTIPLE_REGISTERS: "写多个寄存器",
|
||||
}
|
||||
function_code = self.function_combo.currentData()
|
||||
self.function_description.setText(descriptions.get(function_code, ""))
|
||||
|
||||
def execute_action(self):
|
||||
if not self.master:
|
||||
QMessageBox.warning(self, "连接", "请先连接到 Modbus 设备。")
|
||||
return
|
||||
|
||||
function_code = self.function_combo.currentData()
|
||||
device = int(self.device_edit.text())
|
||||
address = int(self.address_edit.text())
|
||||
|
||||
try:
|
||||
if function_code in [READ_COILS, READ_DISCRETE_INPUTS]:
|
||||
response = self.master.execute(device, function_code, address, 1)
|
||||
data = response[0]
|
||||
self.display_data({address: data})
|
||||
elif function_code in [READ_HOLDING_REGISTERS, READ_INPUT_REGISTERS]:
|
||||
response = self.master.execute(device, function_code, address, 1)
|
||||
data = response[0]
|
||||
self.display_data({address: data})
|
||||
elif function_code == WRITE_SINGLE_COIL:
|
||||
value = int(self.value_edit.text())
|
||||
if value not in [0, 1]:
|
||||
raise ValueError("写线圈的值必须为0或1")
|
||||
self.master.execute(device, function_code, address, output_value=value)
|
||||
QMessageBox.information(self, "写入", "写入操作成功完成。")
|
||||
elif function_code == WRITE_SINGLE_REGISTER:
|
||||
value = int(self.value_edit.text())
|
||||
self.master.execute(device, function_code, address, output_value=value)
|
||||
QMessageBox.information(self, "写入", "写入操作成功完成。")
|
||||
elif function_code == WRITE_MULTIPLE_REGISTERS:
|
||||
values_str = self.value_edit.text()
|
||||
values = [int(val) for val in values_str.split(",")]
|
||||
self.master.execute(device, function_code, address, output_value=values)
|
||||
QMessageBox.information(self, "写入", "写入操作成功完成。")
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"执行操作时出错: {e}")
|
||||
|
||||
def display_data(self, data):
|
||||
# 批量更新表格
|
||||
self.data_table.setRowCount(len(data))
|
||||
for i, (address, value) in enumerate(data.items()):
|
||||
self.data_table.setItem(i, 0, QTableWidgetItem(str(address)))
|
||||
self.data_table.setItem(i, 1, QTableWidgetItem(str(value)))
|
||||
|
||||
def toggle_monitoring(self):
|
||||
if self.timer.isActive():
|
||||
self.timer.stop()
|
||||
self.monitor_button.setText("开始监视")
|
||||
else:
|
||||
self.timer.start(self.monitor_interval_edit.value())
|
||||
self.monitor_button.setText("停止监视")
|
||||
|
||||
def update_data(self):
|
||||
if not self.master:
|
||||
self.timer.stop()
|
||||
self.monitor_button.setText("开始监视")
|
||||
QMessageBox.warning(self, "连接", "请先连接到 Modbus 设备。")
|
||||
return
|
||||
|
||||
try:
|
||||
device = int(self.device_edit.text())
|
||||
start_address = int(self.start_address_edit.text())
|
||||
length = self.length_edit.value()
|
||||
|
||||
response = self.master.execute(device, READ_HOLDING_REGISTERS, start_address, length)
|
||||
|
||||
# 将数据转换为地址-值对的字典
|
||||
data = {start_address + i: val for i, val in enumerate(response)}
|
||||
|
||||
# 更新表格
|
||||
self.display_data(data)
|
||||
except Exception as e:
|
||||
self.timer.stop()
|
||||
self.monitor_button.setText("开始监视")
|
||||
QMessageBox.critical(self, "错误", f"读取数据时出错: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication([])
|
||||
app.setFont(QFont("Arial", 10)) # 设置全局字体
|
||||
window = ModbusClient()
|
||||
window.show()
|
||||
app.exec_()
|
||||
35
Test/video.py
Normal file
35
Test/video.py
Normal file
@ -0,0 +1,35 @@
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextBrowser, QWidget, QLabel, QPushButton, QFileDialog
|
||||
from PyQt5.QtGui import QImage, QPixmap
|
||||
from PyQt5.QtCore import QTimer, Qt
|
||||
import cv2
|
||||
|
||||
class CameraWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.cap = cv2.VideoCapture(0) # 默认摄像头
|
||||
self.timer = QTimer()
|
||||
self.initUI()
|
||||
self.timer.timeout.connect(self.update_frame)
|
||||
|
||||
def initUI(self):
|
||||
self.setGeometry(100, 100, 640, 480)
|
||||
self.setWindowTitle('Camera Feed')
|
||||
self.show()
|
||||
self.timer.start(20)
|
||||
|
||||
def update_frame(self):
|
||||
ret, frame = self.cap.read()
|
||||
if ret:
|
||||
height, width, _ = frame.shape
|
||||
bytes_per_line = 3 * width
|
||||
cv2_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
qt_img = QImage(cv2_img.data, width, height, bytes_per_line, QImage.Format_RGB888)
|
||||
qt_img = qt_img.scaled(self.width(), self.height(), Qt.KeepAspectRatio)
|
||||
self.setCentralWidget(QLabel(self))
|
||||
self.centralWidget().setPixmap(QPixmap.fromImage(qt_img))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
window = CameraWindow()
|
||||
sys.exit(app.exec_())
|
||||
Reference in New Issue
Block a user