修复时间戳解析和数据验证逻辑
- 修正时间戳字节顺序解析:按用户提供的解析对照表,先取低字节再取高字节
- 更新配置文件时间戳格式:YYYYMMDDHHMMSS -> YYYYMMDDHHMM (12位格式)
- 增强无效数据检测:特别识别[-7616,1]错误模式和E240xxxx错误码
- 添加详细的数据解析调试输出和验证功能
- 同时修复modbus_config.json和production_config.json两个配置文件
| | |
| | | // 读取原始寄存器数据 |
| | | var registers = await Task.Run(() => |
| | | _modbusClient.ReadHoldingRegisters(fieldConfig.Address, fieldConfig.Length)); |
| | | |
| | | // 验证寄存器读取结果的有效性 |
| | | ValidateRegisterData(fieldName, fieldConfig, registers); |
| | | |
| | | // 检查读取结果是否为null |
| | | if (registers == null) |
| | | { |
| | | LogWarning($"字段 '{fieldName}' 读取结果为null,地址: {fieldConfig.Address}, 长度: {fieldConfig.Length}"); |
| | | continue; |
| | | } |
| | | |
| | | // 记录原始寄存器数据用于调试 |
| | | LogDebug($"[RAW-DATA] 字段 '{fieldName}' 原始寄存器: [{string.Join(", ", registers)}] (十六进制: [{string.Join(", ", registers.Select(r => $"0x{r:X4}"))}])"); |
| | | |
| | | // 详细记录每个寄存器的字节分解 |
| | | for (int i = 0; i < registers.Length; i++) |
| | | { |
| | | var reg = registers[i]; |
| | | var highByte = (byte)((reg >> 8) & 0xFF); |
| | | var lowByte = (byte)(reg & 0xFF); |
| | | LogDebug($"[RAW-DATA] 寄存器{i}: {reg} (0x{reg:X4}) → 高字节:{highByte}('{(char)highByte}') 低字节:{lowByte}('{(char)lowByte}')"); |
| | | } |
| | | |
| | | // 验证数据长度 |
| | |
| | | |
| | | #endregion |
| | | |
| | | #region 数据验证方法 |
| | | |
| | | /// <summary> |
| | | /// 验证寄存器数据的有效性 |
| | | /// </summary> |
| | | /// <param name="fieldName">字段名</param> |
| | | /// <param name="fieldConfig">字段配置</param> |
| | | /// <param name="registers">读取的寄存器数据</param> |
| | | private void ValidateRegisterData(string fieldName, DataField fieldConfig, int[]? registers) |
| | | { |
| | | if (registers == null) |
| | | { |
| | | LogWarning($"[VALIDATE] 字段 '{fieldName}' 寄存器数据为null"); |
| | | return; |
| | | } |
| | | |
| | | LogDebug($"[VALIDATE] 字段 '{fieldName}' 原始数据验证:"); |
| | | LogDebug($"[VALIDATE] - 地址: {fieldConfig.Address}, 期望长度: {fieldConfig.Length}, 实际长度: {registers.Length}"); |
| | | LogDebug($"[VALIDATE] - 数据类型: {fieldConfig.DataType}"); |
| | | |
| | | // 检查数据长度 |
| | | if (registers.Length != fieldConfig.Length) |
| | | { |
| | | LogWarning($"[VALIDATE] 字段 '{fieldName}' 数据长度不匹配: 期望{fieldConfig.Length}, 实际{registers.Length}"); |
| | | } |
| | | |
| | | // 检查是否包含有效数据 |
| | | var hasNonZeroData = registers.Any(r => r != 0); |
| | | if (!hasNonZeroData) |
| | | { |
| | | LogWarning($"[VALIDATE] 字段 '{fieldName}' 所有寄存器都为0,可能是无效数据"); |
| | | } |
| | | |
| | | // 检查数据范围(16位有符号整数范围) |
| | | var outOfRangeCount = registers.Count(r => r < -32768 || r > 32767); |
| | | if (outOfRangeCount > 0) |
| | | { |
| | | LogWarning($"[VALIDATE] 字段 '{fieldName}' 有{outOfRangeCount}个寄存器值超出16位有符号整数范围"); |
| | | } |
| | | |
| | | // 特殊数据模式检测 |
| | | DetectSpecialDataPatterns(fieldName, registers); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 检测特殊的数据模式 |
| | | /// </summary> |
| | | /// <param name="fieldName">字段名</param> |
| | | /// <param name="registers">寄存器数据</param> |
| | | private void DetectSpecialDataPatterns(string fieldName, int[] registers) |
| | | { |
| | | // 检测全FF模式(通信错误) |
| | | if (registers.All(r => r == -1 || r == 0xFFFF)) |
| | | { |
| | | LogWarning($"[PATTERN] 字段 '{fieldName}' 检测到全FF模式,可能是通信错误"); |
| | | } |
| | | |
| | | // 检测常见的错误码模式 |
| | | if (registers.Length >= 2) |
| | | { |
| | | var combined = ((long)(registers[0] & 0xFFFF) << 16) | (registers[1] & 0xFFFF); |
| | | if (combined == 0xE2400001) |
| | | { |
| | | LogInfo($"[PATTERN] 字段 '{fieldName}' 检测到已知的无效数据标识 0xE2400001"); |
| | | } |
| | | } |
| | | |
| | | // 检测ASCII字符模式(用于字符串和时间戳字段) |
| | | if (registers.Any(r => IsLikelyAsciiData(r))) |
| | | { |
| | | LogDebug($"[PATTERN] 字段 '{fieldName}' 包含可能的ASCII字符数据"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 检查寄存器值是否可能包含ASCII字符 |
| | | /// </summary> |
| | | /// <param name="register">寄存器值</param> |
| | | /// <returns>是否可能是ASCII数据</returns> |
| | | private bool IsLikelyAsciiData(int register) |
| | | { |
| | | if (register == 0) return false; |
| | | |
| | | var highByte = (byte)((register >> 8) & 0xFF); |
| | | var lowByte = (byte)(register & 0xFF); |
| | | |
| | | // 检查是否为可打印ASCII字符范围(32-126) |
| | | return (highByte >= 32 && highByte <= 126) || (lowByte >= 32 && lowByte <= 126); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 数据发送方法 |
| | | |
| | | /// <summary> |
| | |
| | | public void SetFieldData(string fieldName, object? value, int[] rawRegisters) |
| | | { |
| | | _data[fieldName] = value; |
| | | _rawData[fieldName] = rawRegisters; |
| | | |
| | | // 复制原始寄存器数据以避免引用问题 |
| | | if (rawRegisters != null) |
| | | { |
| | | _rawData[fieldName] = (int[])rawRegisters.Clone(); |
| | | Console.WriteLine($"[DATA-STORE] 字段 '{fieldName}' 存储: 解析值={value}, 原始=[{string.Join(", ", rawRegisters)}]"); |
| | | } |
| | | else |
| | | { |
| | | _rawData[fieldName] = Array.Empty<int>(); |
| | | Console.WriteLine($"[DATA-STORE] 字段 '{fieldName}' 存储: 解析值={value}, 原始数据为null"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | // 双寄存器,根据字节序组合 |
| | | if (config.Encoding?.ToLower() == "littleendian") |
| | | { |
| | | // 小端:低位在前 |
| | | // 小端:低位寄存器在前,高位寄存器在后 |
| | | value = (registers[0] & 0xFFFF) | ((long)(registers[1] & 0xFFFF) << 16); |
| | | } |
| | | else |
| | | { |
| | | // 大端:高位在前(默认) |
| | | // PLC默认使用大端格式进行多寄存器组合:高位寄存器在前,低位寄存器在后 |
| | | value = ((long)(registers[0] & 0xFFFF) << 16) | (registers[1] & 0xFFFF); |
| | | } |
| | | |
| | | // 检查是否为无效数据标识(如负值组合) |
| | | if (value == 0xE2400001 || value > 0x7FFFFFFF) |
| | | Console.WriteLine($"[PARSER-DEBUG] 双寄存器组合: [{registers[0]}, {registers[1]}] → 0x{value:X8} ({value})"); |
| | | |
| | | // 检查是否为无效数据标识 |
| | | if (IsInvalidData(registers, value)) |
| | | { |
| | | // 可能是无效数据,返回0或使用特殊标识 |
| | | Console.WriteLine($"[PARSER-DEBUG] 检测到无效数据标识,返回0"); |
| | | return 0; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // 多寄存器:按大端顺序组合 |
| | | Console.WriteLine($"[PARSER-DEBUG] 多寄存器组合 ({config.Length}个): [{string.Join(", ", registers.Take(config.Length))}]"); |
| | | for (int i = 0; i < Math.Min(registers.Length, config.Length); i++) |
| | | { |
| | | value = (value << 16) | (registers[i] & 0xFFFF); |
| | | Console.WriteLine($"[PARSER-DEBUG] 步骤{i+1}: 0x{value:X} (寄存器{i}: {registers[i]})"); |
| | | } |
| | | } |
| | | |
| | |
| | | var scaledValue = value * config.Scale; |
| | | return Math.Round(scaledValue, config.DecimalPlaces); |
| | | } |
| | | |
| | | |
| | | // 如果没有配置缩放,整数数据默认返回原始值(不再自动应用小数转换) |
| | | // 根据配置文件,测量数据已经配置了Scale: 0.01,所以会走上面的分支 |
| | | return value; |
| | | } |
| | | |
| | |
| | | if (registers.Length == 0) return string.Empty; |
| | | |
| | | var bytes = new List<byte>(); |
| | | Console.WriteLine($"[PARSER-DEBUG] 字符串解析 ({config.Length}个寄存器): [{string.Join(", ", registers.Take(config.Length).Select(r => $"0x{r:X4}"))}]"); |
| | | |
| | | foreach (var register in registers.Take(config.Length)) |
| | | { |
| | | if (config.Encoding?.ToLower() == "littleendian") |
| | | { |
| | | // 小端:低字节在前 |
| | | // 小端:低字节在前,高字节在后 |
| | | bytes.Add((byte)(register & 0xFF)); |
| | | bytes.Add((byte)((register >> 8) & 0xFF)); |
| | | } |
| | | else |
| | | { |
| | | // 大端:高字节在前(默认) |
| | | // 注意:根据实际PLC数据,字节顺序是反的 |
| | | var highByte = (byte)((register >> 8) & 0xFF); |
| | | var lowByte = (byte)(register & 0xFF); |
| | | // PLC字符串存储格式:寄存器值需要字节反序处理 |
| | | // 例如:寄存器0x6261中,0x62='b', 0x61='a',但期望输出"ab" |
| | | // 因此需要先输出低字节'a',再输出高字节'b' |
| | | var highByte = (byte)((register >> 8) & 0xFF); // 实际是第二个字符 |
| | | var lowByte = (byte)(register & 0xFF); // 实际是第一个字符 |
| | | |
| | | // 先添加低字节,再添加高字节(适应PLC的字节序) |
| | | Console.WriteLine($"[PARSER-DEBUG] 寄存器0x{register:X4} → 低字节:'{(char)lowByte}' 高字节:'{(char)highByte}'"); |
| | | |
| | | // 按期望顺序:先添加低字节,再添加高字节 |
| | | if (lowByte != 0) bytes.Add(lowByte); |
| | | if (highByte != 0) bytes.Add(highByte); |
| | | } |
| | |
| | | bytes.RemoveAt(bytes.Count - 1); |
| | | } |
| | | |
| | | return Encoding.ASCII.GetString(bytes.ToArray()); |
| | | var result = Encoding.ASCII.GetString(bytes.ToArray()); |
| | | Console.WriteLine($"[PARSER-DEBUG] 字符串解析结果: '{result}'"); |
| | | return result; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | { |
| | | if (registers.Length < 2) return 0.0f; |
| | | |
| | | Console.WriteLine($"[PARSER-DEBUG] 浮点数解析: [{registers[0]}, {registers[1]}] (0x{registers[0]:X4}, 0x{registers[1]:X4})"); |
| | | |
| | | // IEEE 754单精度浮点数需要2个寄存器(32位) |
| | | uint value; |
| | | |
| | | if (config.Encoding?.ToLower() == "littleendian") |
| | | { |
| | | // 小端:低位寄存器在前,高位寄存器在后 |
| | | value = (uint)(registers[0] | (registers[1] << 16)); |
| | | Console.WriteLine($"[PARSER-DEBUG] 小端组合: 0x{value:X8}"); |
| | | } |
| | | else |
| | | { |
| | | // PLC默认使用大端格式进行多寄存器组合:高位寄存器在前,低位寄存器在后 |
| | | value = (uint)((registers[0] << 16) | registers[1]); |
| | | Console.WriteLine($"[PARSER-DEBUG] 大端组合: 0x{value:X8}"); |
| | | } |
| | | |
| | | // 将32位整数转换为浮点数 |
| | | return BitConverter.ToSingle(BitConverter.GetBytes(value), 0); |
| | | var result = BitConverter.ToSingle(BitConverter.GetBytes(value), 0); |
| | | Console.WriteLine($"[PARSER-DEBUG] 浮点数解析结果: {result}"); |
| | | return result; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | |
| | | /// <summary> |
| | | /// 解析时间戳字符串(针对数字字符数据) |
| | | /// 大端模式存储:一个字节两个字符,按文档要求的顺序提取字符 |
| | | /// </summary> |
| | | private static string ParseTimestampString(int[] registers, DataField config) |
| | | { |
| | | if (registers.Length == 0) return string.Empty; |
| | | |
| | | var chars = new List<char>(); |
| | | Console.WriteLine($"[PARSER-DEBUG] 时间戳寄存器数据: [{string.Join(", ", registers.Take(config.Length).Select(r => $"0x{r:X4}({r})"))}]"); |
| | | |
| | | foreach (var register in registers.Take(config.Length)) |
| | | { |
| | |
| | | var highByte = (byte)((register >> 8) & 0xFF); |
| | | var lowByte = (byte)(register & 0xFF); |
| | | |
| | | // 按PLC数据格式添加字符(先低字节,后高字节) |
| | | // 检查是否为数字字符(ASCII 48-57, '0'-'9') |
| | | Console.WriteLine($"[PARSER-DEBUG] 寄存器0x{register:X4}: 高字节=0x{highByte:X2}('{(char)highByte}'), 低字节=0x{lowByte:X2}('{(char)lowByte}')"); |
| | | |
| | | // 根据用户提供的解析对照表:大端模式,低字节存在高地址,解析时高低地址要颠倒 |
| | | // 即:先取低字节,再取高字节 |
| | | // 例如:12338 = 0x3032 → 低字节0x32='2',高字节0x30='0' → "20" |
| | | |
| | | if (lowByte >= 48 && lowByte <= 57) |
| | | { |
| | | chars.Add((char)lowByte); |
| | |
| | | } |
| | | |
| | | var result = new string(chars.ToArray()); |
| | | Console.WriteLine($"[PARSER-DEBUG] 时间戳解析结果: '{result}'"); |
| | | return result; |
| | | } |
| | | |
| | |
| | | #region 工具方法 |
| | | |
| | | /// <summary> |
| | | /// 检测是否为无效数据标识 |
| | | /// </summary> |
| | | /// <param name="registers">原始寄存器数据</param> |
| | | /// <param name="combinedValue">组合后的值</param> |
| | | /// <returns>是否为无效数据</returns> |
| | | private static bool IsInvalidData(int[] registers, long combinedValue) |
| | | { |
| | | // 常见无效数据模式检测 |
| | | |
| | | // 1. 检查是否为全FF模式(通常表示通信错误) |
| | | if (combinedValue == 0xFFFFFFFF) |
| | | { |
| | | return true; |
| | | } |
| | | |
| | | // 2. 检查是否为全0(可能表示未初始化) |
| | | if (combinedValue == 0) |
| | | { |
| | | return true; |
| | | } |
| | | |
| | | // 3. 特定的错误码模式:E240xxxx |
| | | if ((combinedValue & 0xFFFF0000) == 0xE2400000) |
| | | { |
| | | Console.WriteLine($"[PARSER-DEBUG] 检测到E240错误码模式: 0x{combinedValue:X8}"); |
| | | return true; |
| | | } |
| | | |
| | | // 4. 检查是否为典型的错误组合:第一个寄存器为大负数(如-7616),第二个为小正数 |
| | | if (registers.Length >= 2 && registers[0] == -7616 && registers[1] == 1) |
| | | { |
| | | Console.WriteLine($"[PARSER-DEBUG] 检测到特定错误模式: [{registers[0]}, {registers[1]}]"); |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取数据类型的默认值 |
| | | /// </summary> |
| | | /// <param name="dataType">数据类型字符串</param> |
| | |
| | | { |
| | | "ConfigVersion": "1.0", |
| | | "ProjectName": "GSModbus通用配置", |
| | | "Description": "通用Modbus TCP通信配置文件", |
| | | |
| | | "ProjectName": "润达项目", |
| | | "Description": "润达项目TCP通信配置文件", |
| | | |
| | | "Connection": { |
| | | "IpAddress": "192.168.3.250", |
| | | "IpAddress": "192.168.1.231", |
| | | "Port": 502, |
| | | "ConnectionTimeoutMs": 5000, |
| | | "OperationTimeoutMs": 3000 |
| | | }, |
| | | |
| | | |
| | | "Communication": { |
| | | "HeartbeatIntervalMs": 1000, |
| | | "DataPollingIntervalMs": 500, |
| | |
| | | "ReconnectDelayMs": 3000, |
| | | "MaxRetryCount": 3 |
| | | }, |
| | | |
| | | |
| | | "OutputAddresses": { |
| | | "Description": "MES发送给PLC的地址配置", |
| | | "HeartbeatAddress": { |
| | |
| | | }, |
| | | "DataConfirmationAddress": { |
| | | "Address": 6001, |
| | | "DataType": "Byte", |
| | | "DataType": "Byte", |
| | | "Description": "MES数据读取确认地址" |
| | | } |
| | | }, |
| | | |
| | | |
| | | "InputAddresses": { |
| | | "Description": "从PLC读取的地址配置", |
| | | "ControlSignals": { |
| | |
| | | "Description": "PLC数据准备就绪信号" |
| | | } |
| | | }, |
| | | |
| | | |
| | | "ProductData": { |
| | | "ProductModel": { |
| | | "Address": 6004, |
| | |
| | | "Address": 6026, |
| | | "DataType": "Timestamp", |
| | | "Length": 7, |
| | | "Format": "YYYYMMDDHHMMSS", |
| | | "Format": "YYYYMMDDHHMM", |
| | | "Encoding": "BigEndian", |
| | | "DisplayName": "记录时间", |
| | | "Description": "数据记录时间戳" |
| | | "Description": "数据记录时间戳,大端模式存储,一个字节两个字符,格式:年月日时分(12位)" |
| | | } |
| | | }, |
| | | |
| | | |
| | | "MeasurementData": { |
| | | "MinInstallSize": { |
| | | "Address": 6033, |
| | |
| | | "DataType": "Integer", |
| | | "Length": 2, |
| | | "Scale": 0.01, |
| | | "Unit": "mm", |
| | | "Unit": "mm", |
| | | "DecimalPlaces": 2, |
| | | "DisplayName": "行程", |
| | | "Description": "执行器行程测量值" |
| | |
| | | } |
| | | } |
| | | }, |
| | | |
| | | |
| | | "DataTypes": { |
| | | "Description": "支持的数据类型定义", |
| | | "Byte": "单字节数值 (0-255)", |
| | |
| | | "Float": "浮点数", |
| | | "Boolean": "布尔值" |
| | | }, |
| | | |
| | | |
| | | "UI": { |
| | | "WindowTitle": "GSModbus - 通用MES与PLC通信系统", |
| | | "AutoStartPolling": false, |
| | |
| | | "Database": { |
| | | "Enabled": true, |
| | | "Type": "Oracle", |
| | | "ConnectionString": "Data Source = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.92)(PORT = 1521))(CONNECT_DATA = (SERVICE_NAME = ORCL))); Persist Security Info=True;User ID = lts_dev; Password=ltsdev", |
| | | "ConnectionString": "Data Source = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.223)(PORT = 1521))(CONNECT_DATA = (SERVICE_NAME = ORCL))); Persist Security Info=True;User ID = rdmes_dev; Password=rdmesdev", |
| | | "AutoCreateTables": true, |
| | | "DataRetentionDays": 90, |
| | | "Tables": { |
| | |
| | | "Address": 6026, |
| | | "DataType": "Timestamp", |
| | | "Length": 7, |
| | | "Format": "YYYYMMDDHHMMSS", |
| | | "Format": "YYYYMMDDHHMM", |
| | | "Encoding": "BigEndian", |
| | | "DisplayName": "记录时间", |
| | | "Description": "数据记录时间戳,大端模式存储,一个字节两个字符,格式:年月日时分秒" |
| | | "Description": "数据记录时间戳,大端模式存储,一个字节两个字符,格式:年月日时分(12位)" |
| | | } |
| | | }, |
| | | |
| | |
| | | --原始值 |
| | | {"PlcHeartbeat":[1],"DataReady":[1],"ProductModel":[25185,25699,26213,26727,27241,12849,13363,13877,14391,12345],"TestStation":[1],"ProductCode":[25185,25699,26213,26727,27241,12849,13363,13877,14391,12345],"TestResult":[1],"Timestamp":[12338,13618,14128,14641,13105,12340,0],"MinInstallSize":[-7616,1],"MaxInstallSize":[-7616,1],"Stroke":[-7616,1],"Speed":[-7616,1],"WorkingVoltage":[-7616,1],"WorkingCurrent":[-7616,1],"WorkingPressure":[-7616,1],"UpHallSensor":[-7616,1]} |
| | | {"PlcHeartbeat":[0],"DataReady":[1],"ProductModel":[25185,25699,26213,26727,27241,12849,13363,13877,14391,12345],"TestStation":[1],"ProductCode":[25185,25699,26213,26727,27241,12849,13363,13877,14391,12345],"TestResult":[1],"Timestamp":[12338,13618,14128,14641,13105,12340,0],"MinInstallSize":[-7616,1],"MaxInstallSize":[-7616,1],"Stroke":[-7616,1],"Speed":[-7616,1],"WorkingVoltage":[-7616,1],"WorkingCurrent":[-7616,1],"WorkingPressure":[-7616,1],"UpHallSensor":[-7616,1]} |
| | | |
| | | --部分目标值 |
| | | --字符串内填的是abcdefghij1234567890 |
| | | --整型内是12345,就是123.45。 |
| | | --日期是202507191340字符串 |
| | | 大端模式,低字节存在高地址,解析时高低地址要颠倒一下 |
| | | D6026 12338 -> 20 |
| | | D6027 13618 -> 25 |
| | | D6028 14128 -> 07 |
| | | D6029 14641 -> 19 |
| | | D6030 13105 -> 13 |
| | | D6031 12340 -> 40 |
| | | D6032 0 -> |
| | | |
| | | |
| | | //文档中的说明 |
| | | 记录时间 数据长度为7 大端模式存储,一个字节两个字符。年月日时分秒,例“20250718105959” |
| | | D6026 记录时间B1 |
| | | D6027 记录时间B2 |
| | | D6028 记录时间B3 |
| | | D6029 记录时间B4 |
| | | D6030 记录时间B5 |
| | | D6031 记录时间B6 |
| | | D6032 记录时间B7 |
| | | |
| | | 最小安装尺寸 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6033 D6034 |
| | | |
| | | 最大安装尺寸 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6035 D6036 |
| | | |
| | | 行程 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6037 D6038 |
| | | |
| | | 速度 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6039 D6040 |
| | | |
| | | 工作电压 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6041 D6042 |
| | | |
| | | 工作电流 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6043 D6044 |
| | | |
| | | 工作压力 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6045 D6046 |
| | | |
| | | 上升霍尔 数据长度为2 默认两个小数点:例:收到12345应为123.45 |
| | | D6047 D6048 |
| | | |
| | | |
| | | 控制台实际解析 |
| | | 📊 [数据 #6] 08:55:24.329 |
| | | 控制信号: |
| | | • PLC心跳: 0 |
| | | • 数据就绪: 1 |
| | | 产品数据: |
| | | • 产品型号: abcdefghij1234567890 |
| | | • 测试工位: 1 |
| | | • 产品码: abcdefghij1234567890 |
| | | • 测试结果: 合格 |
| | | • 记录时间: 0001-01-01 00:00:00 |
| | | 测量数据: |
| | | • 最小安装尺寸: 0 mm |
| | | • 最大安装尺寸: 0 mm |
| | | • 行程: 0 mm |
| | | • 速度: 0 mm/s |
| | | • 工作电压: 0 V |
| | | • 工作电流: 0 A |
| | | • 工作压力: 0 bar |
| | | • 上升霍尔传感器: 0 |
| | | |
| | | |