package demo1;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TemperatureMonitorGUI gui = new TemperatureMonitorGUI();
gui.setVisible(true);
});
}
}
package demo1;
import java.util.Arrays;
public class ModbusRequestBuilder {
public static byte[] buildReadRequest(byte slaveId, int registerAddr) {
return new byte[]{
slaveId,
0x03, // 功能码:读保持寄存器
(byte) (registerAddr >> 8),
(byte) (registerAddr & 0xFF),
0x00, 0x01 // 读取1个寄存器
};
}
public static byte[] buildWriteRequest(byte slaveId, int registerAddr, int value) {
return new byte[]{
slaveId,
0x06, // 功能码:写单个寄存器
(byte) (registerAddr >> 8),
(byte) (registerAddr & 0xFF),
(byte) (value >> 8),
(byte) (value & 0xFF)
};
}
public static byte[] calculateCRC(byte[] data) {
int crc = 0xFFFF;
for (int pos = 0; pos < data.length; pos++) {
crc ^= data[pos] & 0xFF;
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return new byte[]{(byte) (crc & 0xFF), (byte) (crc >> 8)};
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
}
package demo1;
public class RegisterAddress {
// 测量值类
public static final int TEMP_MEASURED = 0x0000;
public static final int HUMIDITY_MEASURED = 0x0001;
public static final int RPM_MEASURED = 0x000D;
public static final int CO2_MEASURED = 0x0012;
public static final int PRESSURE_MEASURED = 0x0013;
public static final int O2_MEASURED = 0x00E8;
// 控制设定类
public static final int RUN_CONTROL = 0x0002;
public static final int TEMP_SETPOINT = 0x0003;
public static final int TIMER_SETPOINT = 0x0006;
public static final int HUMIDITY_SETPOINT = 0x0019;
public static final int RPM_SETPOINT = 0x0018;
public static final int LIGHT_GROUP1 = 0x001A;
public static final int LIGHT_GROUP2 = 0x001E;
public static final int LIGHT_GROUP3 = 0x001F;
public static final int CO2_SETPOINT = 0x001B;
public static final int O2_SETPOINT = 0x001C;
public static final int PRESSURE_SETPOINT = 0x001D;
// 状态与报警类
public static final int ALARM_STATUS = 0x000A;
public static final int DEVICE_STATUS = 0x000B;
// 连续读取
public static final int CONTINUOUS_READ = 0x00F8;
}
package demo1;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
public class SerialPortDataListenerImpl implements SerialPortDataListener {
private final SerialPort serialPort;
private final TemperatureMonitorGUI gui;
private final TemperatureController controller;
public SerialPortDataListenerImpl(SerialPort serialPort, TemperatureMonitorGUI gui, TemperatureController controller) {
this.serialPort = serialPort;
this.gui = gui;
this.controller = controller;
}
@Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
}
@Override
public void serialEvent(SerialPortEvent event) {
if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
byte[] responseData = new byte[serialPort.bytesAvailable()];
int numRead = serialPort.readBytes(responseData, responseData.length);
if (numRead > 0) {
System.out.println("收到响应: " + ModbusRequestBuilder.bytesToHex(responseData));
if (responseData.length >= 5) {
int functionCode = responseData[1] & 0xFF;
if (functionCode == 0x03 && responseData.length >= 5) {
int value = ((responseData[3] & 0xFF) << 8) | (responseData[4] & 0xFF);
double temperature = value / 10.0;
controller.updateTemperature(temperature);
}
}
}
}
}
}
package demo1;
class SerialRequest {
public byte[] data;
public boolean isManual;
public SerialRequest(byte[] data, boolean isManual) {
this.data = data;
this.isManual = isManual;
}
}
package demo1;
import com.fazecast.jSerialComm.SerialPort;
import static demo1.ModbusRequestBuilder.buildReadRequest;
import static demo1.ModbusRequestBuilder.buildWriteRequest;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TemperatureController {
private final TemperatureMonitorGUI gui;
private final String portName;
private final int baudRate;
private final int dateBite;
private final int stopBits;
private final int parity;
private SerialPort serialPort;
private volatile boolean running = false;
private final BlockingQueue<SerialRequest> requestQueue = new LinkedBlockingQueue<>();
private ScheduledExecutorService queueExecutor;
public final TemperatureProfileManager profileManager;
public TemperatureController(TemperatureMonitorGUI gui, String portName, int baudRate, int dateBite, int stopBits, int parity) {
this.gui = gui;
this.portName = portName;
this.baudRate = baudRate;
this.dateBite = dateBite;
this.stopBits = stopBits;
this.parity = parity;
this.profileManager = new TemperatureProfileManager(this);
}
public void start() {
new Thread(this::connectSerialPort).start();
}
public void stop() {
running = false;
if (queueExecutor != null) {
queueExecutor.shutdownNow();
}
if (serialPort != null && serialPort.isOpen()) {
serialPort.closePort();
}
}
private void connectSerialPort() {
serialPort = SerialPort.getCommPort(portName);
serialPort.setComPortParameters(baudRate, 8, stopBits, parity);
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1000, 0);
if (serialPort.openPort()) {
System.out.println("✅ 成功打开串口");
gui.setStatus("已连接到 " + portName);
serialPort.addDataListener(new SerialPortDataListenerImpl(serialPort, gui, this));
running = true;
startQueueConsumer();
startTemperaturePolling();
} else {
System.err.println("❌ 无法打开串口");
gui.setStatus("无法打开串口:" + portName);
}
}
private void startQueueConsumer() {
queueExecutor = new ScheduledThreadPoolExecutor(1);
queueExecutor.submit(() -> {
while (!Thread.interrupted() && running) {
try {
SerialRequest request = requestQueue.take();
sendRequest(request.data);
if (request.isManual) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
}
private void startTemperaturePolling() {
queueExecutor.scheduleAtFixedRate(() -> {
enqueueRequest(buildReadRequest((byte) 0x01, RegisterAddress.TEMP_MEASURED), false);
}, 0, 1, TimeUnit.SECONDS);
}
public void readRegister(byte slaveId, int registerAddr) {
enqueueRequest(buildReadRequest(slaveId, registerAddr), true);
}
public void writeRegister(byte slaveId, int registerAddr, int value) {
enqueueRequest(buildWriteRequest(slaveId, registerAddr, value), true);
}
private void enqueueRequest(byte[] data, boolean isManual) {
requestQueue.offer(new SerialRequest(data, isManual));
}
public void sendRequest(byte[] data) {
if (serialPort == null || !serialPort.isOpen()) {
System.err.println("串口未打开,无法发送数据");
return;
}
byte[] crc = ModbusRequestBuilder.calculateCRC(data);
byte[] fullRequest = new byte[data.length + 2];
System.arraycopy(data, 0, fullRequest, 0, data.length);
fullRequest[data.length] = crc[0]; // CRC低字节
fullRequest[data.length + 1] = crc[1]; // CRC高字节
serialPort.writeBytes(fullRequest, fullRequest.length);
System.out.println("发送请求: " + ModbusRequestBuilder.bytesToHex(fullRequest));
}
public void updateTemperature(double temperature) {
gui.updateTemperature(temperature);
}
public void readActualTemperature(byte slaveId) {
enqueueRequest(buildReadRequest(slaveId, RegisterAddress.TEMP_MEASURED), true);
}
public void readSetTemperature(byte slaveId) {
enqueueRequest(buildReadRequest(slaveId, RegisterAddress.TEMP_SETPOINT), true);
}
public void setTargetTemperature(byte slaveId, float temp) {
int value = (int)(temp * 10);
enqueueRequest(buildWriteRequest(slaveId, RegisterAddress.TEMP_SETPOINT, value), true);
}
/**
* 启动温控逻辑(定值模式)
*/
public void startControl(float targetTemp, int transitionTime) {
if (serialPort == null || !serialPort.isOpen()) return;
int registerValue = (int)(targetTemp * 10);
byte[] request = buildWriteRequest((byte) 0x01, RegisterAddress.TEMP_SETPOINT, registerValue);
sendRequest(request);
System.out.println("开始升温,目标温度:" + targetTemp + "°C,过渡时间:" + transitionTime + "秒");
}
}
package demo1;
import com.fazecast.jSerialComm.SerialPort;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class TemperatureMonitorGUI extends JFrame {
private JLabel temperatureLabel;
private JLabel statusLabel;
private JButton connectButton;
private JButton readButton;
private JButton startControlButton;
private JButton refreshPortButton;
private JComboBox<String> portComboBox;
private JComboBox<String> baudRateComboBox;
private JComboBox<String> dateBiteComboBox;
private JComboBox<String> stopBitsComboBox;
private JComboBox<String> parityComboBox;
private JComboBox<String> modeComboBox;
private TemperatureController controller;
// 输入组件
private JTextField targetTempField;
private JTextField transitionTimeField;
private Map<String, Component> modeComponents = new HashMap<>();
// 曲线模式字段
private JTextField[] curveTempFields = new JTextField[3];
private JTextField[] curveDurationFields = new JTextField[3];
private JTextField[] curveHoldFields = new JTextField[3];
private JTextField finalTempField;
private JTextField finalTransitionField;
public TemperatureMonitorGUI() {
setTitle("MODBUS RTU 温控系统");
setSize(1100, 700); // 增加整体尺寸
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setBackground(new Color(240, 245, 250)); // 设置背景色
// 使用主面板管理布局
JPanel mainPanel = new JPanel(new BorderLayout(15, 15));
mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
add(mainPanel);
// 顶部温度显示面板 - 更醒目的设计
JPanel topPanel = createTopPanel();
mainPanel.add(topPanel, BorderLayout.NORTH);
// 中央区域使用网格袋布局
JPanel centerPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(8, 8, 8, 8); // 组件间距
gbc.fill = GridBagConstraints.BOTH;
// 左侧输入配置面板 - 宽度调整
JPanel inputPanel = createInputPanel();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0.3; // 比例调整
gbc.weighty = 1.0;
centerPanel.add(inputPanel, gbc);
// 中间按钮面板 - 更紧凑
JPanel buttonPanel = createButtonPanel();
gbc.gridx = 1;
gbc.weightx = 0.2; // 比例调整
centerPanel.add(buttonPanel, gbc);
// 右侧动态面板 - 宽度增加
JPanel rightPanel = createRightPanel();
gbc.gridx = 2;
gbc.weightx = 0.4; // 比例调整
centerPanel.add(rightPanel, gbc);
mainPanel.add(centerPanel, BorderLayout.CENTER);
// 底部状态栏
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
bottomPanel.setBorder(BorderFactory.createEtchedBorder());
bottomPanel.setBackground(new Color(230, 240, 255));
statusLabel = new JLabel("状态: 未连接");
bottomPanel.add(statusLabel);
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
// 初始化控制器
controller = null;
}
private JPanel createTopPanel() {
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
topPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 15, 0));
topPanel.setBackground(new Color(70, 130, 180));
temperatureLabel = new JLabel("当前温度: -- °C");
temperatureLabel.setFont(new Font("微软雅黑", Font.BOLD, 28));
temperatureLabel.setForeground(Color.WHITE);
topPanel.add(temperatureLabel);
return topPanel;
}
private JPanel createInputPanel() {
JPanel inputPanel = new JPanel(new GridBagLayout());
inputPanel.setBorder(BorderFactory.createTitledBorder("通信配置"));
inputPanel.setBackground(Color.WHITE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
int row = 0;
// 串口选择
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("串口:"), gbc);
gbc.gridx = 1;
JPanel portPanel = new JPanel(new BorderLayout(5, 0));
portComboBox = new JComboBox<>();
portComboBox.setPreferredSize(new Dimension(180, 25));
refreshPortList();
portPanel.add(portComboBox, BorderLayout.CENTER);
refreshPortButton = new JButton("刷新");
refreshPortButton.addActionListener(e -> refreshPortList());
portPanel.add(refreshPortButton, BorderLayout.EAST);
inputPanel.add(portPanel, gbc);
// 波特率
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("波特率:"), gbc);
gbc.gridx = 1;
baudRateComboBox = new JComboBox<>(new String[]{"1200", "2400", "4800", "9600","19200"});
baudRateComboBox.setSelectedIndex(0);
inputPanel.add(baudRateComboBox, gbc);
// 数据位
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("数据位"), gbc);
gbc.gridx = 1;
dateBiteComboBox = new JComboBox<>(new String[]{"6", "7", "8"});
dateBiteComboBox.setSelectedIndex(0);
inputPanel.add(dateBiteComboBox, gbc);
// 停止位
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("停止位:"), gbc);
gbc.gridx = 1;
stopBitsComboBox = new JComboBox<>(new String[]{"1", "1.5", "2"});
stopBitsComboBox.setSelectedIndex(0);
inputPanel.add(stopBitsComboBox, gbc);
// 校验方式
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("校验方式:"), gbc);
gbc.gridx = 1;
parityComboBox = new JComboBox<>(new String[]{"None", "Even", "Odd"});
parityComboBox.setSelectedIndex(0);
inputPanel.add(parityComboBox, gbc);
// 分隔线
gbc.gridx = 0;
gbc.gridy = row++;
gbc.gridwidth = 2;
inputPanel.add(new JSeparator(), gbc);
// 查询当前温度
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("初始温度:"), gbc);
gbc.gridx = 1;
JButton queryCurrentTempButton = new JButton("查询");
queryCurrentTempButton.setPreferredSize(new Dimension(80, 25));
queryCurrentTempButton.addActionListener(this::queryCurrentTemperature);
inputPanel.add(queryCurrentTempButton, gbc);
// 查询设定温度
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("设定温度:"), gbc);
gbc.gridx = 1;
JButton querySetTempButton = new JButton("查询");
querySetTempButton.setPreferredSize(new Dimension(80, 25));
querySetTempButton.addActionListener(this::querySetTemperature);
inputPanel.add(querySetTempButton, gbc);
// 分隔线
gbc.gridx = 0;
gbc.gridy = row++;
gbc.gridwidth = 2;
inputPanel.add(new JSeparator(), gbc);
// 模式选择
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("模式选择:"), gbc);
gbc.gridx = 1;
modeComboBox = new JComboBox<>(new String[]{"定值模式", "曲线模式"});
modeComboBox.setSelectedIndex(0);
inputPanel.add(modeComboBox, gbc);
// 启动控制
gbc.gridx = 0;
gbc.gridy = row++;
inputPanel.add(new JLabel("启动控制:"), gbc);
gbc.gridx = 1;
startControlButton = new JButton("启动");
startControlButton.setPreferredSize(new Dimension(100, 30));
startControlButton.setBackground(new Color(50, 150, 50));
startControlButton.setForeground(Color.WHITE);
startControlButton.addActionListener(this::startControl);
inputPanel.add(startControlButton, gbc);
return inputPanel;
}
private JPanel createButtonPanel() {
JPanel buttonPanel = new JPanel(new GridBagLayout());
buttonPanel.setBorder(BorderFactory.createTitledBorder("操作"));
buttonPanel.setBackground(Color.WHITE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(15, 10, 15, 10);
gbc.fill = GridBagConstraints.HORIZONTAL;
// 连接按钮
connectButton = new JButton("连接串口");
connectButton.setPreferredSize(new Dimension(150, 40));
connectButton.setFont(new Font("微软雅黑", Font.BOLD, 14));
connectButton.setBackground(new Color(70, 130, 180));
connectButton.setForeground(Color.WHITE);
connectButton.addActionListener(this::connectSerialPort);
gbc.gridy = 0;
buttonPanel.add(connectButton, gbc);
// 读取温度按钮
readButton = new JButton("读取温度");
readButton.setPreferredSize(new Dimension(150, 40));
readButton.setFont(new Font("微软雅黑", Font.BOLD, 14));
readButton.setBackground(new Color(60, 179, 113));
readButton.setForeground(Color.WHITE);
readButton.addActionListener(this::readTemperature);
gbc.gridy = 1;
buttonPanel.add(readButton, gbc);
return buttonPanel;
}
private JPanel createRightPanel() {
JPanel rightPanel = new JPanel(new BorderLayout());
rightPanel.setBorder(BorderFactory.createTitledBorder("模式配置"));
rightPanel.setBackground(Color.WHITE);
// 定值模式面板
JPanel constantModePanel = createConstantModePanel();
modeComponents.put("定值模式", constantModePanel);
// 曲线模式面板
JPanel curveModePanel = createCurveModePanel();
modeComponents.put("曲线模式", curveModePanel);
// 默认加载定值模式
rightPanel.add(modeComponents.get("定值模式"), BorderLayout.CENTER);
// 模式切换监听器
modeComboBox.addActionListener(e -> {
String selectedMode = (String) modeComboBox.getSelectedItem();
rightPanel.removeAll();
rightPanel.add(modeComponents.get(selectedMode), BorderLayout.CENTER);
rightPanel.revalidate();
rightPanel.repaint();
});
return rightPanel;
}
private JPanel createConstantModePanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.WHITE);
panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
panel.add(new JLabel("目标温度 (°C):"), gbc);
gbc.gridx = 1;
targetTempField = new JTextField(10);
targetTempField.setText("25.5");
panel.add(targetTempField, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
panel.add(new JLabel("过渡时间 (秒):"), gbc);
gbc.gridx = 1;
transitionTimeField = new JTextField(10);
transitionTimeField.setText("30");
panel.add(transitionTimeField, gbc);
// 添加说明标签
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 2;
JLabel infoLabel = new JLabel("<html><div style='width:250px;'>定值模式将温度稳定在设定值,过渡时间表示达到目标温度所需时间</div></html>");
infoLabel.setForeground(new Color(100, 100, 100));
panel.add(infoLabel, gbc);
return panel;
}
// 曲线模式面板创建方法
private JPanel createCurveModePanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.WHITE);
panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
gbc.fill = GridBagConstraints.HORIZONTAL;
// 表头
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
panel.add(new JLabel("阶段"), gbc);
gbc.gridx = 1;
panel.add(new JLabel("目标温度 (°C)"), gbc);
gbc.gridx = 2;
panel.add(new JLabel("过渡时间 (秒)"), gbc);
gbc.gridx = 3;
panel.add(new JLabel("保持时间 (秒)"), gbc);
// 阶段输入区域
for (int i = 0; i < 3; i++) {
gbc.gridx = 0;
gbc.gridy = i + 1;
gbc.anchor = GridBagConstraints.WEST;
JLabel stageLabel = new JLabel("阶段 " + (i + 1) + ":");
panel.add(stageLabel, gbc);
gbc.gridx = 1;
curveTempFields[i] = new JTextField("0.0");
curveTempFields[i].setColumns(8);
panel.add(curveTempFields[i], gbc);
gbc.gridx = 2;
curveDurationFields[i] = new JTextField("30");
curveDurationFields[i].setColumns(8);
panel.add(curveDurationFields[i], gbc);
gbc.gridx = 3;
curveHoldFields[i] = new JTextField("60");
curveHoldFields[i].setColumns(8);
panel.add(curveHoldFields[i], gbc);
if (i > 0) {
stageLabel.setVisible(false);
curveTempFields[i].setVisible(false);
curveDurationFields[i].setVisible(false);
curveHoldFields[i].setVisible(false);
}
}
// 添加/删除按钮
gbc.gridy = 4;
gbc.gridx = 0;
gbc.gridwidth = 4;
gbc.anchor = GridBagConstraints.CENTER;
JPanel controlButtonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 0));
JButton addStageButton = new JButton("+");
JButton removeStageButton = new JButton("-");
controlButtonPanel.add(addStageButton);
controlButtonPanel.add(removeStageButton);
panel.add(controlButtonPanel, gbc);
// 最终目标
gbc.gridy = 5;
gbc.gridx = 0;
gbc.gridwidth = 1;
gbc.anchor = GridBagConstraints.WEST;
panel.add(new JLabel("最终目标:"), gbc);
gbc.gridx = 1;
finalTempField = new JTextField("30.0", 8);
panel.add(finalTempField, gbc);
gbc.gridx = 2;
finalTransitionField = new JTextField("30", 8);
panel.add(finalTransitionField, gbc);
// 说明文本
gbc.gridy = 6;
gbc.gridx = 0;
gbc.gridwidth = 4;
gbc.anchor = GridBagConstraints.WEST;
JLabel infoLabel = new JLabel("<html><div style='width:350px;'>点击 '+' 增加阶段,'-' 减少阶段。未填写或为 0 的阶段将被跳过</div></html>");
infoLabel.setForeground(new Color(100, 100, 100));
panel.add(infoLabel, gbc);
// 当前最大可见阶段数
final int[] maxVisibleStages = {1};
// 添加 "+" 按钮事件
addStageButton.addActionListener(e -> {
if (maxVisibleStages[0] < 3) {
maxVisibleStages[0]++;
for (int i = 0; i < 3; i++) {
boolean visible = i < maxVisibleStages[0];
curveTempFields[i].setVisible(visible);
curveDurationFields[i].setVisible(visible);
curveHoldFields[i].setVisible(visible);
if (i < 3) {
((JLabel) ((JPanel) curveTempFields[i].getParent()).getComponent(0)).setVisible(visible);
}
}
panel.revalidate();
panel.repaint();
}
});
// 添加 "-" 按钮事件
removeStageButton.addActionListener(e -> {
if (maxVisibleStages[0] > 1) {
maxVisibleStages[0]--;
for (int i = 0; i < 3; i++) {
boolean visible = i < maxVisibleStages[0];
curveTempFields[i].setVisible(visible);
curveDurationFields[i].setVisible(visible);
curveHoldFields[i].setVisible(visible);
if (i < 3) {
((JLabel) ((JPanel) curveTempFields[i].getParent()).getComponent(0)).setVisible(visible);
}
}
panel.revalidate();
panel.repaint();
}
});
return panel;
}
// =========== 以下为功能方法 ===========
private void connectSerialPort(ActionEvent e) {
String selectedPort = (String) portComboBox.getSelectedItem();
if (selectedPort != null && controller == null) {
int baudRate = Integer.parseInt((String) baudRateComboBox.getSelectedItem());
int dateBite = Integer.parseInt((String) dateBiteComboBox.getSelectedItem());
int stopBits = getStopBitsValue();
int parity = getParityValue();
controller = new TemperatureController(this, selectedPort, baudRate, dateBite,stopBits, parity);
controller.start();
connectButton.setText("断开连接");
connectButton.setBackground(new Color(246, 115, 115)); // 红色表示断开状态
} else if (controller != null) {
// 断开连接逻辑
controller.stop();
controller = null;
setStatus("已断开连接");
connectButton.setText("连接串口");
connectButton.setBackground(new Color(70, 130, 180)); // 蓝色表示连接状态
}
}
private int getStopBitsValue() {
String stopBits = (String) stopBitsComboBox.getSelectedItem();
switch (stopBits) {
case "1": return SerialPort.ONE_STOP_BIT;
case "1.5": return SerialPort.ONE_POINT_FIVE_STOP_BITS;
case "2": return SerialPort.TWO_STOP_BITS;
default: return SerialPort.ONE_STOP_BIT;
}
}
private int getParityValue() {
String parity = (String) parityComboBox.getSelectedItem();
switch (parity) {
case "None": return SerialPort.NO_PARITY;
case "Even": return SerialPort.EVEN_PARITY;
case "Odd": return SerialPort.ODD_PARITY;
default: return SerialPort.NO_PARITY;
}
}
private void readTemperature(ActionEvent e) {
if (controller != null) {
try {
byte slaveId = 0x01;
controller.readActualTemperature(slaveId);
} catch (Exception ex) {
showError("读取温度时发生错误: " + ex.getMessage());
}
} else {
showError("请先连接串口");
}
}
private void queryCurrentTemperature(ActionEvent e) {
if (controller != null) {
try {
byte slaveId = 0x01;
controller.readActualTemperature(slaveId);
} catch (Exception ex) {
showError("查询当前温度时发生错误: " + ex.getMessage());
}
} else {
showError("请先连接串口");
}
}
private void querySetTemperature(ActionEvent e) {
if (controller != null) {
try {
byte slaveId = 0x01;
controller.readSetTemperature(slaveId);
} catch (Exception ex) {
showError("查询设定温度时发生错误: " + ex.getMessage());
}
} else {
showError("请先连接串口");
}
}
private void startControl() {
String selectedMode = (String) modeComboBox.getSelectedItem();
if ("恒温模式".equals(selectedMode)) {
try {
float targetTemp = Float.parseFloat(constantTempField.getText());
controller.setConstantTemperature(targetTemp);
showInfo("恒温模式启动: " + targetTemp + "°C");
} catch (NumberFormatException ex) {
showError("请输入有效的温度值");
}
} else if ("曲线模式".equals(selectedMode)) {
float[] temps = new float[4];
int[] durations = new int[4];
int[] holdTimes = new int[3];
int stageCount = 0;
for (int i = 0; i < 3; i++) {
try {
float temp = Float.parseFloat(curveTempFields[i].getText());
int duration = Integer.parseInt(curveDurationFields[i].getText());
int holdTime = Integer.parseInt(curveHoldFields[i].getText());
// ✅ 支持目标温度设为 0°C
if (temp >= 0 && duration > 0 && holdTime >= 0) {
temps[stageCount] = temp;
durations[stageCount] = duration;
holdTimes[stageCount] = holdTime;
stageCount++;
}
} catch (NumberFormatException ignored) {}
}
// 设置最终阶段
try {
temps[stageCount] = Float.parseFloat(finalTempField.getText());
durations[stageCount] = Integer.parseInt(finalTransitionField.getText());
} catch (NumberFormatException ex) {
showError("请正确输入最终目标温度和过渡时间");
return;
}
if (stageCount == 0) {
showError("至少需要一个有效阶段");
return;
}
controller.profileManager.startCurveControl(
Arrays.copyOf(temps, stageCount + 1),
Arrays.copyOf(durations, stageCount + 1),
Arrays.copyOf(holdTimes, stageCount)
);
showInfo("曲线模式启动: " + stageCount + "个阶段 + 最终目标");
}
}
public void refreshPortList() {
portComboBox.removeAllItems();
for (SerialPort port : SerialPort.getCommPorts()) {
portComboBox.addItem(port.getSystemPortName());
}
}
public void updateTemperature(double temperature) {
SwingUtilities.invokeLater(() -> {
temperatureLabel.setText(String.format("当前温度: %.1f°C", temperature));
// 根据温度变化改变颜色
if (temperature > 35) {
temperatureLabel.setForeground(new Color(220, 20, 60)); // 高温红色
} else if (temperature < 10) {
temperatureLabel.setForeground(new Color(30, 144, 255)); // 低温蓝色
} else {
temperatureLabel.setForeground(Color.WHITE); // 正常温度白色
}
});
}
public void setStatus(String status) {
SwingUtilities.invokeLater(() ->
statusLabel.setText("状态: " + status)
);
}
private void showError(String message) {
SwingUtilities.invokeLater(() ->
JOptionPane.showMessageDialog(this, message, "错误", JOptionPane.ERROR_MESSAGE)
);
}
private void showInfo(String message) {
SwingUtilities.invokeLater(() ->
JOptionPane.showMessageDialog(this, message, "信息", JOptionPane.INFORMATION_MESSAGE)
);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TemperatureMonitorGUI gui = new TemperatureMonitorGUI();
gui.setLocationRelativeTo(null); // 居中显示
gui.setVisible(true);
});
}
}
package demo1;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
public class TemperatureProfileManager {
private final TemperatureController controller;
private final AtomicBoolean running = new AtomicBoolean(false);
private ExecutorService executor;
public TemperatureProfileManager(TemperatureController controller) {
this.controller = controller;
}
/**
* 启动多段温度曲线控制
*
* @param temps 温度数组(单位:°C)
* @param durations 每段升温时间(单位:秒)
* @param holdTimes 每段保持时间(单位:秒)
*/
public void startCurveControl(float[] temps, int[] durations, int[] holdTimes) {
if (temps.length != durations.length || temps.length != holdTimes.length + 1) {
throw new IllegalArgumentException("参数数组长度不匹配");
}
if (running.getAndSet(true)) {
System.out.println("已有任务正在运行,无法重复启动");
return;
}
executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
try {
for (int i = 0; i < temps.length - 1 && running.get(); i++) {
float targetTemp = temps[i];
int duration = durations[i];
int holdTime = holdTimes[i];
System.out.printf("阶段 %d: 设置温度 %.1f°C,升温时间 %d 秒%n", i + 1, targetTemp, duration);
controller.setTargetTemperature((byte)0x01, targetTemp);
// 等待升温完成
long startTime = System.currentTimeMillis();
while (running.get() && System.currentTimeMillis() - startTime < duration * 1000L) {
Thread.sleep(500);
}
if (!running.get()) break;
System.out.printf("阶段 %d: 已达到目标温度 %.1f°C,保持 %d 秒%n", i + 1, targetTemp, holdTime);
// 保持阶段
startTime = System.currentTimeMillis();
while (running.get() && System.currentTimeMillis() - startTime < holdTime * 1000L) {
Thread.sleep(500);
}
}
// 最终阶段
if (running.get()) {
float finalTemp = temps[temps.length - 1];
int finalDuration = durations[durations.length - 1];
System.out.printf("最终阶段: 设置温度 %.1f°C,升温时间 %d 秒%n", finalTemp, finalDuration);
controller.setTargetTemperature((byte)0x01, finalTemp);
long startTime = System.currentTimeMillis();
while (running.get() && System.currentTimeMillis() - startTime < finalDuration * 1000L) {
Thread.sleep(500);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
running.set(false);
System.out.println("温度曲线控制已完成或已停止");
}
});
}
/**
* 停止当前正在进行的温度曲线控制
*/
public void stop() {
running.set(false);
if (executor != null) {
executor.shutdownNow();
}
System.out.println("温度曲线控制已停止");
}
}
帮我根据GUI界面,完善一下其他类
最新发布