252 lines
8.3 KiB
C#
252 lines
8.3 KiB
C#
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<byte> _receiveBuffer = new List<byte>(); // 接收缓存
|
||
|
||
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;
|
||
}
|
||
|
||
#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<bool> 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
|
||
}
|
||
} |