2026-01-16 20:53:33 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO.Ports;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
2026-01-22 16:06:24 +08:00
|
|
|
|
using System.Threading;
|
2026-01-16 20:53:33 +08:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
|
|
namespace 口罩泄露定制款.Modbus
|
|
|
|
|
|
{
|
|
|
|
|
|
public class Connect_TSI
|
|
|
|
|
|
{
|
|
|
|
|
|
private SerialPort sp_Indoor;
|
|
|
|
|
|
private SerialPort sp_Outdoor;
|
|
|
|
|
|
private SerialPort sp_bendiPort;
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 协议相关常量
|
|
|
|
|
|
private const byte FRAME_HEADER = 0x15;
|
|
|
|
|
|
private const byte FRAME_TAIL = 0x16;
|
|
|
|
|
|
private const int BAUD_RATE = 115200;
|
|
|
|
|
|
private const int DATA_BITS = 8;
|
|
|
|
|
|
private const Parity PARITY = Parity.None;
|
|
|
|
|
|
private const StopBits STOP_BITS = StopBits.One;
|
|
|
|
|
|
|
|
|
|
|
|
// 命令枚举
|
|
|
|
|
|
private enum PC_CMD : byte
|
|
|
|
|
|
{
|
|
|
|
|
|
PC_CMD_RESPOND = 0x00,
|
|
|
|
|
|
PC_CMD_CONNECT,
|
|
|
|
|
|
PC_CMD_DISCONNECT,
|
|
|
|
|
|
PC_CMD_GET_DATA,
|
|
|
|
|
|
PC_CMD_GET_GENERAL,
|
|
|
|
|
|
PC_CMD_SET_GENERAL,
|
|
|
|
|
|
PC_CMD_RESET,
|
|
|
|
|
|
PC_CMD_GET_MAINTAIN,
|
|
|
|
|
|
PC_CMD_SET_MAINTAIN,
|
|
|
|
|
|
PC_CMD_GET_MEAS_SETTING,
|
|
|
|
|
|
PC_CMD_SET_MEAS_SETTING,
|
|
|
|
|
|
PC_CMD_CTRL_FIRE,
|
|
|
|
|
|
PC_CMD_DONGLE_CONNECT,
|
|
|
|
|
|
PC_CMD_GET_SELECTED_CURVE_PART1,
|
|
|
|
|
|
PC_CMD_GET_SELECTED_CURVE_PART2,
|
|
|
|
|
|
PC_CMD_GET_SELECTED_CURVE_PART3,
|
|
|
|
|
|
PC_CMD_GET_RECORD_NUM,
|
|
|
|
|
|
PC_CMD_GET_RECORD
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 响应结果枚举
|
|
|
|
|
|
private enum RESPOND_RESULT : byte
|
|
|
|
|
|
{
|
|
|
|
|
|
RESPOND_RESULT_SUCCESS = 0x00,
|
|
|
|
|
|
RESPOND_RESULT_FAIL,
|
|
|
|
|
|
RESPOND_RESULT_BUSY
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 数据结构
|
|
|
|
|
|
private struct PC_DATA
|
|
|
|
|
|
{
|
|
|
|
|
|
public byte real_param_sta; // 每个元素的真实使能情况,每1bit对应一个元素
|
|
|
|
|
|
public byte disp_param_sta; // 每个元素的显示使能情况,每1bit对应一个元素
|
|
|
|
|
|
public byte unit; // 浓度单位
|
|
|
|
|
|
public byte is_fire; // 是否已经点着火了
|
|
|
|
|
|
public ushort[] energys; // 每一个元素的能量值
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 当前数据
|
|
|
|
|
|
private float _indoor_data = 0.0f;
|
|
|
|
|
|
private float _outdoor_data = 0.0f;
|
|
|
|
|
|
private float _bendi_data = 0.0f;
|
|
|
|
|
|
|
|
|
|
|
|
// 接收缓冲区
|
|
|
|
|
|
private List<byte> indoorBuffer = new List<byte>();
|
|
|
|
|
|
private List<byte> outdoorBuffer = new List<byte>();
|
|
|
|
|
|
private List<byte> bendiBuffer = new List<byte>();
|
|
|
|
|
|
|
|
|
|
|
|
// 元素索引
|
|
|
|
|
|
private enum ELEMENT_INDEX : int
|
|
|
|
|
|
{
|
|
|
|
|
|
PARAM_NA = 0,
|
|
|
|
|
|
PARAM_K,
|
|
|
|
|
|
PARAM_LI,
|
|
|
|
|
|
PARAM_CA,
|
|
|
|
|
|
PARAM_BA,
|
|
|
|
|
|
PARAM_MAX_NUM = 5
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public float Indoor_Data { get { return _indoor_data; } }
|
|
|
|
|
|
public float Outdoor_Data { get { return _outdoor_data; } }
|
|
|
|
|
|
public float Bend_Data { get { return _bendi_data; } }
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
|
|
|
|
|
public Connect_TSI(string ComPort_TSI_Indoor, string ComPort_TSI_Outdoor)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
// 初始化串口,使用协议规定的参数
|
|
|
|
|
|
sp_Indoor = new SerialPort(ComPort_TSI_Indoor, BAUD_RATE, PARITY, DATA_BITS, STOP_BITS);
|
|
|
|
|
|
sp_Outdoor = new SerialPort(ComPort_TSI_Outdoor, BAUD_RATE, PARITY, DATA_BITS, STOP_BITS);
|
|
|
|
|
|
sp_bendiPort = new SerialPort("COM8", BAUD_RATE, PARITY, DATA_BITS, STOP_BITS); // 假设本底使用COM8
|
|
|
|
|
|
|
|
|
|
|
|
// 订阅DataReceived事件
|
2026-01-16 20:53:33 +08:00
|
|
|
|
sp_Indoor.DataReceived += new SerialDataReceivedEventHandler(Sp_Indoor_DataReceived);
|
|
|
|
|
|
sp_Outdoor.DataReceived += new SerialDataReceivedEventHandler(Sp_Outdoor_DataReceived);
|
2026-01-22 16:06:24 +08:00
|
|
|
|
sp_bendiPort.DataReceived += new SerialDataReceivedEventHandler(Sp_Bendi_DataReceived);
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
// 设置读取超时
|
|
|
|
|
|
sp_Indoor.ReadTimeout = 1000;
|
|
|
|
|
|
sp_Outdoor.ReadTimeout = 1000;
|
|
|
|
|
|
sp_bendiPort.ReadTimeout = 1000;
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
MessageBox.Show($"初始化串口失败: {ex.Message}");
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 发送命令帧
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="port">串口对象</param>
|
|
|
|
|
|
/// <param name="command">命令字节</param>
|
|
|
|
|
|
/// <param name="data">数据域(可选)</param>
|
|
|
|
|
|
private void SendCommand(SerialPort port, PC_CMD command, byte[] data = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (port == null || !port.IsOpen)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
List<byte> frame = new List<byte>();
|
|
|
|
|
|
|
|
|
|
|
|
// 帧头
|
|
|
|
|
|
frame.Add(FRAME_HEADER);
|
|
|
|
|
|
|
|
|
|
|
|
// 数据域长度
|
|
|
|
|
|
byte dataLength = (byte)((data != null) ? data.Length : 0);
|
|
|
|
|
|
frame.Add(dataLength);
|
|
|
|
|
|
|
|
|
|
|
|
// 命令字节(数据域的第一个字节)
|
|
|
|
|
|
frame.Add((byte)command);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有额外的数据,添加到数据域
|
|
|
|
|
|
if (data != null && data.Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
frame.AddRange(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算校验和(对数据域的所有字节累加求和,取低8位)
|
|
|
|
|
|
byte checksum = 0;
|
|
|
|
|
|
for (int i = 2; i < frame.Count; i++) // 从命令字节开始计算
|
|
|
|
|
|
{
|
|
|
|
|
|
checksum += frame[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
frame.Add(checksum);
|
|
|
|
|
|
|
|
|
|
|
|
// 帧尾
|
|
|
|
|
|
frame.Add(FRAME_TAIL);
|
|
|
|
|
|
|
|
|
|
|
|
// 发送帧
|
|
|
|
|
|
port.Write(frame.ToArray(), 0, frame.Count);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"发送命令失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 解析接收到的数据帧
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void ParseFrame(List<byte> buffer, ref float dataStore, string portName)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 查找帧头
|
|
|
|
|
|
int headerIndex = buffer.IndexOf(FRAME_HEADER);
|
|
|
|
|
|
if (headerIndex < 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// 移除帧头之前的数据
|
|
|
|
|
|
if (headerIndex > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
buffer.RemoveRange(0, headerIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有足够的数据读取长度字段
|
|
|
|
|
|
if (buffer.Count < 2)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
byte dataLength = buffer[1];
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否收到完整帧(帧头1 + 长度1 + 数据域 + 校验和1 + 帧尾1)
|
|
|
|
|
|
int frameLength = 2 + dataLength + 2;
|
|
|
|
|
|
if (buffer.Count < frameLength)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// 验证帧尾
|
|
|
|
|
|
if (buffer[frameLength - 1] != FRAME_TAIL)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 帧尾错误,移除帧头继续查找
|
|
|
|
|
|
buffer.RemoveAt(0);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 提取完整帧
|
|
|
|
|
|
byte[] frame = buffer.GetRange(0, frameLength).ToArray();
|
|
|
|
|
|
|
|
|
|
|
|
// 验证校验和
|
|
|
|
|
|
byte checksum = 0;
|
|
|
|
|
|
for (int i = 2; i < 2 + dataLength; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
checksum += frame[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (checksum != frame[frameLength - 2])
|
|
|
|
|
|
{
|
|
|
|
|
|
// 校验和错误
|
|
|
|
|
|
buffer.RemoveRange(0, frameLength);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析响应
|
|
|
|
|
|
if (frame[2] == (byte)PC_CMD.PC_CMD_RESPOND) // 响应命令
|
|
|
|
|
|
{
|
|
|
|
|
|
byte to_cmd = frame[3];
|
|
|
|
|
|
byte result = frame[4];
|
|
|
|
|
|
byte dat_len = frame[5];
|
|
|
|
|
|
|
|
|
|
|
|
if (result == (byte)RESPOND_RESULT.RESPOND_RESULT_SUCCESS)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (to_cmd == (byte)PC_CMD.PC_CMD_GET_DATA && dat_len >= 2 + 5 * 2) // 至少包含header + 5个元素的能量值
|
|
|
|
|
|
{
|
|
|
|
|
|
// 解析PC_DATA结构
|
|
|
|
|
|
PC_DATA pcData = new PC_DATA();
|
|
|
|
|
|
pcData.real_param_sta = frame[6];
|
|
|
|
|
|
pcData.disp_param_sta = frame[7];
|
|
|
|
|
|
pcData.unit = frame[8];
|
|
|
|
|
|
pcData.is_fire = frame[9];
|
|
|
|
|
|
|
|
|
|
|
|
// 读取5个元素的能量值(每个2字节)
|
|
|
|
|
|
pcData.energys = new ushort[5];
|
|
|
|
|
|
int offset = 10;
|
|
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
pcData.energys[i] = (ushort)(frame[offset] + (frame[offset + 1] << 8));
|
|
|
|
|
|
offset += 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 这里我们取第一个元素(PARAM_NA)的能量值作为浓度值
|
|
|
|
|
|
// 根据实际需求,可以选择不同的元素
|
|
|
|
|
|
float energyValue = pcData.energys[(int)ELEMENT_INDEX.PARAM_NA];
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为浓度值(这里需要根据实际校准曲线转换,暂时直接使用能量值)
|
|
|
|
|
|
// 实际应用中需要调用校准曲线进行转换
|
|
|
|
|
|
dataStore = energyValue;
|
|
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"{portName} 收到数据: 能量值={energyValue}, 浓度={dataStore:F2}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除已处理的帧
|
|
|
|
|
|
buffer.RemoveRange(0, frameLength);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"解析数据帧失败: {ex.Message}");
|
|
|
|
|
|
if (buffer.Count > 0)
|
|
|
|
|
|
buffer.RemoveAt(0); // 移除错误数据
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 室内数据接收处理
|
2026-01-16 20:53:33 +08:00
|
|
|
|
private void Sp_Indoor_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sp_Indoor == null || !sp_Indoor.IsOpen)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
int bytesToRead = sp_Indoor.BytesToRead;
|
|
|
|
|
|
if (bytesToRead <= 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
byte[] buffer = new byte[bytesToRead];
|
|
|
|
|
|
sp_Indoor.Read(buffer, 0, bytesToRead);
|
|
|
|
|
|
|
|
|
|
|
|
indoorBuffer.AddRange(buffer);
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试解析帧
|
|
|
|
|
|
ParseFrame(indoorBuffer, ref _indoor_data, "室内光度计");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"室内数据接收异常: {ex.Message}");
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 室外数据接收处理
|
2026-01-16 20:53:33 +08:00
|
|
|
|
private void Sp_Outdoor_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sp_Outdoor == null || !sp_Outdoor.IsOpen)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
int bytesToRead = sp_Outdoor.BytesToRead;
|
|
|
|
|
|
if (bytesToRead <= 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
byte[] buffer = new byte[bytesToRead];
|
|
|
|
|
|
sp_Outdoor.Read(buffer, 0, bytesToRead);
|
|
|
|
|
|
|
|
|
|
|
|
outdoorBuffer.AddRange(buffer);
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试解析帧
|
|
|
|
|
|
ParseFrame(outdoorBuffer, ref _outdoor_data, "室外光度计");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"室外数据接收异常: {ex.Message}");
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 本底数据接收处理
|
|
|
|
|
|
private void Sp_Bendi_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
2026-01-16 20:53:33 +08:00
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sp_bendiPort == null || !sp_bendiPort.IsOpen)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
int bytesToRead = sp_bendiPort.BytesToRead;
|
|
|
|
|
|
if (bytesToRead <= 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
byte[] buffer = new byte[bytesToRead];
|
|
|
|
|
|
sp_bendiPort.Read(buffer, 0, bytesToRead);
|
|
|
|
|
|
|
|
|
|
|
|
bendiBuffer.AddRange(buffer);
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试解析帧
|
|
|
|
|
|
ParseFrame(bendiBuffer, ref _bendi_data, "本底光度计");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"本底数据接收异常: {ex.Message}");
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 启动数据采集
|
|
|
|
|
|
/// </summary>
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Start_Indoor()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_Indoor != null && sp_Indoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 发送连接命令
|
|
|
|
|
|
SendCommand(sp_Indoor, PC_CMD.PC_CMD_CONNECT);
|
|
|
|
|
|
Thread.Sleep(100); // 等待响应
|
|
|
|
|
|
|
|
|
|
|
|
// 开始定时获取数据
|
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
while (sp_Indoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
SendCommand(sp_Indoor, PC_CMD.PC_CMD_GET_DATA);
|
|
|
|
|
|
Thread.Sleep(500); // 每500ms获取一次数据
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Start_Outdoor()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_Outdoor != null && sp_Outdoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 发送连接命令
|
|
|
|
|
|
SendCommand(sp_Outdoor, PC_CMD.PC_CMD_CONNECT);
|
|
|
|
|
|
Thread.Sleep(100); // 等待响应
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
// 开始定时获取数据
|
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
while (sp_Outdoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
SendCommand(sp_Outdoor, PC_CMD.PC_CMD_GET_DATA);
|
|
|
|
|
|
Thread.Sleep(500); // 每500ms获取一次数据
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
|
|
|
|
|
public void Start_bendidoor()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_bendiPort != null && sp_bendiPort.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 发送连接命令
|
|
|
|
|
|
SendCommand(sp_bendiPort, PC_CMD.PC_CMD_CONNECT);
|
|
|
|
|
|
Thread.Sleep(100); // 等待响应
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
// 开始定时获取数据
|
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
while (sp_bendiPort.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
SendCommand(sp_bendiPort, PC_CMD.PC_CMD_GET_DATA);
|
|
|
|
|
|
Thread.Sleep(500); // 每500ms获取一次数据
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 停止数据采集
|
|
|
|
|
|
/// </summary>
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Stop_Indoor()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_Indoor != null && sp_Indoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
SendCommand(sp_Indoor, PC_CMD.PC_CMD_DISCONNECT);
|
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Stop_Outdoor()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_Outdoor != null && sp_Outdoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
SendCommand(sp_Outdoor, PC_CMD.PC_CMD_DISCONNECT);
|
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Stop_bendidoor()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_bendiPort != null && sp_bendiPort.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
SendCommand(sp_bendiPort, PC_CMD.PC_CMD_DISCONNECT);
|
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 连接串口
|
|
|
|
|
|
/// </summary>
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Connect()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sp_Indoor != null && !sp_Indoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
sp_Indoor.Open();
|
|
|
|
|
|
Console.WriteLine("室内光度计串口已打开");
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_Outdoor != null && !sp_Outdoor.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
sp_Outdoor.Open();
|
|
|
|
|
|
Console.WriteLine("室外光度计串口已打开");
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
|
2026-01-22 16:06:24 +08:00
|
|
|
|
if (sp_bendiPort != null && !sp_bendiPort.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
sp_bendiPort.Open();
|
|
|
|
|
|
Console.WriteLine("本底光度计串口已打开");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"打开串口失败: {ex.Message}");
|
|
|
|
|
|
}
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 断开串口连接
|
|
|
|
|
|
/// </summary>
|
2026-01-16 20:53:33 +08:00
|
|
|
|
public void Disconnect()
|
|
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
try
|
2026-01-16 20:53:33 +08:00
|
|
|
|
{
|
2026-01-22 16:06:24 +08:00
|
|
|
|
Stop_Indoor();
|
|
|
|
|
|
Stop_Outdoor();
|
|
|
|
|
|
Stop_bendidoor();
|
|
|
|
|
|
|
|
|
|
|
|
if (sp_Indoor != null && sp_Indoor.IsOpen)
|
2026-01-16 20:53:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
sp_Indoor.Close();
|
|
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
if (sp_Outdoor != null && sp_Outdoor.IsOpen)
|
2026-01-16 20:53:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
sp_Outdoor.Close();
|
|
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
|
|
|
|
|
|
if (sp_bendiPort != null && sp_bendiPort.IsOpen)
|
|
|
|
|
|
{
|
|
|
|
|
|
sp_bendiPort.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("所有串口已关闭");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"关闭串口失败: {ex.Message}");
|
2026-01-16 20:53:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-22 16:06:24 +08:00
|
|
|
|
}
|