Unity 串口通讯2 硬件SDK 开发[数据监听,按键监听]

发布于:2025-09-02 ⋅ 阅读:(14) ⋅ 点赞:(0)

关于如何进行串口通讯,可以查阅另一篇博客 Unity 串口通讯,本文介绍的是如何处理传的数据,这里提供一个十六进制数据的案例,供大家去学习。
数据案例 AA015500AA021407EEFF
数据说明

下标 完整数值 含义 规则
0 0xAA 固定数据头 1 固定为 0xAA(帧起始标识,区分数据帧与干扰信号)
1 0x01 帧序号 从 0x01 开始自增
2 0x55 固定数据头 2 固定为 0x55(二次校验标识,与数据头 1 配合确认帧合法性)
3 0x01 温度数据高位 高位
4 0xAA 温度数据低位 低位
5 0x02 湿度数据高位 高位
6 0x14 湿度数据低位 低位
7 0x07 按键值 按键1为1,按键2为2,按键3为4等,按位标识按键
8 0xEE 结束标识(高位) 固定为 0xEE(帧结束高位,与低位配合确认帧完整性)
9 0xFF 结束标识(低位) 固定为 0xFF(帧结束低位)

先完成准备工作,串口通信中常用的 “高低位字节组合”,传2个8位16进制值,高位字节和低位字节,组合成一个16进制的数值,高位 0x01,低位0xAA
合并原理
‌高位字节左移8位‌:将 0x01 左移8位,得到 0x0100(即二进制 00000001 00000000)。
‌与低位字节相加‌:将移位后的结果与 0xAA 相加(或按位或 |),得到 0x01AA(二进制 00000001 10101010)。
‌转换为十进制‌:0x01AA = 1 × 256 + 10 × 16 + 10 × 1 = ‌426‌。
以此,用C#来实现

    /// <summary>
    /// 将高位和低位十六进制值组合成16位有符号整数
    /// </summary>
    public static float CombineHighLowBytes(string highByteHex, string lowByteHex)
    {
        byte highByte = Convert.ToByte(highByteHex, 16);
        byte lowByte = Convert.ToByte(lowByteHex, 16);
        int combinedValue = (highByte << 8) | lowByte;
        return combinedValue;
    }

拓展一下需要的静态方法,比如收到的字节数组转化,字符分割,字符校验

    /// <summary>
    /// 将字节数组转换为十六进制字符串
    /// </summary>
    public static string BytesToHexString(byte[] bytes)
    {
        if (bytes == null) return string.Empty;

        StringBuilder sb = new StringBuilder(bytes.Length * 2);
        foreach (byte b in bytes)
        {
            sb.AppendFormat("{0:X2}", b);
        }
        return sb.ToString();
    }

    /// <summary>
    /// 将字符串分割为两个字符一组的数组
    /// </summary>
    public static string[] SplitIntoTwoCharParts(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            return Array.Empty<string>();
        }

        List<string> parts = new List<string>();
        for (int i = 0; i < input.Length; i += 2)
        {
            int length = (i + 2 <= input.Length) ? 2 : input.Length - i;
            parts.Add(input.Substring(i, length));
        }

        return parts.ToArray();
    }

    /// <summary>
    /// 检查字符串是否是有效的十六进制值
    /// </summary>
    public static bool IsHexString(string str)
    {
        return str.All(c => char.IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));
    }

根据提供的解析规则,处理数据包,解析除了按键之外的数据

    private const string PACKET_HEAD1 = "AA";         // 固定数据头1
    private const string PACKET_HEAD2 = "55";         // 固定数据头2
    private const string PACKET_TAIL_HIGH = "EE";     // 结束标识高位
    private const string PACKET_TAIL_LOW = "FF";      // 结束标识低位
    private const int EXPECTED_PACKET_PARTS = 10;     // 预期10个数据部分
    private void ProcessPacket(string packet)
    {
        string[] parts = DataConversionUtility.SplitIntoTwoCharParts(packet);

        if (parts.Length != EXPECTED_PACKET_PARTS)
        {
            Debug.LogError($"数据位数解析异常,期望{EXPECTED_PACKET_PARTS}个数据,实际{parts.Length}个");
            return;
        }

        try
        {
            // 验证数据头
            if (parts[0] != PACKET_HEAD1 || parts[2] != PACKET_HEAD2)
            {
                Debug.LogError($"数据头验证失败,预期 {PACKET_HEAD1}{PACKET_HEAD2},实际 {parts[0]}{parts[2]}");
                return;
            }

            // 验证数据尾
            if (parts[8] != PACKET_TAIL_HIGH || parts[9] != PACKET_TAIL_LOW)
            {
                Debug.LogError($"数据尾验证失败,预期 {PACKET_TAIL_HIGH}{PACKET_TAIL_LOW},实际 {parts[8]}{parts[9]}");
                return;
            }

            // 验证所有部分都是有效的十六进制
            if (!parts.All(DataConversionUtility.IsHexString))
            {
                Debug.LogError("数据包包含无效的十六进制值");
                return;
            }

            // 解析帧序号 (索引1)
            byte frameSequence = Convert.ToByte(parts[1], 16);
            OnFrameSequenceUpdated?.Invoke(frameSequence);

            // 解析温度数据 (索引3-4)
            float temperature = DataConversionUtility.CombineHighLowBytes(parts[3], parts[4]);

            // 解析湿度数据 (索引5-6)
            float humidity = DataConversionUtility.CombineHighLowBytes(parts[5], parts[6]);

            // 触发相应事件
            OnTemperatureUpdated?.Invoke(temperature);
            OnHumidityUpdated?.Invoke(humidity);

            // 输出日志
            Debug.Log($"帧序号:{frameSequence},温度:{temperature},湿度:{humidity}");
        }
        catch (Exception ex)
        {
            Debug.LogError($"处理数据包时发生错误: {ex.Message}");
        }
    }

按键单独处理,先设定按键的常用状态

public enum KEYButtonState
{
    None,
    OnButtonDown,
    OnButtonUp,
    OnButtonClick
}

需要制定一个按键状态管理类,负责追踪和管理按键的状态变化,需要注意的是按键抖动和超时问题。

/// <summary>
/// 按键状态管理器,负责跟踪和管理按键状态变化
/// </summary>
public class KeyStateManager
{
    // 按键状态存储
    private Dictionary<int, KEYButtonState> _keyStates = new Dictionary<int, KEYButtonState>();
    // 上一次按下的按键记录
    private HashSet<int> _lastPressedKeys = new HashSet<int>();

    // 按键状态变化事件
    public event Action<int, KEYButtonState> OnKeyStateChanged;

    public KeyStateManager()
    {
        // 初始化1-8号按键状态为None
        for (int i = 1; i <= 8; i++)
        {
            _keyStates[i] = KEYButtonState.None;
        }
    }

    /// <summary>
    /// 更新按键状态并触发相应事件
    /// </summary>
    public void UpdateKeyStates(List<int> currentPressedKeys)
    {
        HashSet<int> currentKeys = new HashSet<int>(currentPressedKeys);

        // 检查所有按键的状态变化
        for (int key = 1; key <= 8; key++)
        {
            bool wasPressed = _lastPressedKeys.Contains(key);
            bool isPressed = currentKeys.Contains(key);
            KEYButtonState newState = _keyStates[key];

            // 状态转换逻辑
            if (!wasPressed && isPressed)
            {
                newState = KEYButtonState.OnButtonDown;
            }
            else if (wasPressed && !isPressed)
            {
                newState = KEYButtonState.OnButtonUp;
            }

            // 触发状态变化事件
            if (newState != _keyStates[key])
            {
                _keyStates[key] = newState;
                OnKeyStateChanged?.Invoke(key, newState);

                // 当按键松开时,触发点击事件
                if (newState == KEYButtonState.OnButtonUp)
                {
                    OnKeyStateChanged?.Invoke(key, KEYButtonState.OnButtonClick);
                }
            }
        }

        // 保存当前按键状态用于下次比较
        _lastPressedKeys = new HashSet<int>(currentKeys);

        // 重置瞬间状态
        ResetTransientStates();
    }

    /// <summary>
    /// 重置瞬间状态为None,避免持续触发
    /// </summary>
    private void ResetTransientStates()
    {
        foreach (int key in _keyStates.Keys.ToList())
        {
            if (_keyStates[key] != KEYButtonState.None)
            {
                _keyStates[key] = KEYButtonState.None;
            }
        }
    }

    /// <summary>
    /// 处理超时情况,将所有按键视为松开
    /// </summary>
    public void HandleTimeout()
    {
        if (_lastPressedKeys.Count > 0)
        {
            List<int> emptyKeys = new List<int>();
            UpdateKeyStates(emptyKeys);
        }
    }   
}

根据位运算规则,设定按键掩码和解析

    private const byte KEY_1_MASK = 0b00000001; // 1 按下1
    private const byte KEY_2_MASK = 0b00000010; // 2 按下2
    private const byte KEY_3_MASK = 0b00000100; // 4 按下3
    private const byte KEY_4_MASK = 0b00001000; // 8 按下4
    private const byte KEY_5_MASK = 0b00010000; // 16 按下5
    private const byte KEY_6_MASK = 0b00100000; // 32 以此类推
    private const byte KEY_7_MASK = 0b01000000;
    private const byte KEY_8_MASK = 0b10000000;

    /// <summary>
    /// 解析十六进制值,判断哪些按键被按下
    /// </summary>
    public List<int> ParseKeyPress(byte hexValue)
    {
        List<int> pressedKeys = new List<int>();

        if ((hexValue & KEY_1_MASK) != 0) pressedKeys.Add(1);
        if ((hexValue & KEY_2_MASK) != 0) pressedKeys.Add(2);
        if ((hexValue & KEY_3_MASK) != 0) pressedKeys.Add(3);
        if ((hexValue & KEY_4_MASK) != 0) pressedKeys.Add(4);
        if ((hexValue & KEY_5_MASK) != 0) pressedKeys.Add(5);
        if ((hexValue & KEY_6_MASK) != 0) pressedKeys.Add(6);
        if ((hexValue & KEY_7_MASK) != 0) pressedKeys.Add(7);
        if ((hexValue & KEY_8_MASK) != 0) pressedKeys.Add(8);

        return pressedKeys;
    }

在数据包处理的方法中加入按键处理

    private readonly KeyStateManager _keyStateManager = new KeyStateManager();
    private float _lastMessageTime;
    private const float KEY_TIMEOUT = 1f;
    protected void Awake()
    {
        _keyStateManager.OnKeyStateChanged += LogKeyState;
        _lastMessageTime = Time.time;
    }
    /// <summary>
    /// 检查消息超时
    /// </summary>
    private void CheckMessageTimeout()
    {
        if (Time.time - _lastMessageTime > KEY_TIMEOUT)
        {
            _keyStateManager.HandleTimeout();
            _lastMessageTime = Time.time;
        }
    }
    private void ProcessPacket()
    {
    //-------------从已有的逻辑部分增加
        byte keyValue = Convert.ToByte(parts[7], 16);
        List<int> pressedKeys = ParseKeyPress(keyValue);
        _keyStateManager.UpdateKeyStates(pressedKeys);
		Debug.Log($"按键:{string.Join(", ", pressedKeys)}");
	}
	    /// <summary>
    /// 打印按键状态变化
    /// </summary>
    private void LogKeyState(int key, KEYButtonState state)
    {
        string color = state switch
        {
            KEYButtonState.OnButtonDown => "green",
            KEYButtonState.OnButtonUp => "yellow",
            KEYButtonState.OnButtonClick => "blue",
            _ => "white"
        };

        Debug.Log($"<color={color}>[DataHandlerLog]按键[ {key} ]{GetKeyStateDescription(state)}</color>");
    }

    /// <summary>
    /// 获取按键状态的描述文本
    /// </summary>
    private string GetKeyStateDescription(KEYButtonState state)
    {
        return state switch
        {
            KEYButtonState.OnButtonDown => "被按下",
            KEYButtonState.OnButtonUp => "被松开",
            KEYButtonState.OnButtonClick => "被点击",
            _ => "状态未知"
        };
    }

按键事件监听

    public event Action<float> OnTemperatureUpdated;
    public event Action<float> OnHumidityUpdated;
    public void SubscribeToKeyEvents(Action<int, KEYButtonState> listener)
    {
        _keyStateManager.OnKeyStateChanged += listener;
    }

    public void UnsubscribeFromKeyEvents(Action<int, KEYButtonState> listener)
    {
        _keyStateManager.OnKeyStateChanged -= listener;
    }

到这里位置,功能基本完善,但是还需要有个非常重要的处理,串口数据传输有个不可避免的问题,数据粘包。常用的解决方法是,添加一个缓冲区,接收到的数据不立刻处理,添加到缓冲区,然后从缓冲区去拿数据,拿一段去掉一段。

    private string _dataBuffer = "";
    /// <summary>
    /// 接收数据并加入缓冲区
    /// </summary>
    private void ReceiveData(string newData)
    {
        _dataBuffer += newData;
        ParseBuffer();
        _lastMessageTime = Time.time;
    }
        /// <summary>
    /// 解析缓冲区中的数据,提取完整数据包
    /// </summary>
    private void ParseBuffer()
    {
        while (true)
        {
            // 查找第一个数据头
            int head1Index = _dataBuffer.IndexOf(PACKET_HEAD1);
            if (head1Index == -1)
            {
                _dataBuffer = "";
                break;
            }

            // 检查是否有足够的长度容纳第二个数据头
            if (head1Index + 2 >= _dataBuffer.Length)
            {
                _dataBuffer = _dataBuffer.Substring(head1Index);
                break;
            }

            // 验证第二个数据头
            string potentialHead2 = _dataBuffer.Substring(head1Index + 4, 2); // 头1占2字节,帧序号占2字节
            if (potentialHead2 != PACKET_HEAD2)
            {
                _dataBuffer = _dataBuffer.Substring(head1Index + 2);
                continue;
            }

            // 查找数据包尾部
            string remaining = _dataBuffer.Substring(head1Index);
            int tailIndex = remaining.IndexOf(PACKET_TAIL_HIGH + PACKET_TAIL_LOW);
            if (tailIndex == -1)
            {
                _dataBuffer = _dataBuffer.Substring(head1Index);
                break;
            }

            // 提取完整数据包
            int packetLength = tailIndex + 4; // 尾部占4个字符(2字节)
            string completePacket = remaining.Substring(0, packetLength);

            ProcessPacket(completePacket);

            _dataBuffer = _dataBuffer.Substring(head1Index + packetLength);
        }
    }

模拟一下收到的信号数据,输出内容
在这里插入图片描述

实际上现在很多单片机已经支持直接传输中文字符串,处理起来更加简单,十六进制的话功耗会更小?
最后附上完整的数据解析代码

public class DataHandler : MonoSingleton<DataHandler>
{
    public bool isSimulation;
    // 事件定义
    public event Action<float> OnTemperatureUpdated;
    public event Action<float> OnHumidityUpdated;
    public event Action<byte> OnFrameSequenceUpdated;

    // 按键处理相关
    private readonly KeyStateManager _keyStateManager = new KeyStateManager();
    private float _lastMessageTime;
    private const float KEY_TIMEOUT = 1f;

    // 数据处理相关 - 根据新规则定义
    private string _dataBuffer = "";
    private const string PACKET_HEAD1 = "AA";         // 固定数据头1
    private const string PACKET_HEAD2 = "55";         // 固定数据头2
    private const string PACKET_TAIL_HIGH = "EE";     // 结束标识高位
    private const string PACKET_TAIL_LOW = "FF";      // 结束标识低位
    private const int EXPECTED_PACKET_PARTS = 10;     // 预期10个数据部分

    protected void Awake()
    {
        _keyStateManager.OnKeyStateChanged += LogKeyState;
        _lastMessageTime = Time.time;
    }

    private void Start()
    {
		//没有硬件的时候 unirx 模拟数据接收
        Observable.Interval(TimeSpan.FromSeconds(0.1f))
                  .Subscribe(_ => { if (isSimulation) ReceiveData("AA015500AA021407EEFF"); }
                   )
                  .AddTo(this);
    }

    protected virtual void Update()
    {
        CheckMessageTimeout();
    }

    /// <summary>
    /// 检查消息超时
    /// </summary>
    private void CheckMessageTimeout()
    {
        if (Time.time - _lastMessageTime > KEY_TIMEOUT)
        {
            _keyStateManager.HandleTimeout();
            _lastMessageTime = Time.time;
        }
    }

    /// <summary>
    /// 处理接收到的完整数据
    /// </summary>
    public void ReadComplateString(object data)
    {
        try
        {
            string hexString = data switch
            {
                byte[] byteData => DataConversionUtility.BytesToHexString(byteData),
                string stringData => stringData,
                _ => throw new ArgumentException($"未知的数据类型: {data.GetType()}")
            };

            if (!string.IsNullOrEmpty(hexString))
            {
                Debug.Log($"接收到数据: {hexString}");
                ReceiveData(hexString);
            }
        }
        catch (Exception ex)
        {
            Debug.LogError($"处理接收数据时发生错误: {ex.Message}");
        }
    }

    /// <summary>
    /// 接收数据并加入缓冲区
    /// </summary>
    private void ReceiveData(string newData)
    {
        _dataBuffer += newData;
        ParseBuffer();
        _lastMessageTime = Time.time;
    }

    /// <summary>
    /// 解析缓冲区中的数据,提取完整数据包
    /// </summary>
    private void ParseBuffer()
    {
        while (true)
        {
            // 查找第一个数据头
            int head1Index = _dataBuffer.IndexOf(PACKET_HEAD1);
            if (head1Index == -1)
            {
                _dataBuffer = "";
                break;
            }

            // 检查是否有足够的长度容纳第二个数据头
            if (head1Index + 2 >= _dataBuffer.Length)
            {
                _dataBuffer = _dataBuffer.Substring(head1Index);
                break;
            }

            // 验证第二个数据头
            string potentialHead2 = _dataBuffer.Substring(head1Index + 4, 2); // 头1占2字节,帧序号占2字节
            if (potentialHead2 != PACKET_HEAD2)
            {
                _dataBuffer = _dataBuffer.Substring(head1Index + 2);
                continue;
            }

            // 查找数据包尾部
            string remaining = _dataBuffer.Substring(head1Index);
            int tailIndex = remaining.IndexOf(PACKET_TAIL_HIGH + PACKET_TAIL_LOW);
            if (tailIndex == -1)
            {
                _dataBuffer = _dataBuffer.Substring(head1Index);
                break;
            }

            // 提取完整数据包
            int packetLength = tailIndex + 4; // 尾部占4个字符(2字节)
            string completePacket = remaining.Substring(0, packetLength);

            ProcessPacket(completePacket);

            _dataBuffer = _dataBuffer.Substring(head1Index + packetLength);
        }
    }

    /// <summary>
    /// 处理完整的数据包
    /// </summary>
    private void ProcessPacket(string packet)
    {
        string[] parts = DataConversionUtility.SplitIntoTwoCharParts(packet);

        if (parts.Length != EXPECTED_PACKET_PARTS)
        {
            Debug.LogError($"数据位数解析异常,期望{EXPECTED_PACKET_PARTS}个数据,实际{parts.Length}个");
            return;
        }

        try
        {
            // 验证数据头
            if (parts[0] != PACKET_HEAD1 || parts[2] != PACKET_HEAD2)
            {
                Debug.LogError($"数据头验证失败,预期 {PACKET_HEAD1}{PACKET_HEAD2},实际 {parts[0]}{parts[2]}");
                return;
            }

            // 验证数据尾
            if (parts[8] != PACKET_TAIL_HIGH || parts[9] != PACKET_TAIL_LOW)
            {
                Debug.LogError($"数据尾验证失败,预期 {PACKET_TAIL_HIGH}{PACKET_TAIL_LOW},实际 {parts[8]}{parts[9]}");
                return;
            }

            // 验证所有部分都是有效的十六进制
            if (!parts.All(DataConversionUtility.IsHexString))
            {
                Debug.LogError("数据包包含无效的十六进制值");
                return;
            }

            // 解析帧序号 (索引1)
            byte frameSequence = Convert.ToByte(parts[1], 16);
            OnFrameSequenceUpdated?.Invoke(frameSequence);

            // 解析温度数据 (索引3-4)
            float temperature = DataConversionUtility.CombineHighLowBytes(parts[3], parts[4]);

            // 解析湿度数据 (索引5-6)
            float humidity = DataConversionUtility.CombineHighLowBytes(parts[5], parts[6]);

            // 处理按键数据 (索引7)
            byte keyValue = Convert.ToByte(parts[7], 16);
            List<int> pressedKeys = ParseKeyPress(keyValue);
            _keyStateManager.UpdateKeyStates(pressedKeys);

            // 触发相应事件
            OnTemperatureUpdated?.Invoke(temperature);
            OnHumidityUpdated?.Invoke(humidity);

            // 输出日志
            Debug.Log($"帧序号:{frameSequence},温度:{temperature},湿度:{humidity},按键:{string.Join(", ", pressedKeys)}");
        }
        catch (Exception ex)
        {
            Debug.LogError($"处理数据包时发生错误: {ex.Message}");
        }
    }

    #region 按键解析
    // 按键掩码定义
    private const byte KEY_1_MASK = 0b00000001; // 1
    private const byte KEY_2_MASK = 0b00000010; // 2
    private const byte KEY_3_MASK = 0b00000100; // 4
    private const byte KEY_4_MASK = 0b00001000; // 8
    private const byte KEY_5_MASK = 0b00010000; // 16
    private const byte KEY_6_MASK = 0b00100000; // 32
    private const byte KEY_7_MASK = 0b01000000; 
    private const byte KEY_8_MASK = 0b10000000; 

    /// <summary>
    /// 解析十六进制值,判断哪些按键被按下
    /// </summary>
    public List<int> ParseKeyPress(byte hexValue)
    {
        List<int> pressedKeys = new List<int>();

        if ((hexValue & KEY_1_MASK) != 0) pressedKeys.Add(1);
        if ((hexValue & KEY_2_MASK) != 0) pressedKeys.Add(2);
        if ((hexValue & KEY_3_MASK) != 0) pressedKeys.Add(3);
        if ((hexValue & KEY_4_MASK) != 0) pressedKeys.Add(4);
        if ((hexValue & KEY_5_MASK) != 0) pressedKeys.Add(5);
        if ((hexValue & KEY_6_MASK) != 0) pressedKeys.Add(6);
        if ((hexValue & KEY_7_MASK) != 0) pressedKeys.Add(7);
        if ((hexValue & KEY_8_MASK) != 0) pressedKeys.Add(8);

        return pressedKeys;
    }
    #endregion

    #region 事件订阅
    public void SubscribeToKeyEvents(Action<int, KEYButtonState> listener)
    {
        _keyStateManager.OnKeyStateChanged += listener;
    }

    public void UnsubscribeFromKeyEvents(Action<int, KEYButtonState> listener)
    {
        _keyStateManager.OnKeyStateChanged -= listener;
    }
    #endregion

    /// <summary>
    /// 打印按键状态变化
    /// </summary>
    private void LogKeyState(int key, KEYButtonState state)
    {
        string color = state switch
        {
            KEYButtonState.OnButtonDown => "green",
            KEYButtonState.OnButtonUp => "yellow",
            KEYButtonState.OnButtonClick => "blue",
            _ => "white"
        };

        Debug.Log($"<color={color}>[DataHandlerLog]按键[ {key} ]{GetKeyStateDescription(state)}</color>");
    }

    /// <summary>
    /// 获取按键状态的描述文本
    /// </summary>
    private string GetKeyStateDescription(KEYButtonState state)
    {
        return state switch
        {
            KEYButtonState.OnButtonDown => "被按下",
            KEYButtonState.OnButtonUp => "被松开",
            KEYButtonState.OnButtonClick => "被点击",
            _ => "状态未知"
        };
    }
}

/// <summary>
/// 数据转换工具类,封装通用的数据转换方法
/// </summary>
public static class DataConversionUtility
{
    /// <summary>
    /// 将字节数组转换为十六进制字符串
    /// </summary>
    public static string BytesToHexString(byte[] bytes)
    {
        if (bytes == null) return string.Empty;

        StringBuilder sb = new StringBuilder(bytes.Length * 2);
        foreach (byte b in bytes)
        {
            sb.AppendFormat("{0:X2}", b);
        }
        return sb.ToString();
    }

    /// <summary>
    /// 将字符串分割为两个字符一组的数组
    /// </summary>
    public static string[] SplitIntoTwoCharParts(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            return Array.Empty<string>();
        }

        List<string> parts = new List<string>();
        for (int i = 0; i < input.Length; i += 2)
        {
            int length = (i + 2 <= input.Length) ? 2 : input.Length - i;
            parts.Add(input.Substring(i, length));
        }

        return parts.ToArray();
    }

    /// <summary>
    /// 检查字符串是否是有效的十六进制值
    /// </summary>
    public static bool IsHexString(string str)
    {
        return str.All(c => char.IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));
    }

    /// <summary>
    /// 将高位和低位十六进制值组合成16位有符号整数
    /// </summary>
    public static float CombineHighLowBytes(string highByteHex, string lowByteHex)
    {
        byte highByte = Convert.ToByte(highByteHex, 16);
        byte lowByte = Convert.ToByte(lowByteHex, 16);
        int combinedValue = (highByte << 8) | lowByte;
        return combinedValue;
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到