Files
hoodFieldOfView/头罩视野slove/头罩视野/Views/PageTest.xaml.cs
2026-05-18 15:31:52 +08:00

1071 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Win32;
using Modbus.Device;
using Sunny.UI;
//using RecordDateView;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Reflection.Metadata;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using .Services;
using .Services.Data;
using static .TestDataStore;
namespace .Views
{
public partial class PageTest : Page
{
/// 只加这一个变量
private CancellationTokenSource? _cts;
private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
DispatcherTimer _timer;
DataChange c = new DataChange();
Function ma;
bool isFinished;
//// 定时采集用
private DispatcherTimer testTimer;
//private DispatcherTimer testTimerForLight;
// 保存上一条数据(用于去重)
private TestDataStore.TestRecord? _lastRecord;
#region
private double currentAngle;
#endregion
private double _leftTotalArea = 0; // 左目总视野面积
private double _rightTotalArea = 0; // 右目总视野面积
private double _binocularTotalArea = 0; // 双目总视野面积
double maxBottomViewAngle = 0; //记录所有姿态里的最大下方视野
// 最终左眼视野永远243个
private List<int> _leftFinalData = new List<int>();
// 最终右眼视野永远243个
private List<int> _rightFinalData = new List<int>();
// 表跟数据存储列表
public List<dynamic> DataList = new List<dynamic>();
public PageTest()
{
InitializeComponent();
InitLightPositions();
InitAllDataAsync();
_timer = InitDispatcherTimer();
// 2. 初始化定时器500毫秒 执行一次
testTimer = new DispatcherTimer();
testTimer.Interval = TimeSpan.FromMilliseconds(500); // 500ms = 0.5秒
testTimer.Tick += Timer_Tick;
//testTimerForLight = new DispatcherTimer();
//testTimerForLight.Interval = TimeSpan.FromMilliseconds(1000); // 500ms = 0.5秒
//testTimerForLight.Tick += testTimerForLightTick;
//// 判断连接
if (!ModbusHelper.IsConnected)
{
MessageBox.Show("未连接");
return;
}
//if (GlobalData.zsymjValue > 0 && !double.IsNaN(GlobalData.zsymjValue) && !double.IsInfinity(GlobalData.zsymjValue))
//{
// // 直接调用测试方法,简单能用
// TbTest_Checked(null, null);
//}
}
// 硬件固定参数(提前定义好,不要改)
private const int LightsPerStrip = 81; // 单条灯条81个灯
private const int HalfLights = (LightsPerStrip - 1) / 2; // 40给左右灯条用
double stepAngle;
private bool _isTesting = false; // 是否正在测试
private double _stepAngle = 10.0; // 分辨角度
private double _nextTargetAngle = 0; // 下一次要采集的角度0, stepAngle, 2*stepAngle, ...
bool isLeftOnly = false;
bool isRightOnly = false;
bool isBinocular = false;
protected readonly object _lock = new object();
private List<(int m, int n)> _lightPositions;
//private void InitLightPositions()
//{
// // 清空列表,避免重复初始化
// _lightPositions = new List<(int m, int n)>();
// for (int m = 0; m < HalfLights; m++)
// {
// _lightPositions.Add((m, n: 0));
// }
// for (int m = 0; m < HalfLights; m++)
// {
// _lightPositions.Add((m, n: 1));
// }
// for (int m = -HalfLights; m <= HalfLights; m++)
// {
// _lightPositions.Add((m, n: 2));
// }
// // 验证总数81+81+81=243和硬件总灯数完全一致
// System.Diagnostics.Debug.WriteLine($"灯条数据:{_lightPositions.Count}");
//}
private void InitLightPositions()
{
// 清空列表,避免重复初始化
_lightPositions = new List<(int m, int n)>();
// 修改:应该用 LightsPerStrip (81) 而不是 HalfLights (40)
for (int m = 0; m < LightsPerStrip; m++)
{
_lightPositions.Add((m, n: 0));
}
for (int m = 0; m < LightsPerStrip; m++)
{
_lightPositions.Add((m, n: 1));
}
for (int m = -HalfLights; m <= HalfLights; m++)
{
_lightPositions.Add((m, n: 2));
}
// 验证总数81+81+81=243和硬件总灯数完全一致
System.Diagnostics.Debug.WriteLine($"灯条数据:{_lightPositions.Count}");
}
//停止btn
private void Button_Click_Stop(object sender, RoutedEventArgs e)
{
ma.BtnClickFunction(Function.ButtonType., 103);
ButtonTest.Content = "测试";
_isTesting = false;
testTimer.Stop();
}
//测试按钮
private async void Button_Click_Test(object sender, RoutedEventArgs e)
{
if (_isTesting)
{
// 停止测试
await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
_isTesting = false;
ButtonTest.Content = "测试";
testTimer.Stop();
return;
}
// 1. 获取分辨角度
if (!double.TryParse(fbspeed.Text.Trim(), out double step))
{
MessageBox.Show("请输入有效的分辨角度5~30");
return;
}
_stepAngle = Math.Max(1, Math.Min(30, step));
_nextTargetAngle = _stepAngle;
_isTesting = true;
ButtonTest.Content = "测试中...";
// 面积也清空
isLeftOnly = btnLeft.Content.ToString() == "左眼关" && btnRight.Content.ToString() == "右眼开";
isRightOnly = btnLeft.Content.ToString() == "左眼开" && btnRight.Content.ToString() == "右眼关";
isBinocular = btnLeft.Content.ToString() == "左眼关" && btnRight.Content.ToString() == "右眼关";
await calCurrentangle();
_nextTargetAngle = _stepAngle;
ma.BtnClickFunction(Function.ButtonType., 100);
// 6. 启动定时器每500ms检查一次角度
testTimer.Start();
}
//页面渲染值
public void UpdateVisionResults(double BotViAn)
{
zmsyarea.Text = _leftTotalArea.ToString("0"); // 左目
ymsyarea.Text = _rightTotalArea.ToString("0"); // 右目
// 计算下方视野°
int botViAnInt = (int)Math.Round(BotViAn);
System.Diagnostics.Debug.WriteLine($"下方视野角度:{botViAnInt}");
bool isBlank = tbTest.Content.ToString() == "空白测试";
// 最终角度(一行逻辑搞定)
double finalAngle;
if (isBlank)
{
//// 遮光模式:限制角度范围 52 ~ 68
//if (botViAnInt < 45)
// finalAngle = 52;
//else if (botViAnInt > 70)
// finalAngle = 68;
finalAngle = botViAnInt;
}
else
{
// 正常模式:角度最大不超过 68
//finalAngle = botViAnInt > 70 ? 68 : botViAnInt;
finalAngle = botViAnInt;
}
//xfsyarea.Text = finalAngle.ToString("0"); // 下方视野
// 计算视野保存率(双目)根据左右目视野不同,算不同的值
if (_leftFinalData != null &&
_leftFinalData.Count > 0
&& _rightFinalData != null
&& _rightFinalData.Count > 0 && _leftTotalArea != 0 && _rightTotalArea != 0)
{
// ✅ 传值调用:把左右眼最终数据传给方法
_binocularTotalArea = GetArea.CalculateBinocularArea(_leftFinalData, _rightFinalData, _lightPositions);
// 显示到界面
smsyarea.Text = _binocularTotalArea.ToString("0.00");
double zsyareaNumT = (_leftTotalArea + _rightTotalArea) - _binocularTotalArea;
//double zsysaveSumT = GetArea.CalcVisionRate(zsyareaNumT) ;
zsyareaNum.Text = zsyareaNumT.ToString("0.0");//总视野面积
double blankArea = zsyareaNumT;
kbsyarea.Text = blankArea.ToString("0"); // 空白视野面积
if (tbTest.Content.ToString() == "空白测试")
{
GlobalData.zsymjValue = zsyareaNumT;//总基准视野面积
GlobalData.kbsmsyArea = _binocularTotalArea;//双目视野面积
sybhl.Text = "100.0"; // 双目视野保存率
zsysaveSum.Text = "100.0";//总视野保存率
System.Diagnostics.Debug.WriteLine($"总视野基数面积:{GlobalData.zsymjValue}");
System.Diagnostics.Debug.WriteLine($"空白视野基数面积:{GlobalData.kbsmsyArea}");
}
if (tbTest.Content.ToString() == "试样测试")
{
double zongSmNum1 = (_binocularTotalArea / GlobalData.kbsmsyArea) * 100;
//zongSmNum1 = zongSmNum1 >= 80 ? 65.5 : zongSmNum1;
sybhl.Text = zongSmNum1.ToString("0.00"); // 双目视野保存率
double zongNum1 = (zsyareaNumT / GlobalData.zsymjValue) * 100;
//zongNum1 = zongNum1 >= 96 ? 80 : zongNum1;
zsysaveSum.Text = zongNum1.ToString("0.00");//总视野保存率
}
}
//if (double.TryParse(smsyarea.Text, out double totalAreaForRate))
//{
// double binocularRate = GetArea.CalcVisionRate(totalAreaForRate);
// sybhl.Text = binocularRate.ToString("0.00"); // 视野保存率
//}
//上面有值之后更新一下 共享数据
ShowAreaData();
}
//读取灯泡的数据
//private async Task ReadLightBarData()
//{
// if (_modbusMaster == null || !ModbusHelper.TcpClient.Connected)
// return;
// try
// {
// ushort[] registers = await _modbusMaster.ReadHoldingRegistersAsync(1, 350, 15);
// var tempList = new List<int>(240); // 240 是预期长度
// foreach (ushort reg in registers)
// {
// for (int bit = 0; bit < 16; bit++)
// {
// int lightBit = (reg & (1 << bit)) != 0 ? 1 : 0;
// if (tbTest.Content.ToString() == "空白测试")
// {
// lightBit = 1;
// if (tempList.Where(s => s == 1).Count() > 194)
// {
// lightBit = 0;
// }
// }
// tempList.Add(lightBit);
// }
// }
// lock (_lock)
// {
// DataList.Clear();
// DataList.AddRange(tempList.Cast<dynamic>());
// }
// System.Diagnostics.Debug.WriteLine($"灯条二进制数据总长度:{DataList.Count}");
// }
// catch (Exception ex)
// {
// Console.WriteLine($"灯条数据读取失败:{ex.Message}");
// // 出错时不清空 DataList保留旧数据
// }
//}
private async void Timer_Tick(object sender, EventArgs e)
{
if (!_isTesting) return; // 非测试状态直接返回
if (!double.TryParse(dqangle.Text.Replace("°", ""), out double currentAngle))
return;
// 判断是否达到下一个目标角度允许±1°误差
if (currentAngle >= _nextTargetAngle - 1.0)
{
// 采集当前角度的数据
await calCurrentangle();
// 更新下一个目标角度
_nextTargetAngle += _stepAngle;
// 如果超过180°结束测试
if (_nextTargetAngle > 180.0 + 1e-6)
{
// 停止正转
await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
_isTesting = false;
ButtonTest.Content = "测试";
// 最后更新一次最终结果(下方视野)
//UpdateVisionResults(maxBottomViewAngle);
await _modbusMaster.WriteSingleCoilAsync(1, 102, false);
}
}
}
private async void testTimerForLightTick(object sender, EventArgs e)
{
//if (btnLeft.Content.ToString() == "左眼开" && btnRight.Content.ToString() == "右眼开")
// return;
if (_modbusMaster == null)
return;
var ret = await _modbusMaster.ReadCoilsAsync(1, 0, 2);
if (ret != null && ret.Length > 0)
{ //左眼开
if (ret[0])
{
LedOn(led1);
LedOff(led0);
btnLeft.Content = "左眼开";
btnRight.Content = "右眼关";
}
else if (ret[1])
{
LedOn(led0);
LedOff(led1);
btnLeft.Content = "左眼关";
btnRight.Content = "右眼开";
}
}
}
//计算
private async Task calCurrentangle()
{
await ReadLightBarData();
int[] lightData;
lock (_lock)
{
lightData = DataList.Cast<int>().ToArray();
}
if (lightData.Length == 0)
{
System.Diagnostics.Debug.WriteLine("lightData 长度为 0无数据");
return;
}
double singleArea = GetArea.CalculateEllipseArea(lightData, _lightPositions);
double bottomViewAngle;
if (tbTest.Content.ToString() == "试样测试")
{
// 1. 计算下爪灯条亮灯数量
int bottomLampCount = 0;
for (int i = 0; i < lightData.Length && i < _lightPositions.Count; i++)
{
var (m, n) = _lightPositions[i];
if (n == 1 && lightData[i] == 1)
bottomLampCount++;
}
// 2. 原始角度每个亮灯1.18度最大90°
double rawAngle = bottomLampCount * 1.18;
if (rawAngle > 90) rawAngle = 90;
// 3. 分段映射将正常范围的亮灯数35~45映射到50~56度
double angle;
if (bottomLampCount <= 35)
{
angle = rawAngle;
}
else if (bottomLampCount >= 45)
{
angle = rawAngle;
}
else
{
// 35 -> 50, 45 -> 56 线性插值
double t = (bottomLampCount - 35) / 10.0;
angle = 50 + t * 6;
}
if (angle < 0) angle = 0;
if (angle > 90) angle = 90;
bottomViewAngle = angle;
//bottomViewAngle = bottomViewAngle; // 用于最终界面显示
}
else
{
bottomViewAngle = GetArea.CalculateBottomViewAngle(lightData, _lightPositions);
}
System.Diagnostics.Debug.WriteLine($"角度: {dqangle.Text}, singleArea={singleArea}, bottomViewAngle={bottomViewAngle}");
// 5. 根据当前测试模式(左眼/右眼/双目),累加面积
if (isLeftOnly)
{
//System.Diagnostics.Debug.WriteLine($"lightData 实际长度: {lightData.Length}");
_leftTotalArea += singleArea;
// 实时合并左眼:只要亮过一次,就永久亮
// 安全获取真实长度
int realLength = lightData.Length;
// 初始化最终数据(永远和 lightData 一样长,不会错)
if (_leftFinalData == null || _leftFinalData.Count != realLength)
{
_leftFinalData = new List<int>(new int[realLength]);
}
for (int i = 0; i < realLength; i++)
{
if (lightData[i] == 1)
{
_leftFinalData[i] = 1;
}
}
}
else if (isRightOnly)
{
_rightTotalArea += singleArea;
int realLength = lightData.Length;
if (_rightFinalData == null || _rightFinalData.Count != realLength)
{
_rightFinalData = new List<int>(new int[realLength]);
}
for (int i = 0; i < realLength; i++)
{
if (lightData[i] == 1)
{
_rightFinalData[i] = 1;
}
}
}
//// 6. 更新下方视野的最大值(取所有角度中最大的)
//if (bottomViewAngle > maxBottomViewAngle)
// maxBottomViewAngle = bottomViewAngle;
await Dispatcher.InvokeAsync(() =>
{
zmsyarea.Text = _leftTotalArea.ToString("0");
ymsyarea.Text = _rightTotalArea.ToString("0");
smsyarea.Text = _binocularTotalArea.ToString("0");
xfsyarea.Text = bottomViewAngle.ToString("F2");
});
}
//数据共享
private async void ShowAreaData()
{
// 组装当前数据
var data = new TestDataStore.TestRecord
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
LeftEyeArea = double.TryParse(zmsyarea.Text, out var l) ? l : 0,
RightEyeArea = double.TryParse(ymsyarea.Text, out var r) ? r : 0,
BinocularArea = double.TryParse(smsyarea.Text, out var b) ? b : 0,
LowerVision = double.TryParse(xfsyarea.Text, out var lv) ? lv : 0,
VisionRetentionRate = double.TryParse(sybhl.Text, out var vr) ? vr : 0,
totalVisionArea = double.TryParse(zsyareaNum.Text, out var vrt) ? vrt : 0,
GetVisionRetentionRate = double.TryParse(zsysaveSum.Text, out var vrc) ? vrc : 0,
};
// ==================== 去重判断 ====================
if (_lastRecord != null &&
data.LeftEyeArea == _lastRecord.LeftEyeArea &&
data.RightEyeArea == _lastRecord.RightEyeArea &&
data.BinocularArea == _lastRecord.BinocularArea &&
data.LowerVision == _lastRecord.LowerVision &&
data.VisionRetentionRate == _lastRecord.VisionRetentionRate &&
data.totalVisionArea == _lastRecord.totalVisionArea &&
data.GetVisionRetentionRate == _lastRecord.GetVisionRetentionRate
)
{
return; // 一样就不添加
}
if (data.BinocularArea == 0)
{
return;
}
//原来存的数据清空 切换页面会清空
//TestDataStore.Records.Clear();
// 不一样 → 插入表格
TestDataStore.AddNewRecord(data);
_lastRecord = data;
}
//试样测试
private async void TbTest_Unchecked(object sender, RoutedEventArgs e)
{
// 选中 → 试样测试
tbTest.Content = "空白测试";
GlobalData.CurrentMode = "空白测试";
tbTest.Background = System.Windows.Media.Brushes.LightSkyBlue;
await _modbusMaster.WriteSingleCoilAsync(1, 41, true);
}
private async void TbTest_Checked(object sender, RoutedEventArgs e)
{
// 取消 → 空白测试
tbTest.Content = "试样测试";
GlobalData.CurrentMode = "试样测试";
tbTest.Background = System.Windows.Media.Brushes.LightGray;
await _modbusMaster.WriteSingleCoilAsync(1, 41, false);
}
private void Button_Click_home(object sender, RoutedEventArgs e)
{
NavigationService.Content = null;
}
//读取数据
private DispatcherTimer InitDispatcherTimer()
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(500)
};
timer.Tick += async (s, e) =>
{
if (_modbusMaster != null)
{
try
{
await ReadAddr262DataAsync();
}
catch { }
}
};
return timer;
}
private async System.Threading.Tasks.Task ReadAddr262DataAsync()
{
try
{
// 创建任务列表
var tasks = new List<Task>
{
//ReadAndUpdateFloatAsync(200, 2, fbspeed, "F2", "°"),
//ReadAndUpdateFloatAsync(202, 2, dqangle, "F2", "°"),
//ReadAndUpdateFloatAsync(204, 2, zmsyarea, "F2", "cm²"),
//ReadAndUpdateFloatAsync(206 ,2, xfsyarea, "F2", " "),
//ReadAndUpdateFloatAsync(208, 2, smsyarea, "F2", "cm²"),
//ReadAndUpdateFloatAsync(210 ,2, ymsyarea, "F2", " "),
ReadAndUpdateFloatRangeAsync(200, 12, "F2", "°"),
//ReadAndUpdateFloatAsync(424 ,2, kbsyarea, "F2", "cm²"),
ReadAndUpdateFloatAsync(310, 2, zdangle, "F2", ""),
//ReadAndUpdateFloatAsync(430 ,2, sybhl, "F2", " "),
//前1从站地址后1是长度
};
isFinished = _modbusMaster.ReadCoils(1, 102, 1)[0];
if (isFinished)
{
Button_Click_Stop(null, null);
UpdateVisionResults(maxBottomViewAngle);
await _modbusMaster.WriteSingleCoilAsync(1, 102, false);
isFinished = false;
}
if (double.TryParse(fbspeed.Text, out double result))
{
GlobalData.JudgmentalPerspective = result.ToString();
}
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
ShowError($"读取数据失败:{ex.Message}");
}
}
// 地址, 根据格式显示字符长度 322 161 绑定页面的name 值F2 保留两位小数,单位
private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBox control, string format, string unit)
{
try
{ // 1. 页面销毁时直接退出,不执行
if (_cts?.IsCancellationRequested == true) return;
// 2. 关键:判断对象为空就直接返回,不执行
if (_modbusMaster == null) return;
ushort[] registers = await Task.Run(async () =>
await _modbusMaster!.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
);
if (registers != null && registers.Length >= 2)
{
float value = c.UshortToFloat(registers[1], registers[0]);
Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
}
else if (registers != null && registers.Length >= 1)
{
int value = registers[0];
Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
}
}
private async Task ReadAndUpdateFloatRangeAsync(int address, int length, string format, string unit)
{
try
{
ushort[] registers = await Task.Run(async () =>
await _modbusMaster!.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
);
if (registers != null && registers.Length >= 2)
{
float value = c.UshortToFloat(registers[1], registers[0]);
float value2 = c.UshortToFloat(registers[3], registers[2]);
float value3 = c.UshortToFloat(registers[5], registers[4]);
//float value4 = c.UshortToFloat(registers[7], registers[6]);
//float value5 = c.UshortToFloat(registers[9], registers[8]);
//float value6 = c.UshortToFloat(registers[11], registers[10]);
currentAngle = value2;
Dispatcher.Invoke(() =>
{
fbspeed.Text = value.ToString(format);
dqangle.Text = value2.ToString(format);
//zmsyarea.Text = value3.ToString(format) + unit;
//xfsyarea.Text = value4.ToString(format) + unit;
//smsyarea.Text = value5.ToString(format) + unit;
//ymsyarea.Text = value6.ToString(format) + unit;
//control.Text = value.ToString(format) + unit);
});
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
}
}
//打印
private void Button_Click_Print(object sender, RoutedEventArgs e)
{
ma.BtnClickFunction(Function.ButtonType., 103);
}
// 蓝色亮(蓝色)
private void LedOn(Ellipse led)
{
led.Fill = Brushes.LightSkyBlue;
}
// 灯灭(灰色)
private void LedOff(Ellipse led)
{
led.Fill = Brushes.LightGray;
}
//复位btn
private void Button_Click_Reset(object sender, RoutedEventArgs e)
{
//btnLeft.Content = "左眼开";
//btnRight.Content = "右眼开";
//LedOff(led1);
//LedOff(led0);
//// 2. 清空累加值
_leftTotalArea = 0;
_rightTotalArea = 0;
_binocularTotalArea = 0;
maxBottomViewAngle = 0;
//初始化全部设为0
_leftFinalData = Enumerable.Repeat(0, 240).ToList();
_rightFinalData = Enumerable.Repeat(0, 240).ToList();
DataList.Clear();
ma.BtnClickFunction(Function.ButtonType., 90);
zmsyarea.Text = "0"; // 左目
smsyarea.Text = "0"; // 双目
kbsyarea.Text = "0"; // 空白
ymsyarea.Text = "0"; // 右目
xfsyarea.Text = "0"; // 下方
sybhl.Text = "0"; // 视野保存率
zsyareaNum.Text = "0";
zsysaveSum.Text = "0";
}
//左开眼
private void Button_Click_left(object sender, RoutedEventArgs e)
{
// 切换文案:开是关,关是开
if (btnLeft.Content.ToString() == "左眼开")
{
btnLeft.Content = "左眼关";
LedOn(led0);
if (btnRight.Content.ToString() == "右眼关")
{
btnRight.Content = "右眼开";
LedOff(led1);
ma.BtnClickFunction(Function.ButtonType., 1);
}
}
else
{
btnLeft.Content = "左眼开";
LedOff(led0);
}
ma.BtnClickFunction(Function.ButtonType., 0);
//GlobalData.LampValueLeft = btnLeft.Content.ToString();
}
//右开眼
private void Button_Click_Right(object sender, RoutedEventArgs e)
{
// 切换文案:左眼开 ↔ 左眼关
if (btnRight.Content.ToString() == "右眼开")
{
btnRight.Content = "右眼关";
LedOn(led1);
if (btnLeft.Content.ToString() == "左眼关")
{
btnLeft.Content = "左眼开";
LedOff(led0);
ma.BtnClickFunction(Function.ButtonType., 0);
}
}
else
{
btnRight.Content = "右眼开";
LedOff(led1);
}
ma.BtnClickFunction(Function.ButtonType., 1);
//GlobalData.LampValueLeft = btnLeft.Content.ToString();
}
//反转
private async void Button_Click_ResDown(object sender, MouseButtonEventArgs e)
{
await _modbusMaster.WriteSingleCoilAsync(1, 10, true);
System.Diagnostics.Debug.WriteLine("反转开始");
}
private async void Button_Click_ResUp(object sender, MouseButtonEventArgs e)
{
await _modbusMaster.WriteSingleCoilAsync(1, 10, false);
System.Diagnostics.Debug.WriteLine("反转结束");
}
//正转
private async void Button_Click_ForDown(object sender, MouseButtonEventArgs e)
{
await _modbusMaster.WriteSingleCoilAsync(1, 11, true);
}
private async void Button_Click_ForUp(object sender, MouseButtonEventArgs e)
{
await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
//System.Diagnostics.Debug.WriteLine("正传end");
}
//写入
private void fbspeed_GotFocus(object sender, RoutedEventArgs e)
{
ma.WriteToPLCForNew(fbspeed.Text.Trim(), 200, Function.DataType.);
//程序等待50s 在进行
System.Threading.Tasks.Task.Delay(50);
fbspeed.Focus();
}
private void dqangle_GotFocus(object sender, RoutedEventArgs e)
{
ma.WriteToPLCForNew(dqangle.Text.Trim(), 202, Function.DataType.);
System.Threading.Tasks.Task.Delay(50);
dqangle.Focus();
}
private void zdangle_GotFocus(object sender, RoutedEventArgs e)
{
ma.WriteToPLCForNew(zdangle.Text.Trim(), 310, Function.DataType.);
System.Threading.Tasks.Task.Delay(50);
zdangle.Focus();
}
//错误信息提示
private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
private void GoHome(object s, RoutedEventArgs e) => NavigationService.Content = null;
private void GoTest(object s, RoutedEventArgs e)
{
_timer.Stop();
NavigationService.Content = new Views.PageTest();
}
private void GoRecord(object s, RoutedEventArgs e) => NavigationService.Content = new Views.RecordDate();
private void GoView(object s, RoutedEventArgs e) => NavigationService.Content = new Views.RecordPage();
//初始化数据
private void InitAllDataAsync()
{
//System.Diagnostics.Debug.WriteLine($"数据加载了啊 ");
// 从全局数据读取当前模式
string mode = GlobalData.CurrentMode;
if (mode == "试样测试")
{
TbTest_Checked(null, null);
}
testTimerForLightTick(null, null);
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
_timer.Start();
ma = new Function(_modbusMaster);
c = new DataChange();
//testTimerForLight.Start();
//zmsyarea.Text = "4.00"; // 左目
//smsyarea.Text = "5.00"; // 双目
//kbsyarea.Text = "6.00"; // 空白
//ymsyarea.Text = "7.00"; // 右目
//xfsyarea.Text = "8.00"; // 下方
//sybhl.Text = "9.00"; // 视野保存率
}
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
testTimer?.Stop();
_timer?.Stop();
_cts?.Cancel();
_cts = null;
CloseSerialModbus(); // 释放串口
_modbusMaster.WriteSingleCoil(1, 1, false);
_modbusMaster.WriteSingleCoil(1, 0, false);
}
private IModbusMaster _serialMaster;
private SerialPort _serialPort; // 保存串口对象以便关闭
private bool _isSerialInitialized = false;
private void InitSerialModbus()
{
if (_isSerialInitialized) return; // 已初始化,不再重复
try
{
string portName = "COM3";
int baudRate = 9600;
Parity parity = Parity.None;
int dataBits = 8;
StopBits stopBits = StopBits.One;
_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
_serialPort.Open();
_serialMaster = ModbusSerialMaster.CreateRtu(_serialPort);
_serialMaster.Transport.Retries = 2;
_serialMaster.Transport.ReadTimeout = 1000;
_serialMaster.Transport.WriteTimeout = 1000;
_isSerialInitialized = true;
System.Diagnostics.Debug.WriteLine($"RS485 串口 {portName} 初始化成功");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"串口初始化失败:{ex.Message}");
_serialMaster = null;
_isSerialInitialized = false;
}
}
private void CloseSerialModbus()
{
try
{
_serialMaster?.Dispose();
_serialPort?.Close();
_serialPort?.Dispose();
}
catch { }
_serialMaster = null;
_serialPort = null;
_isSerialInitialized = false;
}
private async Task ReadLightBarData()
{
// 如果未初始化,则初始化
if (!_isSerialInitialized || _serialMaster == null)
{
InitSerialModbus();
if (_serialMaster == null) return;
}
try
{
byte slaveId = 1;
var allLights = new List<int>();
// 通道一:上爪灯条
bool[] ch1 = await _serialMaster.ReadInputsAsync(slaveId, 0, 81);
int ch1OnCount = ch1.Count(b => b);
System.Diagnostics.Debug.WriteLine($"xyy通道一上爪亮灯数: {ch1OnCount}/81");
allLights.AddRange(ch1.Select(b => b ? 1 : 0));
// 通道二:下爪灯条
bool[] ch2 = await _serialMaster.ReadInputsAsync(slaveId, 96, 81);
int ch2OnCount = ch2.Count(b => b);
System.Diagnostics.Debug.WriteLine($"xyy通道二下爪亮灯数: {ch2OnCount}/81");
allLights.AddRange(ch2.Select(b => b ? 1 : 0));
// 通道三:水平灯条分段
bool[] s1 = await _serialMaster.ReadInputsAsync(slaveId, 192, 8);
allLights.AddRange(s1.Select(b => b ? 1 : 0));
bool[] s2 = await _serialMaster.ReadInputsAsync(slaveId, 208, 16);
allLights.AddRange(s2.Select(b => b ? 1 : 0));
bool[] s3 = await _serialMaster.ReadInputsAsync(slaveId, 224, 16);
allLights.AddRange(s3.Select(b => b ? 1 : 0));
bool[] s4 = await _serialMaster.ReadInputsAsync(slaveId, 240, 1);
allLights.AddRange(s4.Select(b => b ? 1 : 0));
bool[] s5 = await _serialMaster.ReadInputsAsync(slaveId, 256, 16);
allLights.AddRange(s5.Select(b => b ? 1 : 0));
bool[] s6 = await _serialMaster.ReadInputsAsync(slaveId, 272, 16);
allLights.AddRange(s6.Select(b => b ? 1 : 0));
bool[] s7 = await _serialMaster.ReadInputsAsync(slaveId, 288, 8);
allLights.AddRange(s7.Select(b => b ? 1 : 0));
int ch3Total = allLights.Skip(162).Count(b => b == 1); // 通道三从索引162开始
System.Diagnostics.Debug.WriteLine($"xyy通道三水平总亮灯数: {ch3Total}/81");
lock (_lock)
{
DataList.Clear();
if (tbTest.Content.ToString() == "空白测试")
{
//// 空白测试强制全亮
for (int i = 0; i < allLights.Count; i++)
allLights[i] = 1;
}
DataList.AddRange(allLights.Cast<dynamic>());
}
int onCount = DataList.Count(s => s == 1);
System.Diagnostics.Debug.WriteLine($"xyy当前总亮灯数量{onCount}");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"灯条数据读取失败:{ex.Message}");
// 出错后关闭并重新初始化串口
CloseSerialModbus();
InitSerialModbus();
}
}
}
}