576 lines
23 KiB
Python
576 lines
23 KiB
Python
|
|
import tkinter as tk
|
|||
|
|
from tkinter import ttk, messagebox
|
|||
|
|
import serial
|
|||
|
|
import serial.tools.list_ports
|
|||
|
|
import threading
|
|||
|
|
import time
|
|||
|
|
from datetime import datetime
|
|||
|
|
import crcmod
|
|||
|
|
|
|||
|
|
class ATEApplication:
|
|||
|
|
def __init__(self, root):
|
|||
|
|
self.root = root
|
|||
|
|
self.root.title("LARK-1FQ ATE设备监控")
|
|||
|
|
self.root.geometry("680x480")
|
|||
|
|
|
|||
|
|
# 串口相关变量
|
|||
|
|
self.serial_port = None
|
|||
|
|
self.is_connected = False
|
|||
|
|
self.read_thread = None
|
|||
|
|
self.stop_thread = False
|
|||
|
|
self.receive_buffer = bytearray() # 接收缓冲区
|
|||
|
|
|
|||
|
|
# 创建CRC计算函数
|
|||
|
|
self.crc16_func = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
|
|||
|
|
|
|||
|
|
# 数据存储
|
|||
|
|
self.frequency_values = [0, 0, 0, 0] # ch0-ch3 频率值
|
|||
|
|
self.peak_values = [0, 0, 0, 0] # ch0-ch3 峰峰值
|
|||
|
|
self.key_status = 0 # 按键状态
|
|||
|
|
self.sd_status = 0 # SD卡状态
|
|||
|
|
|
|||
|
|
# 上下限设置
|
|||
|
|
self.freq_limits = [
|
|||
|
|
{"min": 7, "max": 9}, # ch0
|
|||
|
|
{"min": 7, "max": 9}, # ch1
|
|||
|
|
{"min": 7, "max": 9}, # ch2
|
|||
|
|
{"min": 7, "max": 9} # ch3
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.peak_limits = [
|
|||
|
|
{"min": 2000, "max": 4000}, # ch0
|
|||
|
|
{"min": 2000, "max": 4000}, # ch1
|
|||
|
|
{"min": 2000, "max": 4000}, # ch2
|
|||
|
|
{"min": 2000, "max": 4000} # ch3
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.create_widgets()
|
|||
|
|
self.refresh_ports()
|
|||
|
|
|
|||
|
|
# 设置关闭事件
|
|||
|
|
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
|||
|
|
|
|||
|
|
def create_widgets(self):
|
|||
|
|
# 1. 串口相关界面
|
|||
|
|
serial_frame = ttk.LabelFrame(self.root, text="串口设置", padding=10)
|
|||
|
|
serial_frame.pack(fill="x", padx=10, pady=5)
|
|||
|
|
|
|||
|
|
# 串口号选择
|
|||
|
|
ttk.Label(serial_frame, text="串口号:").grid(row=0, column=0, padx=5)
|
|||
|
|
self.port_var = tk.StringVar()
|
|||
|
|
self.port_combobox = ttk.Combobox(serial_frame, textvariable=self.port_var, width=15)
|
|||
|
|
self.port_combobox.grid(row=0, column=1, padx=5)
|
|||
|
|
|
|||
|
|
self.refresh_btn = ttk.Button(serial_frame, text="刷新", command=self.refresh_ports)
|
|||
|
|
self.refresh_btn.grid(row=0, column=2, padx=5)
|
|||
|
|
|
|||
|
|
# 波特率选择
|
|||
|
|
ttk.Label(serial_frame, text="波特率:").grid(row=0, column=3, padx=5)
|
|||
|
|
self.baud_var = tk.StringVar(value="19200")
|
|||
|
|
baud_combobox = ttk.Combobox(serial_frame, textvariable=self.baud_var,
|
|||
|
|
values=["9600", "19200", "38400", "57600", "115200"], width=10)
|
|||
|
|
baud_combobox.grid(row=0, column=4, padx=5)
|
|||
|
|
|
|||
|
|
# 打开关闭按钮
|
|||
|
|
self.open_btn = ttk.Button(serial_frame, text="打开串口", command=self.open_serial)
|
|||
|
|
self.open_btn.grid(row=0, column=5, padx=5)
|
|||
|
|
|
|||
|
|
self.close_btn = ttk.Button(serial_frame, text="关闭串口", command=self.close_serial, state="disabled")
|
|||
|
|
self.close_btn.grid(row=0, column=6, padx=5)
|
|||
|
|
|
|||
|
|
# 调试信息显示
|
|||
|
|
self.debug_var = tk.StringVar(value="等待连接...")
|
|||
|
|
debug_label = ttk.Label(serial_frame, textvariable=self.debug_var, foreground="blue")
|
|||
|
|
debug_label.grid(row=1, column=0, columnspan=7, pady=5)
|
|||
|
|
|
|||
|
|
# 2. 数值比较界面
|
|||
|
|
value_frame = ttk.LabelFrame(self.root, text="数值比较", padding=10)
|
|||
|
|
value_frame.pack(fill="both", expand=True, padx=10, pady=5)
|
|||
|
|
|
|||
|
|
# 频率部分(左边)
|
|||
|
|
freq_frame = ttk.LabelFrame(value_frame, text="频率 (Hz)")
|
|||
|
|
freq_frame.pack(side="left", fill="both", expand=True, padx=5)
|
|||
|
|
|
|||
|
|
self.freq_widgets = []
|
|||
|
|
for i in range(4):
|
|||
|
|
ch_frame = ttk.Frame(freq_frame)
|
|||
|
|
ch_frame.pack(fill="x", pady=2)
|
|||
|
|
|
|||
|
|
ttk.Label(ch_frame, text=f"CH{i}:").pack(side="left")
|
|||
|
|
|
|||
|
|
# 最小值输入
|
|||
|
|
min_frame = ttk.Frame(ch_frame)
|
|||
|
|
min_frame.pack(side="left", padx=2)
|
|||
|
|
ttk.Label(min_frame, text="min:").pack()
|
|||
|
|
min_var = tk.StringVar(value="7")
|
|||
|
|
min_entry = tk.Entry(min_frame, textvariable=min_var, width=5, bg="white")
|
|||
|
|
min_entry.pack()
|
|||
|
|
min_entry.bind('<Return>', lambda e, ch=i: self.update_freq_limit(ch))
|
|||
|
|
|
|||
|
|
# 当前值显示
|
|||
|
|
value_label = tk.Label(ch_frame, text="0.0", width=8, relief="sunken", bg="white")
|
|||
|
|
value_label.pack(side="left", padx=5)
|
|||
|
|
|
|||
|
|
# 最大值输入
|
|||
|
|
max_frame = ttk.Frame(ch_frame)
|
|||
|
|
max_frame.pack(side="left", padx=2)
|
|||
|
|
ttk.Label(max_frame, text="max:").pack()
|
|||
|
|
max_var = tk.StringVar(value="9")
|
|||
|
|
max_entry = tk.Entry(max_frame, textvariable=max_var, width=5, bg="white")
|
|||
|
|
max_entry.pack()
|
|||
|
|
max_entry.bind('<Return>', lambda e, ch=i: self.update_freq_limit(ch))
|
|||
|
|
|
|||
|
|
self.freq_widgets.append({
|
|||
|
|
"min_var": min_var,
|
|||
|
|
"max_var": max_var,
|
|||
|
|
"min_entry": min_entry,
|
|||
|
|
"max_entry": max_entry,
|
|||
|
|
"value_label": value_label
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# 峰峰值部分(右边)
|
|||
|
|
peak_frame = ttk.LabelFrame(value_frame, text="峰峰值 (mV)")
|
|||
|
|
peak_frame.pack(side="right", fill="both", expand=True, padx=5)
|
|||
|
|
|
|||
|
|
self.peak_widgets = []
|
|||
|
|
for i in range(4):
|
|||
|
|
ch_frame = ttk.Frame(peak_frame)
|
|||
|
|
ch_frame.pack(fill="x", pady=2)
|
|||
|
|
|
|||
|
|
ttk.Label(ch_frame, text=f"CH{i}:").pack(side="left")
|
|||
|
|
|
|||
|
|
# 最小值输入
|
|||
|
|
min_frame = ttk.Frame(ch_frame)
|
|||
|
|
min_frame.pack(side="left", padx=2)
|
|||
|
|
ttk.Label(min_frame, text="min:").pack()
|
|||
|
|
min_var = tk.StringVar(value="2000")
|
|||
|
|
min_entry = tk.Entry(min_frame, textvariable=min_var, width=5, bg="white")
|
|||
|
|
min_entry.pack()
|
|||
|
|
min_entry.bind('<Return>', lambda e, ch=i: self.update_peak_limit(ch))
|
|||
|
|
|
|||
|
|
# 当前值显示
|
|||
|
|
value_label = tk.Label(ch_frame, text="0", width=8, relief="sunken", bg="white")
|
|||
|
|
value_label.pack(side="left", padx=5)
|
|||
|
|
|
|||
|
|
# 最大值输入
|
|||
|
|
max_frame = ttk.Frame(ch_frame)
|
|||
|
|
max_frame.pack(side="left", padx=2)
|
|||
|
|
ttk.Label(max_frame, text="max:").pack()
|
|||
|
|
max_var = tk.StringVar(value="4000")
|
|||
|
|
max_entry = tk.Entry(max_frame, textvariable=max_var, width=5, bg="white")
|
|||
|
|
max_entry.pack()
|
|||
|
|
max_entry.bind('<Return>', lambda e, ch=i: self.update_peak_limit(ch))
|
|||
|
|
|
|||
|
|
self.peak_widgets.append({
|
|||
|
|
"min_var": min_var,
|
|||
|
|
"max_var": max_var,
|
|||
|
|
"min_entry": min_entry,
|
|||
|
|
"max_entry": max_entry,
|
|||
|
|
"value_label": value_label
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# 3. 状态显示界面
|
|||
|
|
status_frame = ttk.LabelFrame(self.root, text="状态显示", padding=10)
|
|||
|
|
status_frame.pack(fill="x", padx=10, pady=5)
|
|||
|
|
|
|||
|
|
# 通讯状态
|
|||
|
|
comm_frame = ttk.Frame(status_frame)
|
|||
|
|
comm_frame.pack(side="left", expand=True)
|
|||
|
|
ttk.Label(comm_frame, text="通讯状态:").pack()
|
|||
|
|
self.comm_status = tk.Label(comm_frame, text="●", font=("Arial", 20), fg="red")
|
|||
|
|
self.comm_status.pack()
|
|||
|
|
|
|||
|
|
# SD卡状态
|
|||
|
|
sd_frame = ttk.Frame(status_frame)
|
|||
|
|
sd_frame.pack(side="left", expand=True)
|
|||
|
|
ttk.Label(sd_frame, text="SD卡状态:").pack()
|
|||
|
|
self.sd_status_label = tk.Label(sd_frame, text="●", font=("Arial", 20), fg="red")
|
|||
|
|
self.sd_status_label.pack()
|
|||
|
|
|
|||
|
|
# 按键状态
|
|||
|
|
key_frame = ttk.Frame(status_frame)
|
|||
|
|
key_frame.pack(side="left", expand=True)
|
|||
|
|
ttk.Label(key_frame, text="按键状态:").pack()
|
|||
|
|
self.key_status_label = tk.Label(key_frame, text="●", font=("Arial", 20), fg="red")
|
|||
|
|
self.key_status_label.pack()
|
|||
|
|
|
|||
|
|
def refresh_ports(self):
|
|||
|
|
"""刷新可用串口列表"""
|
|||
|
|
ports = serial.tools.list_ports.comports()
|
|||
|
|
port_list = [port.device for port in ports]
|
|||
|
|
self.port_combobox['values'] = port_list
|
|||
|
|
if port_list and not self.port_var.get():
|
|||
|
|
self.port_var.set(port_list[0])
|
|||
|
|
|
|||
|
|
def open_serial(self):
|
|||
|
|
"""打开串口"""
|
|||
|
|
port = self.port_var.get()
|
|||
|
|
baudrate = self.baud_var.get()
|
|||
|
|
|
|||
|
|
if not port:
|
|||
|
|
messagebox.showerror("错误", "请选择串口号")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
self.serial_port = serial.Serial(
|
|||
|
|
port=port,
|
|||
|
|
baudrate=int(baudrate),
|
|||
|
|
bytesize=serial.EIGHTBITS,
|
|||
|
|
parity=serial.PARITY_NONE,
|
|||
|
|
stopbits=serial.STOPBITS_ONE,
|
|||
|
|
timeout=0.1
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 清空缓冲区
|
|||
|
|
self.clear_serial_buffer()
|
|||
|
|
self.receive_buffer = bytearray()
|
|||
|
|
|
|||
|
|
self.is_connected = True
|
|||
|
|
self.open_btn.config(state="disabled")
|
|||
|
|
self.close_btn.config(state="normal")
|
|||
|
|
self.refresh_btn.config(state="disabled")
|
|||
|
|
|
|||
|
|
# 启动读取线程
|
|||
|
|
self.stop_thread = False
|
|||
|
|
self.read_thread = threading.Thread(target=self.serial_read_loop)
|
|||
|
|
self.read_thread.daemon = True
|
|||
|
|
self.read_thread.start()
|
|||
|
|
|
|||
|
|
self.update_debug_info("串口打开成功,开始发送查询命令...")
|
|||
|
|
messagebox.showinfo("成功", "串口打开成功")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
messagebox.showerror("错误", f"打开串口失败: {str(e)}")
|
|||
|
|
|
|||
|
|
def close_serial(self):
|
|||
|
|
"""关闭串口"""
|
|||
|
|
self.stop_thread = True
|
|||
|
|
self.is_connected = False
|
|||
|
|
|
|||
|
|
if self.serial_port and self.serial_port.is_open:
|
|||
|
|
self.serial_port.close()
|
|||
|
|
|
|||
|
|
self.open_btn.config(state="normal")
|
|||
|
|
self.close_btn.config(state="disabled")
|
|||
|
|
self.refresh_btn.config(state="normal")
|
|||
|
|
self.comm_status.config(fg="red")
|
|||
|
|
self.update_debug_info("串口已关闭")
|
|||
|
|
|
|||
|
|
def clear_serial_buffer(self):
|
|||
|
|
"""清空串口缓冲区"""
|
|||
|
|
if self.serial_port and self.serial_port.is_open:
|
|||
|
|
try:
|
|||
|
|
self.serial_port.reset_input_buffer()
|
|||
|
|
self.serial_port.reset_output_buffer()
|
|||
|
|
self.receive_buffer.clear()
|
|||
|
|
self.update_debug_info("串口缓冲区已清空")
|
|||
|
|
except Exception as e:
|
|||
|
|
self.update_debug_info(f"清空缓冲区错误: {e}")
|
|||
|
|
|
|||
|
|
def update_debug_info(self, message):
|
|||
|
|
"""更新调试信息"""
|
|||
|
|
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
|||
|
|
debug_msg = f"[{timestamp}] {message}"
|
|||
|
|
self.debug_var.set(debug_msg)
|
|||
|
|
print(debug_msg)
|
|||
|
|
|
|||
|
|
def calculate_crc(self, data):
|
|||
|
|
"""计算CRC并返回对调后的两个字节"""
|
|||
|
|
if not data:
|
|||
|
|
return bytes.fromhex('0000')
|
|||
|
|
|
|||
|
|
# 计算CRC
|
|||
|
|
crc_value = self.crc16_func(data)
|
|||
|
|
|
|||
|
|
# 转换为两个字节并对调
|
|||
|
|
crc_bytes = crc_value.to_bytes(2, byteorder='big')
|
|||
|
|
crc_swapped = bytes([crc_bytes[1], crc_bytes[0]])
|
|||
|
|
|
|||
|
|
return crc_swapped
|
|||
|
|
|
|||
|
|
def send_and_receive_command(self):
|
|||
|
|
"""发送命令并接收响应"""
|
|||
|
|
if not (self.serial_port and self.serial_port.is_open):
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 清空接收缓冲区
|
|||
|
|
self.clear_serial_buffer()
|
|||
|
|
|
|||
|
|
# 发送查询命令
|
|||
|
|
full_command = bytes.fromhex('5A04123400097991')
|
|||
|
|
self.serial_port.write(full_command)
|
|||
|
|
self.update_debug_info(f"发送命令: {full_command.hex().upper()}")
|
|||
|
|
|
|||
|
|
# 等待100ms让设备准备响应
|
|||
|
|
time.sleep(0.1)
|
|||
|
|
|
|||
|
|
# 读取响应数据
|
|||
|
|
if self.serial_port.in_waiting:
|
|||
|
|
data = self.serial_port.read(self.serial_port.in_waiting)
|
|||
|
|
if data:
|
|||
|
|
self.update_debug_info(f"收到 {len(data)} 字节响应数据")
|
|||
|
|
self.process_received_data(data)
|
|||
|
|
else:
|
|||
|
|
self.update_debug_info("未收到响应数据")
|
|||
|
|
self.root.after(0, lambda: self.comm_status.config(fg="red"))
|
|||
|
|
else:
|
|||
|
|
self.update_debug_info("无响应数据可读")
|
|||
|
|
self.root.after(0, lambda: self.comm_status.config(fg="red"))
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.update_debug_info(f"发送接收命令错误: {e}")
|
|||
|
|
self.root.after(0, lambda: self.comm_status.config(fg="red"))
|
|||
|
|
|
|||
|
|
def serial_read_loop(self):
|
|||
|
|
"""串口读取循环"""
|
|||
|
|
last_send_time = 0
|
|||
|
|
send_interval = 0.2 # 200ms发送一次
|
|||
|
|
|
|||
|
|
while self.is_connected and not self.stop_thread:
|
|||
|
|
current_time = time.time()
|
|||
|
|
|
|||
|
|
# 发送并接收命令
|
|||
|
|
if current_time - last_send_time >= send_interval:
|
|||
|
|
self.send_and_receive_command()
|
|||
|
|
last_send_time = current_time
|
|||
|
|
|
|||
|
|
time.sleep(0.01)
|
|||
|
|
|
|||
|
|
def process_received_data(self, data):
|
|||
|
|
"""处理接收到的数据"""
|
|||
|
|
hex_data = data.hex().upper()
|
|||
|
|
self.update_debug_info(f"原始响应数据: {hex_data}")
|
|||
|
|
|
|||
|
|
# 检查数据长度
|
|||
|
|
if len(data) < 23:
|
|||
|
|
self.update_debug_info(f"数据长度不足: {len(data)}字节,期望至少23字节")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 查找帧头
|
|||
|
|
frame_start = -1
|
|||
|
|
for i in range(len(data) - 2):
|
|||
|
|
if data[i] == 0x5A and data[i+1] == 0x04 and data[i+2] == 0x12:
|
|||
|
|
frame_start = i
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if frame_start == -1:
|
|||
|
|
self.update_debug_info("未找到帧头 5A0412")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self.update_debug_info(f"找到帧头,位置: {frame_start}")
|
|||
|
|
|
|||
|
|
# 提取完整帧(从帧头开始的23字节)
|
|||
|
|
if len(data) - frame_start >= 23:
|
|||
|
|
frame_data = data[frame_start:frame_start+23]
|
|||
|
|
self.process_received_frame(frame_data)
|
|||
|
|
else:
|
|||
|
|
self.update_debug_info("帧数据不完整")
|
|||
|
|
|
|||
|
|
def process_received_frame(self, data):
|
|||
|
|
"""处理接收到的完整数据帧(23字节)"""
|
|||
|
|
hex_data = data.hex().upper()
|
|||
|
|
self.update_debug_info(f"处理数据帧: {hex_data}")
|
|||
|
|
|
|||
|
|
# CRC校验 - 前21字节计算CRC,最后2字节是CRC
|
|||
|
|
if not self.check_crc(data):
|
|||
|
|
self.update_debug_info("CRC校验失败")
|
|||
|
|
self.root.after(0, lambda: self.comm_status.config(fg="red"))
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 解析数据
|
|||
|
|
try:
|
|||
|
|
# 解析峰峰值 (4个通道,每个2字节)
|
|||
|
|
peak_values = []
|
|||
|
|
for i in range(4):
|
|||
|
|
start_idx = 3 + i * 2 # 跳过帧头5A0412 (3字节)
|
|||
|
|
peak_value = (data[start_idx] << 8) | data[start_idx + 1]
|
|||
|
|
peak_values.append(peak_value)
|
|||
|
|
|
|||
|
|
# 解析频率 (4个通道,每个2字节,需要除以10)
|
|||
|
|
freq_values = []
|
|||
|
|
for i in range(4):
|
|||
|
|
start_idx = 11 + i * 2 # 峰峰值后是频率
|
|||
|
|
freq_value = (data[start_idx] << 8) | data[start_idx + 1]
|
|||
|
|
freq_values.append(freq_value / 10.0)
|
|||
|
|
|
|||
|
|
# 解析状态
|
|||
|
|
key_status = data[19] # 按键状态
|
|||
|
|
sd_status = data[20] # SD卡状态
|
|||
|
|
|
|||
|
|
self.update_debug_info(f"解析成功: 峰峰值{peak_values}, 频率{freq_values}, 按键{key_status}, SD卡{sd_status}")
|
|||
|
|
|
|||
|
|
# 更新界面
|
|||
|
|
self.root.after(0, self.update_display, peak_values, freq_values, key_status, sd_status)
|
|||
|
|
|
|||
|
|
# 通讯成功,更新状态
|
|||
|
|
self.root.after(0, lambda: self.comm_status.config(fg="green"))
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.update_debug_info(f"解析数据错误: {e}")
|
|||
|
|
self.root.after(0, lambda: self.comm_status.config(fg="red"))
|
|||
|
|
|
|||
|
|
def check_crc(self, data):
|
|||
|
|
"""CRC校验 - 前21字节计算CRC,最后2字节是CRC(需要对调)"""
|
|||
|
|
try:
|
|||
|
|
if len(data) < 23:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 分离数据(前21字节)和CRC(最后2字节)
|
|||
|
|
data_part = data[:21] # 前21字节是数据
|
|||
|
|
crc_received = data[21:23] # 最后2字节是CRC
|
|||
|
|
|
|||
|
|
# 计算期望的CRC值(对调后的)
|
|||
|
|
expected_crc = self.calculate_crc(data_part)
|
|||
|
|
|
|||
|
|
# 比较CRC
|
|||
|
|
result = crc_received == expected_crc
|
|||
|
|
if not result:
|
|||
|
|
self.update_debug_info(f"CRC不匹配: 收到{crc_received.hex().upper()}, 期望{expected_crc.hex().upper()}")
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.update_debug_info(f"CRC校验错误: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def update_display(self, peak_values, freq_values, key_status, sd_status):
|
|||
|
|
"""更新显示"""
|
|||
|
|
# 更新峰峰值
|
|||
|
|
for i in range(4):
|
|||
|
|
value = peak_values[i]
|
|||
|
|
self.peak_values[i] = value
|
|||
|
|
widget = self.peak_widgets[i]
|
|||
|
|
widget["value_label"].config(text=str(value))
|
|||
|
|
|
|||
|
|
# 检查范围并设置颜色
|
|||
|
|
in_range = self.peak_limits[i]["min"] <= value <= self.peak_limits[i]["max"]
|
|||
|
|
color = "green" if in_range else "red"
|
|||
|
|
widget["value_label"].config(bg=color)
|
|||
|
|
|
|||
|
|
# 如果越界,设置上下限输入框颜色
|
|||
|
|
min_color = "red" if value < self.peak_limits[i]["min"] else "white"
|
|||
|
|
max_color = "red" if value > self.peak_limits[i]["max"] else "white"
|
|||
|
|
widget["min_entry"].config(bg=min_color)
|
|||
|
|
widget["max_entry"].config(bg=max_color)
|
|||
|
|
|
|||
|
|
# 更新频率
|
|||
|
|
for i in range(4):
|
|||
|
|
value = freq_values[i]
|
|||
|
|
self.frequency_values[i] = value
|
|||
|
|
widget = self.freq_widgets[i]
|
|||
|
|
widget["value_label"].config(text=f"{value:.1f}")
|
|||
|
|
|
|||
|
|
# 检查范围并设置颜色
|
|||
|
|
in_range = self.freq_limits[i]["min"] <= value <= self.freq_limits[i]["max"]
|
|||
|
|
color = "green" if in_range else "red"
|
|||
|
|
widget["value_label"].config(bg=color)
|
|||
|
|
|
|||
|
|
# 如果越界,设置上下限输入框颜色
|
|||
|
|
min_color = "red" if value < self.freq_limits[i]["min"] else "white"
|
|||
|
|
max_color = "red" if value > self.freq_limits[i]["max"] else "white"
|
|||
|
|
widget["min_entry"].config(bg=min_color)
|
|||
|
|
widget["max_entry"].config(bg=max_color)
|
|||
|
|
|
|||
|
|
# 更新状态
|
|||
|
|
self.key_status = key_status
|
|||
|
|
self.sd_status = sd_status
|
|||
|
|
|
|||
|
|
# 按键状态:0=未按下,1=按下
|
|||
|
|
key_color = "green" if key_status == 1 else "red"
|
|||
|
|
self.key_status_label.config(fg=key_color)
|
|||
|
|
|
|||
|
|
# SD卡状态:5=成功,其他=失败
|
|||
|
|
sd_color = "green" if sd_status == 5 else "red"
|
|||
|
|
self.sd_status_label.config(fg=sd_color)
|
|||
|
|
|
|||
|
|
self.update_debug_info("界面更新完成")
|
|||
|
|
|
|||
|
|
def update_freq_limit(self, channel):
|
|||
|
|
"""更新频率上下限"""
|
|||
|
|
try:
|
|||
|
|
min_val = float(self.freq_widgets[channel]["min_var"].get())
|
|||
|
|
max_val = float(self.freq_widgets[channel]["max_var"].get())
|
|||
|
|
|
|||
|
|
# 验证最小值不大于最大值
|
|||
|
|
if min_val > max_val:
|
|||
|
|
messagebox.showerror("错误", "最小值不能大于最大值")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self.freq_limits[channel]["min"] = min_val
|
|||
|
|
self.freq_limits[channel]["max"] = max_val
|
|||
|
|
|
|||
|
|
# 立即检查当前值并更新显示
|
|||
|
|
self.check_freq_value(channel)
|
|||
|
|
|
|||
|
|
except ValueError:
|
|||
|
|
messagebox.showerror("错误", "请输入有效的数字")
|
|||
|
|
|
|||
|
|
def update_peak_limit(self, channel):
|
|||
|
|
"""更新峰峰值上下限"""
|
|||
|
|
try:
|
|||
|
|
min_val = float(self.peak_widgets[channel]["min_var"].get())
|
|||
|
|
max_val = float(self.peak_widgets[channel]["max_var"].get())
|
|||
|
|
|
|||
|
|
# 验证最小值不大于最大值
|
|||
|
|
if min_val > max_val:
|
|||
|
|
messagebox.showerror("错误", "最小值不能大于最大值")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self.peak_limits[channel]["min"] = min_val
|
|||
|
|
self.peak_limits[channel]["max"] = max_val
|
|||
|
|
|
|||
|
|
# 立即检查当前值并更新显示
|
|||
|
|
self.check_peak_value(channel)
|
|||
|
|
|
|||
|
|
except ValueError:
|
|||
|
|
messagebox.showerror("错误", "请输入有效的数字")
|
|||
|
|
|
|||
|
|
def check_freq_value(self, channel):
|
|||
|
|
"""检查指定通道的频率值是否在范围内"""
|
|||
|
|
value = self.frequency_values[channel]
|
|||
|
|
widget = self.freq_widgets[channel]
|
|||
|
|
|
|||
|
|
# 检查范围并设置颜色
|
|||
|
|
in_range = self.freq_limits[channel]["min"] <= value <= self.freq_limits[channel]["max"]
|
|||
|
|
color = "green" if in_range else "red"
|
|||
|
|
widget["value_label"].config(bg=color)
|
|||
|
|
|
|||
|
|
# 如果越界,设置上下限输入框颜色
|
|||
|
|
min_color = "red" if value < self.freq_limits[channel]["min"] else "white"
|
|||
|
|
max_color = "red" if value > self.freq_limits[channel]["max"] else "white"
|
|||
|
|
widget["min_entry"].config(bg=min_color)
|
|||
|
|
widget["max_entry"].config(bg=max_color)
|
|||
|
|
|
|||
|
|
def check_peak_value(self, channel):
|
|||
|
|
"""检查指定通道的峰峰值是否在范围内"""
|
|||
|
|
value = self.peak_values[channel]
|
|||
|
|
widget = self.peak_widgets[channel]
|
|||
|
|
|
|||
|
|
# 检查范围并设置颜色
|
|||
|
|
in_range = self.peak_limits[channel]["min"] <= value <= self.peak_limits[channel]["max"]
|
|||
|
|
color = "green" if in_range else "red"
|
|||
|
|
widget["value_label"].config(bg=color)
|
|||
|
|
|
|||
|
|
# 如果越界,设置上下限输入框颜色
|
|||
|
|
min_color = "red" if value < self.peak_limits[channel]["min"] else "white"
|
|||
|
|
max_color = "red" if value > self.peak_limits[channel]["max"] else "white"
|
|||
|
|
widget["min_entry"].config(bg=min_color)
|
|||
|
|
widget["max_entry"].config(bg=max_color)
|
|||
|
|
|
|||
|
|
def check_current_values(self):
|
|||
|
|
"""检查当前值是否在范围内"""
|
|||
|
|
for i in range(4):
|
|||
|
|
self.check_freq_value(i)
|
|||
|
|
self.check_peak_value(i)
|
|||
|
|
|
|||
|
|
def on_closing(self):
|
|||
|
|
"""程序关闭时的清理工作"""
|
|||
|
|
self.stop_thread = True
|
|||
|
|
if self.serial_port and self.serial_port.is_open:
|
|||
|
|
self.serial_port.close()
|
|||
|
|
self.root.destroy()
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
root = tk.Tk()
|
|||
|
|
app = ATEApplication(root)
|
|||
|
|
root.mainloop()
|