检查指定Text输入框的值是否是数值型数据(转)

本文介绍了一个用于检查文本输入框中数据是否为数值型的JavaScript函数。该函数能够确保用户输入的数据符合数值格式,适用于年龄、数量等字段的验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本函数用于检查指定Text输入框的值是否是数值型数据
// txtName : 文本输入框对象
// sLabel : 文本输入框的标签名称;如:年龄,数量等
//-----------------------------------------------------------------------------------
function JHshIsNumber(txtName,sLabel)
{
var strTemp = "";

if (isNaN(txtName.value) || (txtName.value.length == 0))
{
strTemp = "“" + sLabel + "”必须是数值型数据。";
window.alert(strTemp) ;
txtName.value = "0";
// txtName.select() ;
txtName.focus() ;
return false ;
}
else   
{
return true ;
}
}


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10294527/viewspace-124738/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10294527/viewspace-124738/

import tkinter as tk import ttkbootstrap as tb import threading import socket import subprocess import time from ttkbootstrap.constants import * from PIL import Image, ImageTk, ImageDraw from tkinter import scrolledtext from datetime import datetime # 数据接收器类 class MLUDataReceiver: def __init__(self, callback): self.callback = callback self.devices = { "设备1": { "ip": "192.168.100.50", "status": "离线", "temperature": 0, "power": 0, "memory": 0, "bandwidth": 0, "mlu_avg_usage": 0, "cpu_avg_usage": 0 } } self.current_device = "设备1" self.running = True self.start_udp_receive() def parse_info(self, info_str): info = {} sections = info_str.split("---------------END---------------")[0].split("\n\n") for section in sections: lines = [line.strip() for line in section.splitlines() if line.strip()] if not lines: continue key = lines[0].split(":")[0].strip() if key == "温度信息": info.update(self.parse_temperature(lines[1:])) elif key == "功率信息": info.update(self.parse_power(lines[1:])) elif key == "内存信息": info.update(self.parse_memory(lines)) elif key == "带宽信息": info.update(self.parse_bandwidth(lines[1:])) elif key == "MLU信息": # 解析MLU核心利用率 mlu_info = self.parse_mlu_info(lines) info.update(mlu_info) elif key == "CPU信息": # 解析CPU核心利用率 cpu_info = self.parse_cpu_info(lines) info.update(cpu_info) return info def parse_temperature(self, lines): temp = 0 for line in lines: if "C" in line: try: temp = max(temp, float(line.split(":")[1].strip().replace(" C", ""))) except (IndexError, ValueError): continue return {"temperature": temp} def parse_power(self, lines): power = 0 for line in lines: if "W" in line: try: power = float(line.split(":")[1].strip().replace(" W", "")) except (IndexError, ValueError): continue return {"power": power} def parse_memory(self, lines): total = 0 used = 0 physical_memory_section = False for line in lines: if "Physical Memory Usage" in line: physical_memory_section = True elif physical_memory_section: if "Total" in line: total = self.parse_memory_value(line) elif "Used" in line: used = self.parse_memory_value(line) return {"memory": round(used / total * 100, 1) if total != 0 else 0} def parse_memory_value(self, line): try: value = line.split(":")[1].strip() num = float(value.split()[0]) unit = value.split()[1] if unit == "MiB": return num * 1024 * 1024 return num except (IndexError, ValueError): return 0 def parse_bandwidth(self, lines): bandwidth = 0 for line in lines: if "GB/s" in line: try: bandwidth = float(line.split(":")[1].strip().replace(" GB/s", "")) except (IndexError, ValueError): continue return {"bandwidth": bandwidth} def parse_mlu_info(self, lines): """解析MLU信息,包括平均利用率和各核心利用率""" mlu_avg_usage = 0 mlu_cores = [0.0] * 4 # 初始化4个核心的利用率 for line in lines: if "MLU Average" in line: try: parts = line.split(':') if len(parts) > 1: mlu_avg_usage = float(parts[1].strip().replace("%", "")) except (IndexError, ValueError): continue # 解析各核心利用率 for i in range(4): if f"MLU {i}" in line: try: parts = line.split(':') if len(parts) > 1: mlu_cores[i] = float(parts[1].strip().replace("%", "")) except (IndexError, ValueError): continue return { "mlu_avg_usage": mlu_avg_usage, "mlu_cores": mlu_cores } def parse_cpu_info(self, lines): """解析CPU信息,包括平均利用率和各核心利用率""" cpu_avg_usage = 0 cpu_cores = [0.0] * 4 # 初始化4个核心的利用率 for line in lines: if "Device CPU Chip" in line: try: parts = line.split(':') if len(parts) > 1: cpu_avg_usage = float(parts[1].strip().replace("%", "")) except (IndexError, ValueError): continue # 解析各核心利用率 for i in range(4): if f"Device CPU Core {i}" in line: try: parts = line.split(':') if len(parts) > 1: cpu_cores[i] = float(parts[1].strip().replace("%", "")) except (IndexError, ValueError): continue return { "cpu_avg_usage": cpu_avg_usage, "cpu_cores": cpu_cores } def start_udp_receive(self): def read_config(): config = {} try: with open('config.txt', 'r') as config_file: for line in config_file: if '=' in line: key, value = line.strip().split('=', 1) config[key] = value print("Read config success.") except FileNotFoundError: print("Unable to open config file!") return None return config config = read_config() if config is None: return server_ip = config.get('SERVER_IP') server_port = int(config.get('SERVER_PORT')) client_ip = config.get('CLIENT_IP') client_port = int(config.get('CLIENT_PORT')) print("ServerIP: {}".format(server_ip)) print("ServerPort: {}".format(server_port)) print("ClientIP: {}".format(client_ip)) print("ClientPort: {}".format(client_port)) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) print("Set socket ok.") try: sock.bind((client_ip, client_port)) print("Bind success.") except OSError: print("Bind error!") return def receive_data(): print("Start receive data.") try: while self.running: data, addr = sock.recvfrom(4096) try: info_str = data.decode('utf-8') device = self.devices[self.current_device] # ping检测逻辑 ip = device["ip"] try: result = subprocess.run(['ping', '-c', '1', '-W', '1', ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if result.returncode == 0: device["status"] = "在线" else: device["status"] = "离线" except Exception as e: print(f"Ping 检测出错: {e}") device["status"] = "离线" # 解析数据并更新设备信息 info = self.parse_info(info_str) device.update(info) # 通过回调传递数据 self.callback({ 'cpu_temp': device['temperature'], 'power': device['power'], 'mem_usage': device['memory'], 'bandwidth': device['bandwidth'] * 8000, # 换为Mbps 'mlu_usage': device['mlu_avg_usage'], 'mlu_cores': device.get('mlu_cores', [0, 0, 0, 0]), 'cpu_usage': device['cpu_avg_usage'], 'cpu_cores': device.get('cpu_cores', [0, 0, 0, 0]), 'status': device['status'] }) except UnicodeDecodeError: print("解码数据时出错,请检查数据编码。") except OSError: print("Receive data error!") except Exception as e: print(f"Unexpected error: {e}") finally: sock.close() receive_thread = threading.Thread(target=receive_data) receive_thread.daemon = True receive_thread.start() def stop(self): self.running = False # 增强型圆形进度条类 class EnhancedCircularProgressBar: def __init__(self, parent, size=200, thickness=20, font_size=16, title="", unit="", max_value=100): self.parent = parent self.size = size self.thickness = thickness self.font_size = font_size self.title = title self.unit = unit self.max_value = max_value self.current_value = 0 self.target_value = 0 self.animation_speed = 1.0 # 动画速度因子 # 获取当前主题颜色 style = tb.Style() self.text_color = style.colors.fg self.bg_color = style.colors.bg self.secondary_bg = style.colors.inputbg # 背景圆环使用输入框背景色 # 创建画布 self.canvas = tk.Canvas( parent, width=size, height=size, highlightthickness=0, bd=0, bg=self.bg_color # 使用主题背景色 ) # 计算圆心和半径 self.center_x = size / 2 self.center_y = size / 2 self.radius = (size - thickness) / 2 - 5 # 绘制背景圆环 self.draw_background() # 绘制文本 self.text_id = self.canvas.create_text( self.center_x, self.center_y, text="0%", fill=self.text_color, # 使用主题前景色 font=("Arial", font_size, "bold") ) # 绘制标题 self.title_id = self.canvas.create_text( self.center_x, self.center_y + 40, text=title, fill=self.text_color, # 使用主题前景色 font=("Arial", int(font_size*0.8)) ) # 初始绘制 self.set_value(0) def draw_background(self): """绘制背景圆环""" # 计算圆环的外接矩形坐标 x0 = self.center_x - self.radius y0 = self.center_y - self.radius x1 = self.center_x + self.radius y1 = self.center_y + self.radius # 绘制背景圆环 self.bg_arc = self.canvas.create_arc( x0, y0, x1, y1, start=0, # 起始角度 extent=360, # 360度完整圆环 width=self.thickness, outline=self.secondary_bg, # 使用主题输入框背景色 style=tk.ARC ) def interpolate_color(self, progress): """根据进度计算颜色(绿-黄-橙-红过渡)""" # 定义颜色过渡点 color_points = [ (0.00, (0, 180, 0)), # 深绿色 (0.25, (170, 255, 0)), # 黄绿色 (0.50, (255, 255, 0)), # 黄色 (0.75, (255, 170, 0)), # 橙色 (1.00, (255, 0, 0)) # 红色 ] # 找到当前进度所在的区间 for i in range(1, len(color_points)): if progress <= color_points[i][0]: # 计算区间内的比例 t = (progress - color_points[i-1][0]) / (color_points[i][0] - color_points[i-1][0]) # 线性插计算RGB(不使用numpy) r1, g1, b1 = color_points[i-1][1] r2, g2, b2 = color_points[i][1] r = int(r1 + t * (r2 - r1)) g = int(g1 + t * (g2 - g1)) b = int(b1 + t * (b2 - b1)) return f"#{r:02x}{g:02x}{b:02x}" # 默认返回红色 return "#ff0000" def set_value(self, value, animate=True): """设置当前并更新进度条""" # 确保在合理范围内 value = max(0, min(value, self.max_value)) if animate: self.target_value = value # 启动动画(如果尚未运行) if abs(self.current_value - self.target_value) > 0.1: self.animate_step() else: self.target_value = value self.current_value = value self.update_display() def update_display(self): """更新进度条显示""" # 计算进度比例 progress = self.current_value / self.max_value # 计算角度(从-90度开始,即12点钟方向) angle = min(progress * 360, 359.99) # 清除旧的前景圆环 if hasattr(self, 'fg_arc'): self.canvas.delete(self.fg_arc) # 计算圆环的外接矩形坐标 x0 = self.center_x - self.radius y0 = self.center_y - self.radius x1 = self.center_x + self.radius y1 = self.center_y + self.radius # 获取插颜色 color = self.interpolate_color(progress) # 绘制前景圆环(进度指示) self.fg_arc = self.canvas.create_arc( x0, y0, x1, y1, start=90, # 从12点钟方向开始 extent=angle, # 根据计算角度 width=self.thickness, outline=color, style=tk.ARC ) # 提升前景圆环的显示层级 self.canvas.tag_raise(self.fg_arc) # 更新文本显示 - 修改带宽显示 if "带宽" in self.title: # 对于带宽,显示实际加单位 display_text = f"{self.current_value:.1f} {self.unit}" elif self.unit == "%": # 对于百分比,显示百分比 display_text = f"{progress*100:.1f}%" else: # 其他情况显示数值加单位 display_text = f"{self.current_value:.1f} {self.unit}" self.canvas.itemconfig(self.text_id, text=display_text) def animate_step(self): """执行一步动画(不使用numpy)""" if abs(self.current_value - self.target_value) < 0.1: self.current_value = self.target_value else: # 使用缓动函数实现平滑动画 diff = self.target_value - self.current_value self.current_value += diff * 0.2 * self.animation_speed self.update_display() # 如果未达到目标,继续动画 if abs(self.current_value - self.target_value) > 0.1: self.parent.after(16, self.animate_step) # 约60fps # 详细窗口类 class DetailWindow: def __init__(self, parent, title, data, core_data, core_type): self.parent = parent self.window = tb.Toplevel(parent) self.window.title(title) self.window.geometry("650x450") self.window.resizable(True, True) # 设置主题与主窗口一致 style = tb.Style() current_theme = self.parent.style.theme_use() style.theme_use(current_theme) # 主框架 main_frame = tb.Frame(self.window, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # 标题 tb.Label( main_frame, text=title, font=("Arial", 16, "bold"), bootstyle=PRIMARY ).pack(pady=(0, 15)) # 平均利用率 avg_frame = tb.Frame(main_frame) avg_frame.pack(fill=tk.X, pady=5) # 保存平均利用率标签引用以便更新 self.avg_label = tb.Label( avg_frame, text=f"平均利用率: {data:.1f}%", font=("Arial", 14), bootstyle=INFO ) self.avg_label.pack(side=tk.LEFT) # 核心利用率容器 cores_frame = tb.Frame(main_frame) cores_frame.pack(fill=tk.BOTH, expand=True, pady=10) # 创建4列 for i in range(4): cores_frame.columnconfigure(i, weight=1) # 创建核心利用率进度条 self.core_bars = [] self.core_labels = [] # 保存核心利用率标签引用 for i, usage in enumerate(core_data): frame = tb.Frame(cores_frame) frame.grid(row=0, column=i, padx=10, pady=10, sticky="nsew") # 核心标题 tb.Label( frame, text=f"{core_type} 核心 {i}", font=("Arial", 12), bootstyle=SECONDARY ).pack(pady=(0, 5)) # 进度条 progress_bar = EnhancedCircularProgressBar( frame, size=120, thickness=12, title="", unit="%", max_value=100 ) progress_bar.set_value(usage) progress_bar.canvas.pack() self.core_bars.append(progress_bar) # 利用率标签 core_label = tb.Label( frame, text=f"{usage:.1f}%", font=("Arial", 12), bootstyle=INFO ) core_label.pack(pady=(5, 0)) self.core_labels.append(core_label) # 保存标签引用 def update_values(self, avg_usage, core_usages): """更新详细窗口中的所有""" # 更新平均利用率标签 self.avg_label.config(text=f"平均利用率: {avg_usage:.1f}%") # 更新核心利用率进度条和标签 for i, (bar, label) in enumerate(zip(self.core_bars, self.core_labels)): if i < len(core_usages): bar.set_value(core_usages[i]) label.config(text=f"{core_usages[i]:.1f}%") # 队列监控组件类 class QueueMonitor: def __init__(self, parent, server_ip="192.168.100.50", monitor_port=9997): self.parent = parent # 创建容器框架并设置固定尺寸 self.container = tb.Frame(parent) self.container.pack(fill=tk.BOTH, expand=True) self.container.config(width=900, height=600) self.container.pack_propagate(False) # 阻止容器根据内容调整大小 # 创建内部框架,所有内容放在这个内部框架中 self.frame = tb.Frame(self.container) self.frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 连接状态变量 self.connected = False self.server_ip = server_ip self.monitor_port = monitor_port self.monitor_running = True # 任务队列数据 self.cpu_queue = [] self.mlu_queue = [] self.current_cpu_task = "" self.current_mlu_task = "" self.cpu_eta = "" self.mlu_eta = "" self.report_time = "" # 新增:存储报告时间 # 创建UI self.create_widgets() # 启动状态监听线程 self.start_monitor_thread() def create_widgets(self): """创建专业UI界面,优化布局""" # 主容器 main_container = tb.Frame(self.frame, padding=(15, 15)) main_container.pack(fill=tk.BOTH, expand=True) # 标题区域 header_frame = tb.Frame(main_container, padding=(10, 10)) header_frame.pack(fill=tk.X, pady=(0, 10)) tb.Label( header_frame, text="任务队列监控", font=("Segoe UI", 16, "bold"), ).pack(side=tk.LEFT, padx=6) right_status_frame = tb.Frame(header_frame) right_status_frame.pack(side=tk.RIGHT) # 报告时间标签 self.time_label = tb.Label( right_status_frame, text="报告时间: -", bootstyle=INFO, font=("Segoe UI", 10), ) self.time_label.pack(side=tk.TOP, pady=(0, 5)) # 上方元素,底部留空 # 分隔线 separator = tb.Separator( right_status_frame, orient=tk.HORIZONTAL, bootstyle=SECONDARY ) separator.pack(fill=tk.X, pady=3) # 在时间和状态之间添加分隔线 # 连接状态指示器 self.status_indicator = tb.Label( right_status_frame, text="● 未连接", bootstyle=DANGER, font=("Segoe UI", 10, "bold"), ) self.status_indicator.pack(side=tk.TOP) # 下方元素 # 控制面板 control_frame = tb.Frame(main_container) control_frame.pack(fill=tk.X, pady=(0, 10)) # 服务器配置网格 config_grid = tb.Frame(control_frame) config_grid.pack(fill=tk.X, padx=5, pady=5) # 服务器地址 tb.Label( config_grid, text="服务器地址:", font=("Segoe UI", 9), ).grid(row=0, column=0, padx=5, pady=5, sticky=tk.W) self.ip_entry = tb.Entry( config_grid, width=22, font=("Consolas", 9), ) self.ip_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W) self.ip_entry.insert(0, self.server_ip) # 监控端口 tb.Label( config_grid, text="监控端口:", font=("Segoe UI", 9), ).grid(row=0, column=2, padx=(15, 5), pady=5, sticky=tk.W) self.monitor_entry = tb.Entry( config_grid, width=8, font=("Consolas", 9), ) self.monitor_entry.grid(row=0, column=3, padx=5, pady=5, sticky=tk.W) self.monitor_entry.insert(0, str(self.monitor_port)) # 连接按钮 self.connect_btn = tb.Button( config_grid, text="连接监控", command=self.connect_to_server, bootstyle=(OUTLINE,DARK), width=10 ) self.connect_btn.grid(row=0, column=4, padx=(15, 5)) # 队列状态区域 queue_frame = tb.Frame(main_container) queue_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10)) # 创建网格布局 - 改为2列 queue_frame.columnconfigure(0, weight=1) queue_frame.columnconfigure(1, weight=1) queue_frame.rowconfigure(0, weight=1) # CPU队列面板 - 常驻队列和调度队列两个子面板 cpu_frame = tb.LabelFrame( queue_frame, text="CPU队列状态", padding=10, ) cpu_frame.grid(row=0, column=0, padx=(0, 5), sticky="nsew") # CPU队列内容 - 使用网格布局分为常驻队列和调度队列 cpu_grid = tb.Frame(cpu_frame) cpu_grid.pack(fill=tk.BOTH, expand=True) # 常驻队列部分 cpu_resident_frame = tb.LabelFrame( cpu_grid, text="常驻队列", padding=5, bootstyle="info" ) cpu_resident_frame.grid(row=0, column=0, padx=5, pady=5, sticky="nsew") # 常驻队列标题 tb.Label( cpu_resident_frame, text="当前任务:", font=("Segoe UI", 9, "bold"), ).pack(anchor=tk.W, padx=5, pady=(0, 5)) # 常驻队列内容 self.cpu_resident_text = scrolledtext.ScrolledText( cpu_resident_frame, wrap=tk.WORD, height=4, font=("Consolas", 9), state=tk.DISABLED ) self.cpu_resident_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=(0, 5)) # 调度队列部分 cpu_schedule_frame = tb.LabelFrame( cpu_grid, text="调度队列", padding=5, bootstyle="warning" ) cpu_schedule_frame.grid(row=1, column=0, padx=5, pady=5, sticky="nsew") # 调度队列标题 tb.Label( cpu_schedule_frame, text="当前任务:", font=("Segoe UI", 9, "bold"), ).pack(anchor=tk.W, padx=5, pady=(0, 5)) # 调度队列内容 self.cpu_schedule_text = scrolledtext.ScrolledText( cpu_schedule_frame, wrap=tk.WORD, height=4, font=("Consolas", 9), state=tk.DISABLED ) self.cpu_schedule_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=(0, 5)) # 设置网格权重 cpu_grid.rowconfigure(0, weight=1) cpu_grid.rowconfigure(1, weight=1) cpu_grid.columnconfigure(0, weight=1) # MLU队列面板 - 同样改为常驻队列和调度队列两个子面板 mlu_frame = tb.LabelFrame( queue_frame, text="MLU队列状态", padding=10, ) mlu_frame.grid(row=0, column=1, padx=(5, 0), sticky="nsew") # MLU队列内容 - 使用网格布局分为常驻队列和调度队列 mlu_grid = tb.Frame(mlu_frame) mlu_grid.pack(fill=tk.BOTH, expand=True) # 常驻队列部分 mlu_resident_frame = tb.LabelFrame( mlu_grid, text="常驻队列", padding=5, bootstyle="info" ) mlu_resident_frame.grid(row=0, column=0, padx=5, pady=5, sticky="nsew") # 常驻队列标题 tb.Label( mlu_resident_frame, text="当前任务:", font=("Segoe UI", 9, "bold"), ).pack(anchor=tk.W, padx=5, pady=(0, 5)) # 常驻队列内容 self.mlu_resident_text = scrolledtext.ScrolledText( mlu_resident_frame, wrap=tk.WORD, height=4, font=("Consolas", 9), state=tk.DISABLED ) self.mlu_resident_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=(0, 5)) # 调度队列部分 mlu_schedule_frame = tb.LabelFrame( mlu_grid, text="调度队列", padding=5, bootstyle="warning" ) mlu_schedule_frame.grid(row=1, column=0, padx=5, pady=5, sticky="nsew") # 调度队列标题 tb.Label( mlu_schedule_frame, text="当前任务:", font=("Segoe UI", 9, "bold"), ).pack(anchor=tk.W, padx=5, pady=(0, 5)) # 调度队列内容 self.mlu_schedule_text = scrolledtext.ScrolledText( mlu_schedule_frame, wrap=tk.WORD, height=4, font=("Consolas", 9), state=tk.DISABLED ) self.mlu_schedule_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=(0, 5)) # 设置网格权重 mlu_grid.rowconfigure(0, weight=1) mlu_grid.rowconfigure(1, weight=1) mlu_grid.columnconfigure(0, weight=1) # 底部状态栏 status_frame = tb.Frame(self.frame) status_frame.pack(fill=tk.X, side=tk.BOTTOM) self.status_var = tk.StringVar() self.status_var.set("就绪") status_label = tb.Label( status_frame, textvariable=self.status_var, font=("Segoe UI", 9), ) status_label.pack(side=tk.LEFT, padx=15) # 任务计数 self.task_count_var = tk.StringVar() self.task_count_var.set("总任务: 0") task_count_label = tb.Label( status_frame, textvariable=self.task_count_var, font=("Segoe UI", 9), ) task_count_label.pack(side=tk.RIGHT, padx=15) def connect_to_server(self): """连接到服务器监控""" try: self.server_ip = self.ip_entry.get() self.monitor_port = int(self.monitor_entry.get()) # 重启监控线程以使用新的配置 self.monitor_running = False time.sleep(0.5) # 等待线程结束 self.start_monitor_thread() self.connected = True self.status_indicator.config(text="● 已连接", bootstyle=SUCCESS) self.status_var.set(f"已连接到 {self.server_ip}:{self.monitor_port}") self.update_status("监控连接成功") except Exception as e: self.update_status(f"连接失败: {str(e)}") self.status_indicator.config(text="● 连接失败", bootstyle=DANGER) def start_monitor_thread(self): """启动监控线程""" self.monitor_running = True threading.Thread(target=self.monitor_status, daemon=True).start() self.update_status("监控线程已启动") def monitor_status(self): """监听服务器状态""" monitor_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: monitor_socket.bind(('0.0.0.0', self.monitor_port)) self.update_status(f"开始监听端口: {self.monitor_port}") self.update_status(f"等待来自 {self.server_ip} 的数据...") except Exception as e: self.update_status(f"端口绑定失败: {str(e)}") return while self.monitor_running: try: data, addr = monitor_socket.recvfrom(4096) if addr[0] != self.server_ip: self.update_status(f"收到来自 {addr[0]} 的数据,已忽略") continue try: status_str = data.decode('utf-8') self.parse_queue_status(status_str) self.update_status("收到队列状态更新") self.last_update_var.set(f"更新: {datetime.now().strftime('%H:%M:%S')}") except UnicodeDecodeError: self.update_status("收到非文本数据,无法解码") except Exception as e: self.update_status(f"监听错误: {str(e)}") time.sleep(1) monitor_socket.close() self.update_status("监控线程已停止") def parse_queue_status(self, status_str): """解析队列状态字符串 - 更新解析逻辑以适应新格式""" # 初始化队列数据 self.cpu_resident_queue = [] # CPU常驻队列 self.cpu_schedule_queue = [] # CPU调度队列 self.mlu_resident_queue = [] # MLU常驻队列 self.mlu_schedule_queue = [] # MLU调度队列 lines = status_str.split('\n') if len(lines) < 8: self.update_status("状态信息格式错误,无法解析") return # 解析队列状态报告时间 self.report_time = "未知时间" for line in lines: if "队列状态报告" in line: # 尝试提取时间部分 # 行格式:队列状态报告 - 2023-03-02 14:30:46 parts = line.split(' - ') if len(parts) > 1: self.report_time = parts[1].strip() break # 更新报告时间标签 self.time_label.config(text=f"报告时间: {self.report_time}") # 解析CPU队列 current_section = None for line in lines: line = line.strip() # 检测队列类型 if "CPU常驻队列" in line: current_section = "CPU_RESIDENT" continue elif "CPU调度队列" in line: current_section = "CPU_SCHEDULE" continue elif "MLU常驻队列" in line: current_section = "MLU_RESIDENT" continue elif "MLU调度队列" in line: current_section = "MLU_SCHEDULE" continue elif "无任务" in line: # 空队列标记 current_section = None continue # 解析任务行 if current_section and line.startswith("任务"): # 提取任务信息 task_info = line.split(":", 1)[1].strip() # 添加到相应队列 if current_section == "CPU_RESIDENT": self.cpu_resident_queue.append(task_info) elif current_section == "CPU_SCHEDULE": self.cpu_schedule_queue.append(task_info) elif current_section == "MLU_RESIDENT": self.mlu_resident_queue.append(task_info) elif current_section == "MLU_SCHEDULE": self.mlu_schedule_queue.append(task_info) # 更新UI self.update_queue_display() def update_queue_display(self): """更新队列显示 - 适配新的队列结构""" # CPU常驻队列 self.cpu_resident_text.config(state=tk.NORMAL) self.cpu_resident_text.delete(1.0, tk.END) if self.cpu_resident_queue: for task in self.cpu_resident_queue: self.cpu_resident_text.insert(tk.END, f"• {task}\n") else: self.cpu_resident_text.insert(tk.END, "无任务") self.cpu_resident_text.config(state=tk.DISABLED) # CPU调度队列 self.cpu_schedule_text.config(state=tk.NORMAL) self.cpu_schedule_text.delete(1.0, tk.END) if self.cpu_schedule_queue: for task in self.cpu_schedule_queue: self.cpu_schedule_text.insert(tk.END, f"• {task}\n") else: self.cpu_schedule_text.insert(tk.END, "无任务") self.cpu_schedule_text.config(state=tk.DISABLED) # MLU常驻队列 self.mlu_resident_text.config(state=tk.NORMAL) self.mlu_resident_text.delete(1.0, tk.END) if self.mlu_resident_queue: for task in self.mlu_resident_queue: self.mlu_resident_text.insert(tk.END, f"• {task}\n") else: self.mlu_resident_text.insert(tk.END, "无任务") self.mlu_resident_text.config(state=tk.DISABLED) # MLU调度队列 self.mlu_schedule_text.config(state=tk.NORMAL) self.mlu_schedule_text.delete(1.0, tk.END) if self.mlu_schedule_queue: for task in self.mlu_schedule_queue: self.mlu_schedule_text.insert(tk.END, f"• {task}\n") else: self.mlu_schedule_text.insert(tk.END, "无任务") self.mlu_schedule_text.config(state=tk.DISABLED) # 更新任务计数 total_tasks = (len(self.cpu_resident_queue) + len(self.cpu_schedule_queue) + len(self.mlu_resident_queue) + len(self.mlu_schedule_queue)) self.task_count_var.set(f"总任务: {total_tasks}") def update_status(self, message): """更新状态日志""" # 更新状态栏 self.status_var.set(message) def stop(self): """停止监控""" self.monitor_running = False time.sleep(0.2) # 等待线程结束 # 主应用类 class SystemMonitorApp: def __init__(self): # 创建主窗口 - 使用darkly主题 self.root = tb.Window(themename="darkly", title="系统资源监控", size=(1650, 900)) self.root.minsize(1300, 800) self.root.protocol("WM_DELETE_WINDOW", self.on_closing) self.style.configure( 'Custom.TFrame', background=self.style.colors.inputbg # 使用输入框背景色作为次级背景 ) # 设置样式 self.style = tb.Style() # 创建主框架 - 使用网格布局 main_frame = tb.Frame(self.root, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # 配置网格权重 main_frame.columnconfigure(0, weight=1) # 左侧面板 main_frame.columnconfigure(1, weight=3) # 中间面板 main_frame.columnconfigure(2, weight=1) # 右侧面板 main_frame.rowconfigure(1, weight=1) # 获取当前主题颜色 self.bg_color = self.style.colors.bg self.secondary_bg = self.style.colors.selectbg # 使用更深一级的背景色 # 创建自定义样式 self.style.configure( 'Custom.TFrame', background=self.style.colors.inputbg # 使用输入框背景色作为次级背景 ) self.style.configure( 'Custom.TButton', background=self.style.colors.inputbg, # 使用次级背景 bordercolor=self.style.colors.border, # 边框颜色 darkcolor=self.style.colors.inputbg, # 深色状态颜色 lightcolor=self.style.colors.inputbg # 浅色状态颜色 ) self.style.configure( 'Custom.TLabel', background=self.style.colors.inputbg, # 使用次级背景 foreground=self.style.colors.fg # 前景色(文本颜色)使用主题的前景色 ) # ========== 顶部控制栏 ========== control_bar = tb.Frame(main_frame, padding=(10, 5)) control_bar.grid(row=0, column=0, columnspan=3, sticky="ew", pady=(0, 10)) # 采样频率滑块 tb.Label(control_bar, text="采样频率:", bootstyle=PRIMARY).pack(side=tk.LEFT, padx=(20, 5)) self.sampling_rate = tk.IntVar(value=1) tb.Scale( control_bar, from_=0.5, to=5, length=120, orient=tk.HORIZONTAL, variable=self.sampling_rate, bootstyle=PRIMARY ).pack(side=tk.LEFT, padx=5) # 动画速度滑块 tb.Label(control_bar, text="动画速度:", bootstyle=PRIMARY).pack(side=tk.LEFT, padx=(20, 5)) self.animation_speed = tk.DoubleVar(value=1.0) tb.Scale( control_bar, from_=0.5, to=3.0, length=120, orient=tk.HORIZONTAL, variable=self.animation_speed, bootstyle=PRIMARY ).pack(side=tk.LEFT, padx=5) # 控制按钮 tb.Button( control_bar, text="启动", bootstyle=(OUTLINE, PRIMARY), width=8, command=self.start_monitoring ).pack(side=tk.LEFT, padx=5) tb.Button( control_bar, text="暂停", bootstyle=(OUTLINE, PRIMARY), width=8, command=self.stop_monitoring ).pack(side=tk.LEFT, padx=5) tb.Button( control_bar, text="重置", bootstyle=(OUTLINE, PRIMARY), width=8, command=self.reset_all ).pack(side=tk.LEFT, padx=5) # 状态指示器 self.status_indicator = tb.Label( control_bar, text="● 等待连接", bootstyle=(WARNING, INVERSE), font=("Arial", 10), padding=(10, 0) ) self.status_indicator.pack(side=tk.RIGHT, padx=(10, 0)) # ========== 左侧设置面板 - 使用更深背景色 ========== settings_frame = tb.Frame( main_frame, padding=10, style='Custom.TFrame' ) settings_frame.grid(row=1, column=0, sticky="nsew", padx=(0, 10), pady=(0, 10)) # 添加标题 tb.Label( settings_frame, text="监控设置", bootstyle=PRIMARY, font=("Arial", 10, "bold"), style='Custom.TLabel' # 应用自定义标签样式 ).pack(anchor=tk.W, pady=(0, 10)) # 信息类型选择 - 四个垂直排列的按钮 tb.Label( settings_frame, text="信息类型:", bootstyle=PRIMARY ).pack(anchor=tk.W, pady=(0, 5)) # 创建按钮容器 - 使用垂直排列 button_container = tb.Frame(settings_frame, style='Custom.TFrame') button_container.pack(fill=tk.X, pady=(0, 10)) # 四个独立按钮 - 垂直排列 self.info_buttons = {} info_types = ["总体信息", "MLU信息", "CPU信息", "队列信息"] button_styles = [PRIMARY, PRIMARY, PRIMARY, PRIMARY] for i, (info_type, style) in enumerate(zip(info_types, button_styles)): btn = tb.Button( button_container, text=info_type, bootstyle=(OUTLINE,DARK), width=15, command=lambda t=info_type: self.set_info_type(t) ) # 存储按钮的样式信息 btn.pack(side=tk.TOP, pady=3, fill=tk.X) self.info_buttons[info_type] = btn # 默认选中总体信息 self.info_type_var = tk.StringVar(value="总体信息") self.update_button_style("总体信息") # 分隔线 tb.Separator(settings_frame, bootstyle=SECONDARY).pack(fill=tk.X, pady=10) # 操作按钮框架 - 垂直排列 button_frame = tb.Frame(settings_frame) button_frame.pack(fill=tk.X, pady=(10, 5)) # ========== 中间监控面板 ========== self.monitor_frame = tb.Frame(main_frame, bootstyle="default") self.monitor_frame.grid(row=1, column=1, sticky="nsew", pady=(0, 10)) # 创建卡片容器 - 固定尺寸 self.card_container = tb.Frame(self.monitor_frame) self.card_container.pack(fill=tk.BOTH, expand=True) self.card_container.config(width=1100, height=700) self.card_container.pack_propagate(False) # 创建资源监控卡片 self.resource_card = tb.Frame(self.card_container) self.resource_card.pack(fill=tk.BOTH, expand=True) # 标题 tb.Label( self.resource_card, text="系统资源实时监控", font=("Arial", 16, "bold"), bootstyle=PRIMARY ).pack(pady=(0, 15)) # 创建进度条容器框架 progress_container = tb.Frame(self.resource_card) progress_container.pack(fill=tk.BOTH, expand=True, pady=5) # 创建监控指标配置 monitor_config = [ {"title": "CPU温度", "unit": "°C", "max_value": 100, "thickness": 18}, {"title": "功耗", "unit": "W", "max_value": 15, "thickness": 18}, {"title": "内存使用", "unit": "%", "max_value": 100, "thickness": 18}, {"title": "网络带宽", "unit": "Mbps", "max_value": 1000, "thickness": 18}, {"title": "MLU利用率", "unit": "%", "max_value": 100, "thickness": 18}, {"title": "CPU利用率", "unit": "%", "max_value": 100, "thickness": 18} ] # 使用网格布局排列进度条 self.progress_bars = [] for i, config in enumerate(monitor_config): frame = tb.Frame(progress_container) frame.grid(row=i//3, column=i%3, padx=15, pady=15, sticky="nsew") # 创建增强型进度条 progress_bar = EnhancedCircularProgressBar( frame, size=220, thickness=config["thickness"], title=config["title"], unit=config["unit"], max_value=config["max_value"] ) self.progress_bars.append(progress_bar) progress_bar.canvas.pack(fill=tk.BOTH, expand=True) # 设置网格列权重 for i in range(3): progress_container.columnconfigure(i, weight=1) for i in range(2): progress_container.rowconfigure(i, weight=1) # 创建队列监控卡片 self.queue_card = QueueMonitor(self.card_container) self.queue_card.container.pack_forget() # 初始隐藏 # 默认显示资源监控卡片 self.resource_card.pack(fill=tk.BOTH, expand=True) # ========== 右侧信息面板 - 使用更深背景色 ========== info_frame = tb.Frame( main_frame, padding=10, style='Custom.TFrame' ) info_frame.grid(row=1, column=2, sticky="nsew", padx=(10, 0), pady=(0, 10)) # 添加标题 tb.Label( info_frame, text="系统信息", bootstyle=PRIMARY, font=("Arial", 10, "bold"), style='Custom.TLabel' # 应用自定义标签样式 ).pack(anchor=tk.W, pady=(0, 10)) # 系统信息标签 - 调整标签宽度 info_labels = [ ("设备型号:", "MLU220"), ("操作系统:", "Ubuntu 20.04 LTS"), ("处理器:", "4核ARM Cortex-A53 CPU"), ("内存总量:", "4GB LPDDR4x"), ("MLU数量:", "4"), ("网络接口:", "PCIe 3.0×4接口") ] for label, value in info_labels: frame = tb.Frame(info_frame, style='Custom.TFrame') frame.pack(fill=tk.X, pady=3) # 增加标签宽度,确保显示完整 tb.Label(frame, text=label, width=12, anchor=tk.W, bootstyle=PRIMARY).pack(side=tk.LEFT) tb.Label(frame, text=value, bootstyle=INFO, anchor=tk.W).pack(side=tk.LEFT, fill=tk.X, expand=True) # 分隔线 tb.Separator(info_frame, bootstyle=SECONDARY).pack(fill=tk.X, pady=10) # 实时状态 tb.Label(info_frame, text="实时状态", bootstyle=PRIMARY).pack(anchor=tk.W, pady=(0, 5)) self.realtime_labels = {} status_items = [ ("CPU温度", "cpu_temp", "°C"), ("功耗", "power", "W"), ("内存使用", "memory", "%"), ("网络带宽", "bandwidth", "Mbps"), ("MLU利用率", "mlu_usage", "%"), ("CPU利用率", "cpu_usage", "%") ] for name, key, unit in status_items: frame = tb.Frame(info_frame, style='Custom.TFrame') frame.pack(fill=tk.X, pady=2) # 增加标签宽度 tb.Label(frame, text=name, width=14, anchor=tk.W, bootstyle=PRIMARY).pack(side=tk.LEFT) value_label = tb.Label(frame, text="0.0", width=10, anchor=tk.W, bootstyle=INFO) value_label.pack(side=tk.LEFT) tb.Label(frame, text=unit, bootstyle=PRIMARY).pack(side=tk.LEFT) self.realtime_labels[key] = value_label # 核心利用率框架 self.core_usage_frame = tb.LabelFrame( info_frame, text="核心利用率", bootstyle="info", padding=5 ) self.core_usage_frame.pack(fill=tk.X, pady=10) # 创建标签用于显示核心利用率 - 调整布局 self.core_labels = {} for i in range(4): # 4个核心 frame = tb.Frame(self.core_usage_frame) frame.pack(fill=tk.X, pady=2) # 核心标题 - 增加宽度 tb.Label(frame, text=f"核心 {i}:", width=10, anchor=tk.W, bootstyle=PRIMARY).pack(side=tk.LEFT) # CPU核心标签 cpu_frame = tb.Frame(frame) cpu_frame.pack(side=tk.LEFT, padx=(0, 5)) tb.Label(cpu_frame, text="CPU:", anchor=tk.W, bootstyle=PRIMARY).pack(side=tk.LEFT) cpu_label = tb.Label(cpu_frame, text="0.0%", width=6, anchor=tk.W, bootstyle=INFO) cpu_label.pack(side=tk.LEFT) self.core_labels[f"cpu_core_{i}"] = cpu_label # MLU核心标签 mlu_frame = tb.Frame(frame) mlu_frame.pack(side=tk.LEFT) tb.Label(mlu_frame, text="MLU:", anchor=tk.W, bootstyle=PRIMARY).pack(side=tk.LEFT) mlu_label = tb.Label(mlu_frame, text="0.0%", width=6, anchor=tk.W, bootstyle=INFO) mlu_label.pack(side=tk.LEFT) self.core_labels[f"mlu_core_{i}"] = mlu_label # ========== 状态栏 ========== self.status = tb.Label( self.root, text="系统准备就绪 | 当前设备: MLU220 | 信息类型: 总体信息", bootstyle=(SECONDARY, INVERSE), anchor=tk.CENTER ) self.status.pack(side=tk.BOTTOM, fill=tk.X) # 监控控制变量 self.monitoring_active = False self.monitoring_thread = None # 创建数据接收器 self.data_receiver = MLUDataReceiver(self.data_received) # 存储详细窗口引用 self.detail_window = None self.last_data = None # 初始状态 self.status_indicator.config(text="● 等待数据", bootstyle=(WARNING, INVERSE)) # 自动启动监控和连接队列监控 self.root.after(1000, self.auto_start) self.root.mainloop() def auto_start(self): """自动启动监控和连接队列监控""" # 自动启动监控 self.start_monitoring() # 自动连接队列监控 if hasattr(self, 'queue_card'): self.queue_card.connect_to_server() def update_button_style(self, active_type): """更新按钮样式以显示当前选中的信息类型""" for info_type, button in self.info_buttons.items(): if info_type == active_type: # 当前选中的按钮使用实心样式 button.configure(bootstyle=PRIMARY) else: # 其他按钮使用轮廓样式+自定义背景 button.configure( bootstyle=(OUTLINE, PRIMARY), style='Custom.TButton' # 应用自定义按钮样式 ) def set_info_type(self, info_type): """设置信息类型并更新按钮样式""" self.info_type_var.set(info_type) self.update_button_style(info_type) self.info_type_changed() def info_type_changed(self): """当信息类型变更时的处理""" info_type = self.info_type_var.get() self.status.config(text=f"已切换至: {info_type}") # 关闭已有的详细窗口 if self.detail_window and self.detail_window.window.winfo_exists(): self.detail_window.window.destroy() self.detail_window = None # 根据选择的信息类型切换中间面板 if info_type == "队列信息": # 隐藏资源监控卡片,显示队列监控卡片 self.resource_card.pack_forget() self.queue_card.container.pack(fill=tk.BOTH, expand=True) else: # 隐藏队列监控卡片,显示资源监控卡片 self.queue_card.container.pack_forget() self.resource_card.pack(fill=tk.BOTH, expand=True) # 根据选择的信息类型显示详细窗口 if info_type == "MLU信息" and self.last_data: self.show_detail_window("MLU核心利用率详情", self.last_data['mlu_usage'], self.last_data['mlu_cores'], "MLU") elif info_type == "CPU信息" and self.last_data: self.show_detail_window("CPU核心利用率详情", self.last_data['cpu_usage'], self.last_data['cpu_cores'], "CPU") def show_detail_window(self, title, avg_usage, core_usages, core_type): """显示详细核心利用率窗口""" # 关闭已有的详细窗口 if self.detail_window and self.detail_window.window.winfo_exists(): self.detail_window.window.destroy() # 创建新窗口 self.detail_window = DetailWindow(self.root, title, avg_usage, core_usages, core_type) def data_received(self, data): """从MLUDataReceiver接收数据的回调函数""" if not self.monitoring_active: return # 更新状态指示器 if data['status'] == "在线": self.status_indicator.config(text="● 已连接", bootstyle=(SUCCESS, INVERSE)) else: self.status_indicator.config(text="● 设备离线", bootstyle=(DANGER, INVERSE)) # 保存最新数据 self.last_data = data # 使用after安全更新UI self.root.after(0, self.update_ui, data) def start_monitoring(self): """启动资源监控""" if self.monitoring_active: return self.status.config(text="启动系统资源监控...") self.monitoring_active = True self.status_indicator.config(text="● 接收数据中...", bootstyle=(INFO, INVERSE)) def stop_monitoring(self): """停止资源监控""" self.monitoring_active = False self.status.config(text="监控已暂停") self.status_indicator.config(text="● 监控暂停", bootstyle=(WARNING, INVERSE)) def reset_all(self): """重置所有监控指标""" for bar in self.progress_bars: bar.set_value(0) self.status.config(text="所有监控指标已重置") def change_theme(self): """更改应用主题""" theme = self.theme_var.get() # 正确切换主题方法 self.root.style.theme_use(theme) self.status.config(text=f"主题已切换为: {theme.capitalize()}") # 更新所有进度条的颜色 style = tb.Style() for bar in self.progress_bars: bar.text_color = style.colors.fg bar.bg_color = style.colors.bg bar.secondary_bg = style.colors.inputbg bar.canvas.config(bg=bar.bg_color) bar.canvas.itemconfig(bar.text_id, fill=bar.text_color) bar.canvas.itemconfig(bar.title_id, fill=bar.text_color) bar.draw_background() bar.update_display() def update_ui(self, data): """安全更新UI组件(在主线程执行)""" # 更新进度条的动画速度 speed = self.animation_speed.get() for bar in self.progress_bars: bar.animation_speed = speed # 更新进度条 self.progress_bars[0].set_value(data['cpu_temp']) self.progress_bars[1].set_value(data['power']) self.progress_bars[2].set_value(data['mem_usage']) self.progress_bars[3].set_value(data['bandwidth']) self.progress_bars[4].set_value(data['mlu_usage']) self.progress_bars[5].set_value(data['cpu_usage']) # 更新实时状态标签 self.realtime_labels["cpu_temp"].config(text=f"{data['cpu_temp']:.1f}") self.realtime_labels["power"].config(text=f"{data['power']:.1f}") self.realtime_labels["memory"].config(text=f"{data['mem_usage']:.1f}") self.realtime_labels["bandwidth"].config(text=f"{data['bandwidth']:.1f}") self.realtime_labels["mlu_usage"].config(text=f"{data['mlu_usage']:.1f}") self.realtime_labels["cpu_usage"].config(text=f"{data['cpu_usage']:.1f}") # 更新核心利用率标签 for i in range(4): self.core_labels[f"cpu_core_{i}"].config(text=f"{data['cpu_cores'][i]:.1f}%") self.core_labels[f"mlu_core_{i}"].config(text=f"{data['mlu_cores'][i]:.1f}%") # 更新状态栏 info_type = self.info_type_var.get() status_text = ( f"当前设备: MLU220 | " f"信息类型: {info_type} | " f"状态: {data['status']} | " f"CPU: {data['cpu_usage']:.1f}% | " f"温度: {data['cpu_temp']:.1f}°C | " f"内存: {data['mem_usage']:.1f}% | " f"MLU: {data['mlu_usage']:.1f}%" ) self.status.config(text=status_text) # 如果详细窗口存在且是当前选择的信息类型,更新详细窗口 current_type = self.info_type_var.get() if self.detail_window and self.detail_window.window.winfo_exists(): if current_type == "MLU信息": self.detail_window.update_values( data['mlu_usage'], data['mlu_cores'] ) elif current_type == "CPU信息": self.detail_window.update_values( data['cpu_usage'], data['cpu_cores'] ) def on_closing(self): """窗口关闭时的清理操作""" if hasattr(self, 'data_receiver'): self.data_receiver.stop() # 停止队列监控 if hasattr(self, 'queue_card'): self.queue_card.stop() self.root.destroy() if __name__ == "__main__": app = SystemMonitorApp()修改之后出现了错误,帮我改修,写出完整的修改代码
07-08
<think>首先,用户的问题是关于在MCGS中使用Modbus RTU协议通过功能码10批量写入寄存器数据的。用户指定了功能码10,这是Modbus协议中的功能码,用于写入多个寄存器。 从系统级指令中,我需要: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,保证回答真实可靠。 用户提供了引用内容: - 引用[1]:解释了Modbus协议的基本信息、寄存器类型和功能码。 - 引用[2]:解释了数据在Modbus中如何传输,特别是使用缩放比例的例子。 - 引用[3]:是关于C#编写的Modbus RTU类库与MCGS通讯的示例。 用户的问题是:“我想在MCGS中使用Modbus RTU协议通过功能码10批量写入寄存器数据 请问MCGS Modbus RTU 协议 功能码10 批量写入寄存器 方法” 所以,我需要提供一个清晰的步骤,指导用户在MCGS中实现这个功能。MCGS是组态软件,用于工业自动化。 关键点: - Modbus功能码10(十六进制是0x10)用于写入多个保持寄存器。 - 在MCGS中,配置Modbus RTU通讯通常涉及设置设备地址、通讯参数等。 - 用户需要指定寄存器地址、数据等。 基于引用[3],它提到了一个C#编写的Modbus RTU类库,但用户现在是在MCGS中操作,所以我应该聚焦于MCGS软件本身的功能。 MCGS通常有内置的Modbus驱动,用户可以在设备配置中设置。 结构我的回答: 1. **理解功能码10**:简要解释Modbus功能码10是什么。 2. **在MCGS中的设置**:描述如何在MCGS中配置Modbus RTU设备。 3. **实现批量写入**:提供具体步骤,包括如何指定寄存器地址和数据。 4. **示例**:给一个简单的例子来演示。 5. **注意事项**:提到缩放比例或其他相关点(参考引用[2])。 6. **生成相关问题**:在结尾添加相关问题。 引用标识:我需要自然地添加引用。例如,如果引用到引用[1]或[2],就在末尾加[^1]或[^2]。 由于用户的问题没有直接引用这些内容,但引用是提供的,我应该尽可能参考。例如: - 当解释寄存器类型时,参考引用[1]。 - 当讨论数据表示时,参考引用[2]。 最后,生成相关问题。 确保回答是中文。</think>### MCGS Modbus RTU 协议功能码10批量写入寄存器方法 在MCGS(Monitor and Control Generated System)组态软件中,使用Modbus RTU协议通过功能码10(十六进制0x10)实现批量写入寄存器数据,是一种高效的工业自动化通讯方式。功能码10专门用于写入多个保持寄存器(Hold Registers),这些寄存器地址范围通常为30001-39999(对应Modbus协议中的0x0000-0xFFFF偏移地址)[^1]。下面我将逐步指导您完成配置和实现过程。整个方法基于MCGS内置的Modbus驱动,确保操作可靠且易于实施。 #### 步骤1: 理解功能码10的工作原理 功能码10允许一次性写入多个连续寄存器,数据包结构包括: - 起始地址:写入的第一个寄存器地址(例如,30001)。 - 寄存器数量:要写入的连续寄存器个数(例如,2个寄存器)。 - 数据长度:字节数,计算公式为$ \text{字节数} = 2 \times \text{寄存器数量} $(因为每个寄存器占2字节)[^1]。 - 数据:要写入的实际数据,需换为16位整数。如果数据是浮点数或带小数点的,需应用缩放比例(例如,220V可能表示为2200,缩放因子为10)[^2]。 例如,写入两个寄存器地址30001和30002,分别为2200和1500,数据包格式如下: - 功能码:0x10 - 起始地址:0x0000(对应30001) - 寄存器数量:0x0002 - 字节数:0x04 - 数据:0x0898(2200的十六进制)和0x05DC(1500的十六进制) 数学上,缩放比例可表示为:如果实际$ v $,缩放后$ v_{\text{scaled}} = v \times \text{scale} $。例如,电压220V,缩放因子10,则写入$ 220 \times 10 = 2200 $[^2]。 #### 步骤2: 在MCGS中配置Modbus RTU设备 MCGS提供了内置的Modbus RTU驱动,您需要在软件中进行设备组态。以下是详细步骤: 1. **打开MCGS工程**: - 启动MCGS组态软件,创建或打开您的工程。 - 在“设备窗口”中添加新设备:右键点击“设备管理”,选择“设备驱动管理”,添加“Modbus RTU”设备。 2. **设置通讯参数**: - 双击添加的Modbus设备,进入属性设置。 - 配置串口参数:波特率(常用9600或19200)、数据位(8位)、停止位(1位)、校验位(无校验、奇校验或偶校验)。这些参数必须与您的PLC或从站设备一致[^3]。 - 设置设备地址:输入Modbus从站地址(例如,1-247之间的整数)。 3. **定义寄存器变量**: - 在“实时数据库”中创建变量,用于存储要写入的数据。 - 例如,添加变量“Voltage”(类型:数值型),用于表示电压。 - 变量地址格式:使用Modbus寄存器地址,如“4x30001”表示保持寄存器地址30001(注意:MCGS中地址通常以“4x”前缀表示保持寄存器)[^1][^3]。 #### 步骤3: 实现功能码10批量写入 在MCGS中,批量写入通过脚本或按钮事件触发,使用内置函数发送Modbus命令。以下是两种常用方法: - **方法1: 使用脚本函数(推荐)** MCGS支持VBScript或JavaScript脚本。在按钮事件或定时器中,调用`!SetDevice`函数发送功能码10命令。 示例脚本(写入两个寄存器30001和30002): ```vbscript ' 定义写入数据:起始地址30001,寄存器数量2,数据[2200, 1500] Dim dataArray(2) dataArray(0) = 2200 ' 对应30001,缩放后的电压 dataArray(1) = 1500 ' 对应30002,其他 ' 发送功能码10命令 !SetDevice("ModbusDevice1", 16, 30001, 2, dataArray) ``` - 参数说明: - `"ModbusDevice1"`:您在设备窗口中定义的Modbus设备名称。 - `16`:功能码10的十进制(十六进制0x10)。 - `30001`:起始寄存器地址。 - `2`:寄存器数量。 - `dataArray`:数据数组,元素个数必须匹配寄存器数量[^3]。 - **方法2: 通过数据对象绑定** 如果数据来自HMI界面(如输入框),可直接绑定变量: 1. 在用户窗口中,放置两个“输入框”控件。 2. 将输入框绑定到变量“Voltage”和另一个变量(如“Current”)。 3. 添加一个按钮,在按钮事件中编写脚本,将变量写入寄存器: ```vbscript ' 读取变量并缩放(例如,缩放因子10) Dim scaledVoltage = !GetVar("Voltage") * 10 Dim scaledCurrent = !GetVar("Current") * 10 ' 批量写入到寄存器30001和30002 Dim writeData(2) writeData(0) = scaledVoltage writeData(1) = scaledCurrent !SetDevice("ModbusDevice1", 16, 30001, 2, writeData) ``` #### 步骤4: 测试与调试 - **模拟测试**:在MCGS中,使用“模拟运行”模式验证通讯。检查“通讯状态”窗口,确认数据包发送成功。 - **错误处理**: - 如果写入失败,检查设备地址、串口参数是否匹配从站。 - 确保寄存器地址在有效范围(30001-39999),且数据不超过16位范围(0-65535)[^1]。 - 缩放比例必须一致:如果从站设备使用缩放因子10,MCGS脚本中也需应用相同因子[^2]。 #### 注意事项 - **性能优化**:批量写入时,尽量减少寄存器数量(例如,一次写入不超过125个寄存器),以避免通讯超时[^1]。 - **安全考虑**:在工业环境中,添加超时重试机制(MCGS脚本可使用循环和延时函数)。 - **引用参考**:Modbus RTU的详细协议说明和功能码定义可参考Modbus标准文档[^1],数据缩放方法在工业应用中常见[^2]。 通过以上步骤,您可以在MCGS中高效实现功能码10的批量写入操作。如果您提供更多细节(如具体PLC型号或数据格式),我可以进一步优化示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值