using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; namespace ConstantCurrentControl { public partial class Window1 : Window { private SerialPort _serialPort; private bool _isConnected = false; private DispatcherTimer _readTimer; private List _receiveBuffer = new List(); // 接收缓存 public Window1() { InitializeComponent(); Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { cmbPort.ItemsSource = SerialPort.GetPortNames(); if (cmbPort.Items.Count > 0) cmbPort.SelectedIndex = 0; // 初始化定时器(50ms 间隔,UI 线程) _readTimer = new DispatcherTimer(); _readTimer.Interval = TimeSpan.FromMilliseconds(50); _readTimer.Tick += ReadTimer_Tick; cmbPort.Text = "COM2"; } #region 串口连接 private async void BtnConnect_Click(object sender, RoutedEventArgs e) { if (cmbPort.SelectedItem == null) { MessageBox.Show("请选择串口号"); return; } try { string port = cmbPort.SelectedItem.ToString(); int baud = int.Parse((cmbBaudrate.SelectedItem as ComboBoxItem).Content.ToString()); _serialPort = new SerialPort(port, baud, Parity.None, 8, StopBits.One); _serialPort.ReadTimeout = 100; _serialPort.WriteTimeout = 1000; _serialPort.Open(); _isConnected = true; btnConnect.IsEnabled = false; btnDisconnect.IsEnabled = true; AddLog($"已连接 {port} @ {baud} bps"); // 清空接收缓存和串口缓冲区 _receiveBuffer.Clear(); _serialPort.DiscardInBuffer(); // 启动定时器读取 _readTimer.Start(); // 发送配置命令(不跟踪模式,byte8=0) await ConfigureOptimalMode(); } catch (Exception ex) { MessageBox.Show($"连接失败: {ex.Message}"); _isConnected = false; } } private void BtnDisconnect_Click(object sender, RoutedEventArgs e) { if (_readTimer != null) _readTimer.Stop(); if (_serialPort != null && _serialPort.IsOpen) { _serialPort.Close(); _serialPort.Dispose(); _serialPort = null; } _isConnected = false; btnConnect.IsEnabled = true; btnDisconnect.IsEnabled = false; AddLog("已断开连接"); } #endregion #region 定时器读取数据 private void ReadTimer_Tick(object sender, EventArgs e) { if (!_isConnected || _serialPort == null || !_serialPort.IsOpen) return; try { int bytesToRead = _serialPort.BytesToRead; if (bytesToRead > 0) { byte[] buffer = new byte[bytesToRead]; _serialPort.Read(buffer, 0, bytesToRead); _receiveBuffer.AddRange(buffer); // 解析完整帧(12字节,以 FE FE 开头,FF FF 结尾) ParseCompleteFrames(); } } catch (Exception ex) { AddLog($"读取错误: {ex.Message}"); } } private void ParseCompleteFrames() { for (int i = 0; i <= _receiveBuffer.Count - 12; i++) { if (_receiveBuffer[i] == 0xFE && _receiveBuffer[i + 1] == 0xFE && _receiveBuffer[i + 10] == 0xFF && _receiveBuffer[i + 11] == 0xFF) { byte[] frame = _receiveBuffer.Skip(i).Take(12).ToArray(); ProcessFrame(frame); // 移除已处理的帧 _receiveBuffer.RemoveRange(0, i + 12); i = -1; // 重新扫描 } } // 防止缓存无限增长 if (_receiveBuffer.Count > 200) _receiveBuffer.RemoveRange(0, _receiveBuffer.Count - 200); } private void ProcessFrame(byte[] frame) { // 解析电流(byte4, byte5) int rawCurrent = (frame[4] << 8) | frame[5]; double current = rawCurrent / 1000.0; AddLog($"回采帧: {BitConverter.ToString(frame)} 电流={current:F3}A"); } #endregion #region 发送命令(只写,不等待读) private async Task SendCommand(byte[] command) { if (!_isConnected || _serialPort == null || !_serialPort.IsOpen) { AddLog("串口未打开"); return false; } try { await _serialPort.BaseStream.WriteAsync(command, 0, command.Length); AddLog($"发送: {BitConverter.ToString(command)}"); return true; } catch (Exception ex) { AddLog($"发送失败: {ex.Message}"); return false; } } private async Task ConfigureOptimalMode() { byte[] configCmd = new byte[12]; configCmd[0] = 0xFE; configCmd[1] = 0xFE; configCmd[2] = 0x55; configCmd[3] = 0xAA; configCmd[4] = 0x00; configCmd[5] = 0x00; configCmd[6] = 0x01; // PC调节 configCmd[7] = rb50Hz.IsChecked == true ? (byte)1 : (byte)2; configCmd[8] = 0x00; // 不跟踪(你实测稳定) configCmd[9] = 0x00; configCmd[10] = 0xFF; configCmd[11] = 0xFF; await SendCommand(configCmd); } #endregion #region UI操作 private async void BtnSet_Click(object sender, RoutedEventArgs e) { if (!_isConnected) { MessageBox.Show("请先连接串口"); return; } if (!double.TryParse(txtSetCurrent.Text, out double target) || target < 0 || target > 5) { MessageBox.Show("电流需为 0~5.000 A"); return; } int raw = (int)(target * 1000); byte cmdH = (byte)((raw >> 8) & 0xFF); byte cmdL = (byte)(raw & 0xFF); byte[] currentCmd = new byte[12]; currentCmd[0] = 0xFE; currentCmd[1] = 0xFE; currentCmd[2] = 0x55; currentCmd[3] = 0xAA; currentCmd[4] = cmdH; currentCmd[5] = cmdL; currentCmd[6] = 0x01; currentCmd[7] = rb50Hz.IsChecked == true ? (byte)1 : (byte)2; currentCmd[8] = 0x00; // 不跟踪 currentCmd[9] = 0x00; currentCmd[10] = 0xFF; currentCmd[11] = 0xFF; await SendCommand(currentCmd); AddLog($"设定电流 = {target:F3} A"); } private async void BtnStop_Click(object sender, RoutedEventArgs e) { if (!_isConnected) return; byte[] stopCmd = new byte[12]; stopCmd[0] = 0xFE; stopCmd[1] = 0xFE; stopCmd[2] = 0x55; stopCmd[3] = 0xAA; stopCmd[4] = 0x00; stopCmd[5] = 0x00; stopCmd[6] = 0x01; stopCmd[7] = rb50Hz.IsChecked == true ? (byte)1 : (byte)2; stopCmd[8] = 0x00; // 不跟踪 stopCmd[9] = 0x00; stopCmd[10] = 0xFF; stopCmd[11] = 0xFF; await SendCommand(stopCmd); AddLog("禁止输出 (0A)"); } private void AddLog(string msg) { Dispatcher.Invoke(() => { lstLog.Items.Insert(0, $"{DateTime.Now:HH:mm:ss} {msg}"); if (lstLog.Items.Count > 50) lstLog.Items.RemoveAt(lstLog.Items.Count - 1); }); } #endregion } }