Compare commits
2 Commits
8681cc0163
...
fbab7e3c17
| Author | SHA1 | Date | |
|---|---|---|---|
| fbab7e3c17 | |||
| 78f1cf038d |
16
Window1.xaml
16
Window1.xaml
@@ -37,8 +37,8 @@
|
|||||||
<Label Content="频率:"/>
|
<Label Content="频率:"/>
|
||||||
<RadioButton x:Name="rb50Hz" Content="50 Hz" GroupName="Freq" IsChecked="True" Margin="5,0,15,0"/>
|
<RadioButton x:Name="rb50Hz" Content="50 Hz" GroupName="Freq" IsChecked="True" Margin="5,0,15,0"/>
|
||||||
<RadioButton x:Name="rb60Hz" Content="60 Hz" GroupName="Freq"/>
|
<RadioButton x:Name="rb60Hz" Content="60 Hz" GroupName="Freq"/>
|
||||||
<Label Content=" 设定电流 (A):" Margin="20,0,0,0"/>
|
<Label Content="设定电流 (A):" Margin="20,0,0,0"/>
|
||||||
<TextBox x:Name="txtSetCurrent" Text="0.65" Width="80" TextAlignment="Right"/>
|
<TextBox x:Name="txtSetCurrent" Text="0.650" Width="80" TextAlignment="Center"/>
|
||||||
<Label Content="A"/>
|
<Label Content="A"/>
|
||||||
<Button x:Name="btnSet" Content="直接设定" Click="BtnSet_Click" Width="80" Margin="10,0,0,0"/>
|
<Button x:Name="btnSet" Content="直接设定" Click="BtnSet_Click" Width="80" Margin="10,0,0,0"/>
|
||||||
<Button x:Name="btnStop" Content="禁止输出" Click="BtnStop_Click" Width="80" Margin="5,0,0,0"/>
|
<Button x:Name="btnStop" Content="禁止输出" Click="BtnStop_Click" Width="80" Margin="5,0,0,0"/>
|
||||||
@@ -47,17 +47,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<!-- 反馈显示 -->
|
|
||||||
<GroupBox Header="实际回采 (软件滑动平均滤波)" Grid.Row="2" Margin="5">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Label Content="当前实际电流:" Grid.Column="0" FontWeight="Bold"/>
|
|
||||||
<TextBox x:Name="txtActualCurrent" Grid.Column="1" Text="0.000" IsReadOnly="True" FontSize="20" FontWeight="Bold" TextAlignment="Center" Background="LightYellow"/>
|
|
||||||
</Grid>
|
|
||||||
</GroupBox>
|
|
||||||
|
|
||||||
<!-- 日志 -->
|
<!-- 日志 -->
|
||||||
<GroupBox Header="通讯日志" Grid.Row="3" Margin="5">
|
<GroupBox Header="通讯日志" Grid.Row="3" Margin="5">
|
||||||
|
|||||||
167
Window1.xaml.cs
167
Window1.xaml.cs
@@ -13,6 +13,8 @@ namespace ConstantCurrentControl
|
|||||||
{
|
{
|
||||||
private SerialPort _serialPort;
|
private SerialPort _serialPort;
|
||||||
private bool _isConnected = false;
|
private bool _isConnected = false;
|
||||||
|
private DispatcherTimer _readTimer;
|
||||||
|
private List<byte> _receiveBuffer = new List<byte>(); // 接收缓存
|
||||||
|
|
||||||
public Window1()
|
public Window1()
|
||||||
{
|
{
|
||||||
@@ -24,6 +26,11 @@ namespace ConstantCurrentControl
|
|||||||
{
|
{
|
||||||
cmbPort.ItemsSource = SerialPort.GetPortNames();
|
cmbPort.ItemsSource = SerialPort.GetPortNames();
|
||||||
if (cmbPort.Items.Count > 0) cmbPort.SelectedIndex = 0;
|
if (cmbPort.Items.Count > 0) cmbPort.SelectedIndex = 0;
|
||||||
|
|
||||||
|
// 初始化定时器(50ms 间隔,UI 线程)
|
||||||
|
_readTimer = new DispatcherTimer();
|
||||||
|
_readTimer.Interval = TimeSpan.FromMilliseconds(50);
|
||||||
|
_readTimer.Tick += ReadTimer_Tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 串口连接
|
#region 串口连接
|
||||||
@@ -39,7 +46,7 @@ namespace ConstantCurrentControl
|
|||||||
string port = cmbPort.SelectedItem.ToString();
|
string port = cmbPort.SelectedItem.ToString();
|
||||||
int baud = int.Parse((cmbBaudrate.SelectedItem as ComboBoxItem).Content.ToString());
|
int baud = int.Parse((cmbBaudrate.SelectedItem as ComboBoxItem).Content.ToString());
|
||||||
_serialPort = new SerialPort(port, baud, Parity.None, 8, StopBits.One);
|
_serialPort = new SerialPort(port, baud, Parity.None, 8, StopBits.One);
|
||||||
_serialPort.ReadTimeout = 1000; // 关键:避免永久阻塞
|
_serialPort.ReadTimeout = 100;
|
||||||
_serialPort.WriteTimeout = 1000;
|
_serialPort.WriteTimeout = 1000;
|
||||||
_serialPort.Open();
|
_serialPort.Open();
|
||||||
|
|
||||||
@@ -48,7 +55,14 @@ namespace ConstantCurrentControl
|
|||||||
btnDisconnect.IsEnabled = true;
|
btnDisconnect.IsEnabled = true;
|
||||||
AddLog($"已连接 {port} @ {baud} bps");
|
AddLog($"已连接 {port} @ {baud} bps");
|
||||||
|
|
||||||
// 发送配置命令(不输出电流,只设置模式),同样异步等待但不死锁
|
// 清空接收缓存和串口缓冲区
|
||||||
|
_receiveBuffer.Clear();
|
||||||
|
_serialPort.DiscardInBuffer();
|
||||||
|
|
||||||
|
// 启动定时器读取
|
||||||
|
_readTimer.Start();
|
||||||
|
|
||||||
|
// 发送配置命令(不跟踪模式,byte8=0)
|
||||||
await ConfigureOptimalMode();
|
await ConfigureOptimalMode();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -60,6 +74,7 @@ namespace ConstantCurrentControl
|
|||||||
|
|
||||||
private void BtnDisconnect_Click(object sender, RoutedEventArgs e)
|
private void BtnDisconnect_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_readTimer != null) _readTimer.Stop();
|
||||||
if (_serialPort != null && _serialPort.IsOpen)
|
if (_serialPort != null && _serialPort.IsOpen)
|
||||||
{
|
{
|
||||||
_serialPort.Close();
|
_serialPort.Close();
|
||||||
@@ -73,30 +88,62 @@ namespace ConstantCurrentControl
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 最优模式配置(不发电流,只设 byte6=1, byte8=1)
|
#region 定时器读取数据
|
||||||
private async Task ConfigureOptimalMode()
|
private void ReadTimer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// 构造命令:电流 0,但强制 PC 模式和跟踪模式
|
if (!_isConnected || _serialPort == null || !_serialPort.IsOpen)
|
||||||
byte[] configCmd = new byte[12];
|
return;
|
||||||
configCmd[0] = 0xFE;
|
|
||||||
configCmd[1] = 0xFE;
|
|
||||||
configCmd[2] = 0x55; // 识别码高
|
|
||||||
configCmd[3] = 0xAA; // 识别码低
|
|
||||||
configCmd[4] = 0x00; // 电流高字节 (0A)
|
|
||||||
configCmd[5] = 0x00; // 电流低字节
|
|
||||||
configCmd[6] = 0x01; // PC调节模式
|
|
||||||
configCmd[7] = 1;
|
|
||||||
configCmd[8] = 0; // 开启跟踪模式
|
|
||||||
configCmd[9] = 0x00;
|
|
||||||
configCmd[10] = 0xFF;
|
|
||||||
configCmd[11] = 0xFF;
|
|
||||||
|
|
||||||
await SendCommandSafe(configCmd);
|
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
|
#endregion
|
||||||
|
|
||||||
#region 安全的命令发送(异步读取,不卡UI)
|
#region 发送命令(只写,不等待读)
|
||||||
private async Task<bool> SendCommandSafe(byte[] command)
|
private async Task<bool> SendCommand(byte[] command)
|
||||||
{
|
{
|
||||||
if (!_isConnected || _serialPort == null || !_serialPort.IsOpen)
|
if (!_isConnected || _serialPort == null || !_serialPort.IsOpen)
|
||||||
{
|
{
|
||||||
@@ -106,53 +153,37 @@ namespace ConstantCurrentControl
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 清空缓冲区
|
|
||||||
_serialPort.DiscardInBuffer();
|
|
||||||
_serialPort.DiscardOutBuffer();
|
|
||||||
|
|
||||||
// 发送命令
|
|
||||||
await _serialPort.BaseStream.WriteAsync(command, 0, command.Length);
|
await _serialPort.BaseStream.WriteAsync(command, 0, command.Length);
|
||||||
AddLog($"发送: {BitConverter.ToString(command)}");
|
AddLog($"发送: {BitConverter.ToString(command)}");
|
||||||
|
return true;
|
||||||
// 异步读取12字节(带超时)
|
|
||||||
byte[] buffer = new byte[12];
|
|
||||||
int totalRead = 0;
|
|
||||||
DateTime start = DateTime.Now;
|
|
||||||
while (totalRead < 12 && (DateTime.Now - start).TotalMilliseconds < 1500)
|
|
||||||
{
|
|
||||||
if (_serialPort.BytesToRead > 0)
|
|
||||||
{
|
|
||||||
int read = await _serialPort.BaseStream.ReadAsync(buffer, totalRead, 12 - totalRead);
|
|
||||||
if (read > 0) totalRead += read;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
await Task.Delay(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalRead == 12)
|
|
||||||
{
|
|
||||||
AddLog($"接收: {BitConverter.ToString(buffer)}");
|
|
||||||
// 解析回采电流 (byte4, byte5)
|
|
||||||
int rawCurrent = (buffer[4] << 8) | buffer[5];
|
|
||||||
double actualCurrent = rawCurrent / 1000.0;
|
|
||||||
Dispatcher.Invoke(() => txtActualCurrent.Text = actualCurrent.ToString("F3"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddLog($"接收超时或字节数不足: {totalRead}/12");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
AddLog($"命令发送异常: {ex.Message}");
|
AddLog($"发送失败: {ex.Message}");
|
||||||
return false;
|
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
|
#endregion
|
||||||
|
|
||||||
#region 设定电流(平滑可选项,但为了简洁直接发)
|
#region UI操作
|
||||||
private async void BtnSet_Click(object sender, RoutedEventArgs e)
|
private async void BtnSet_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!_isConnected)
|
if (!_isConnected)
|
||||||
@@ -166,7 +197,6 @@ namespace ConstantCurrentControl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造12字节电流命令
|
|
||||||
int raw = (int)(target * 1000);
|
int raw = (int)(target * 1000);
|
||||||
byte cmdH = (byte)((raw >> 8) & 0xFF);
|
byte cmdH = (byte)((raw >> 8) & 0xFF);
|
||||||
byte cmdL = (byte)(raw & 0xFF);
|
byte cmdL = (byte)(raw & 0xFF);
|
||||||
@@ -178,21 +208,20 @@ namespace ConstantCurrentControl
|
|||||||
currentCmd[3] = 0xAA;
|
currentCmd[3] = 0xAA;
|
||||||
currentCmd[4] = cmdH;
|
currentCmd[4] = cmdH;
|
||||||
currentCmd[5] = cmdL;
|
currentCmd[5] = cmdL;
|
||||||
currentCmd[6] = 0x01; // PC模式
|
currentCmd[6] = 0x01;
|
||||||
currentCmd[7] = 1;
|
currentCmd[7] = rb50Hz.IsChecked == true ? (byte)1 : (byte)2;
|
||||||
currentCmd[8] = 0; // 跟踪
|
currentCmd[8] = 0x00; // 不跟踪
|
||||||
currentCmd[9] = 0x00;
|
currentCmd[9] = 0x00;
|
||||||
currentCmd[10] = 0xFF;
|
currentCmd[10] = 0xFF;
|
||||||
currentCmd[11] = 0xFF;
|
currentCmd[11] = 0xFF;
|
||||||
|
|
||||||
await SendCommandSafe(currentCmd);
|
await SendCommand(currentCmd);
|
||||||
AddLog($"设定电流 = {target:F3} A");
|
AddLog($"设定电流 = {target:F3} A");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void BtnStop_Click(object sender, RoutedEventArgs e)
|
private async void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!_isConnected) return;
|
if (!_isConnected) return;
|
||||||
// 发送电流0
|
|
||||||
byte[] stopCmd = new byte[12];
|
byte[] stopCmd = new byte[12];
|
||||||
stopCmd[0] = 0xFE;
|
stopCmd[0] = 0xFE;
|
||||||
stopCmd[1] = 0xFE;
|
stopCmd[1] = 0xFE;
|
||||||
@@ -201,12 +230,12 @@ namespace ConstantCurrentControl
|
|||||||
stopCmd[4] = 0x00;
|
stopCmd[4] = 0x00;
|
||||||
stopCmd[5] = 0x00;
|
stopCmd[5] = 0x00;
|
||||||
stopCmd[6] = 0x01;
|
stopCmd[6] = 0x01;
|
||||||
stopCmd[7] = 1; // 50Hz
|
stopCmd[7] = rb50Hz.IsChecked == true ? (byte)1 : (byte)2;
|
||||||
stopCmd[8] = 0;
|
stopCmd[8] = 0x00; // 不跟踪
|
||||||
stopCmd[9] = 0x00;
|
stopCmd[9] = 0x00;
|
||||||
stopCmd[10] = 0xFF;
|
stopCmd[10] = 0xFF;
|
||||||
stopCmd[11] = 0xFF;
|
stopCmd[11] = 0xFF;
|
||||||
await SendCommandSafe(stopCmd);
|
await SendCommand(stopCmd);
|
||||||
AddLog("禁止输出 (0A)");
|
AddLog("禁止输出 (0A)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +247,6 @@ namespace ConstantCurrentControl
|
|||||||
if (lstLog.Items.Count > 50) lstLog.Items.RemoveAt(lstLog.Items.Count - 1);
|
if (lstLog.Items.Count > 50) lstLog.Items.RemoveAt(lstLog.Items.Count - 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
Reference in New Issue
Block a user