当前位置: 首页 > news >正文

unity与usb通信(pc端)

一、本文介绍在windows环境下unity与usb串口进行通信的代码

web版本的放在下一个文章

注:

1.我的硬件是检测磁阻液位,用到四字节十六进制浮点数,所以这里会直接转换到十进制。

2.我的硬件会返回9字节响应,所以我会限制响应长度,可以进行适当更改

重要:再开始前一定要改为.NET 4.x,或者.NET Framework,因为.NET standard 2.0或者2.1不包括需要用到的using System.IO.Ports;更换路径为File/Build Setting/Player Settings.../Other Settings/Api Compatibility Level

二、脚本

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
using UnityEngine;

public class SerialPortCommunicationManager : MonoBehaviour
{
    private static SerialPortCommunicationManager _instance;
    public static SerialPortCommunicationManager Instance
    {
        get
        {

            if (_instance == null)
            {
                GameObject obj = new GameObject("SerialPortCommunicationManager");
                _instance = obj.AddComponent<SerialPortCommunicationManager>();
                DontDestroyOnLoad(obj);
            }
            return _instance;
        }
    }


    public string portName;// 串口号
    public int baudRate;// 波特率
    public int dataBit;//数据位
    public Parity parity;//校验位
    public StopBits stopBit;//停止位
    private SerialPort sp = new SerialPort();

    private List<byte> receiveBuffer = new List<byte>(); // 用于存储接收到的字节
    private const int RESPONSE_LENGTH = 9; // 每组响应的长度(9 个字节)

    /// <summary>
    /// 打开端口
    /// </summary>
    public void OpenPort()
    {
        sp = new SerialPort(portName, baudRate, parity, dataBit, stopBit);
        sp.ReadTimeout = 20;
        try
        {
            sp.Open();
            Debug.Log("端口已打开");
        }
        catch (Exception e)
        {
            Debug.LogError("端口未打开: " + e.Message);
        }
    }
    /// <summary>
    /// 关闭端口
    /// </summary>
    public void ClosePort()
    {
        try
        {
            sp.Close();
            sp.Dispose();
            Debug.Log("端口已关闭");
        }
        catch (Exception e)
        {
            Debug.LogError("端口无法关闭: " + e.Message);
        }
    }


    /// <summary>
    /// 检查串口是否打开
    /// </summary>
    public bool IsPortOpen()
    {
        return sp != null && sp.IsOpen;
    }
    /// <summary>
    /// 发送数据
    /// </summary>
    public void SendData(byte[] dataStr)
    {
        if (sp != null && sp.IsOpen)
        {
            sp.Write(dataStr, 0, dataStr.Length);
            Debug.LogWarning("发送成功: " + BitConverter.ToString(dataStr).Replace("-", " "));
        }
        else
        {
            Debug.LogError("串口未打开,无法发送数据!");
        }
    }
    /// <summary>
    /// 接收端口数据
    /// </summary>
    public void DataReceiveFun()
    {
        while (true)
        {
            if (sp != null && sp.IsOpen)
            {
                try
                {
                    int bytesToRead = sp.BytesToRead;
                    if (bytesToRead > 0)
                    {
                        byte[] buffer = new byte[bytesToRead];
                        int bytesRead = sp.Read(buffer, 0, bytesToRead);
                        if (bytesRead > 0)
                        {
                            // 将读取到的数据添加到缓冲区
                            receiveBuffer.AddRange(buffer);

                            // 按 9 个字节为单位处理数据
                            while (receiveBuffer.Count >= RESPONSE_LENGTH)
                            {
                                byte[] response = receiveBuffer.GetRange(0, RESPONSE_LENGTH).ToArray();
                                receiveBuffer.RemoveRange(0, RESPONSE_LENGTH); // 移除已处理的数据

                                // 打印原始响应数据
                                string responseHex = BitConverter.ToString(response).Replace("-", " ");
                                Debug.Log($"收到响应: {responseHex}");

                                // 解析浮点数数据
                                if (response.Length == RESPONSE_LENGTH && response[0] == 0x01 && response[1] == 0x04)
                                {
                                    // 假设从第 3 字节起 4 个字节是 IEEE 754 单精度浮点数
                                    byte[] floatBytes = new byte[4];
                                    Array.Copy(response, 3, floatBytes, 0, 4); // 提取第 3 到第 6 字节

                                    // 将字节转换为浮点数
                                    float floatValue = ConvertHexToFloat(floatBytes);
                                    Debug.Log($"解析得到的浮点数: {floatValue}");
                                }
                                else
                                {
                                    Debug.LogWarning("响应格式错误!");
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.LogError($"接收数据异常: {e.GetType()} - {e.Message}");
                }
            }
            Thread.Sleep(10); // 降低 CPU 占用,10 毫秒足够快
        }
    }
    /// <summary>
    /// 将 4 个字节转换为 IEEE 754 单精度浮点数
    /// </summary>
    private float ConvertHexToFloat(byte[] bytes)
    {
        // 确保字节顺序正确(大端或小端取决于你的设备,这里假设是大端)
        if (BitConverter.IsLittleEndian)
        {
            Array.Reverse(bytes); // 如果是小端机器,翻转字节顺序
        }

        // 直接使用 BitConverter 将字节转换为浮点数
        float result = BitConverter.ToSingle(bytes, 0);
        return result;
    }
    // 字符串转字节流 推荐
    public byte[] Convert16(string strText)
    {
        strText = strText.Replace(" ", "");
        byte[] bText = new byte[strText.Length / 2];
        for (int i = 0; i < strText.Length / 2; i++)
        {
            bText[i] = Convert.ToByte(Convert.ToInt32(strText.Substring(i * 2, 2), 16));
        }
        return bText;
    }
}

三、使用

using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using System.Threading;
using UnityEngine;

public class UseSerialPort : MonoBehaviour
{
    private bool isRunning = true; // 控制发送循环的标志
    void Start()
    {
        SerialPortCommunicationManager.Instance.portName="COM3";      // 串口号
        SerialPortCommunicationManager.Instance.baudRate=9600;         // 波特率
        SerialPortCommunicationManager.Instance.dataBit=8;           // 数据位
        SerialPortCommunicationManager.Instance.parity=Parity.None;  // 校验位
        SerialPortCommunicationManager.Instance.stopBit=StopBits.One; // 停止位
        SerialPortCommunicationManager.Instance.OpenPort(); // 打开串口
        // 启动接收线程
        new Thread(() =>
        {
            SerialPortCommunicationManager control = new SerialPortCommunicationManager();
            control.DataReceiveFun(); // 持续监听数据
        }).Start();
        // 启动发送协程,持续发送命令
        StartCoroutine(SendCommandRoutine());
    }
    /// <summary>
    /// 持续发送命令
    /// </summary>
    /// <returns></returns>
    IEnumerator SendCommandRoutine()
    {
        // 这里是我要发送的命令,并且会接收到9字节响应,所以会限制响应长度
        string commandHex = "01 04 00 02 00 02 D0 0B"; // 与日志中的命令一致
        byte[] commandBytes = SerialPortCommunicationManager.Instance.Convert16(commandHex.Replace(" ", ""));

        while (isRunning)
        {
            SerialPortCommunicationManager.Instance.SendData(commandBytes);
            // 等待时间
            yield return new WaitForSeconds(0.1f); 
        }
    }
}

四、结尾

有任何错误请指出,补充请评论,看到会第一时间回复,谢谢。

相关文章:

  • MySQL 管理与配置:查看端口、修改密码与数据存储位置
  • 高性能文件上传服务
  • 扒光HPM6800系列 | 显示子系统架构介绍
  • 视频监控汇聚平台智能边缘分析一体机视频智能分析平台智能算法检测识别客流统计检测
  • ChatGPT-API学习笔记
  • 为您的 Web 应用选择最佳文档阅读器
  • 《Vue Router实战教程》10.路由组件传参
  • 【KWDB 创作者计划】香橙派Ai Pro安装部署KWDB数据库踩坑经验
  • 【大模型系列篇】基于Ollama和GraphRAG v2.0.0快速构建知识图谱
  • UNet 改进(4):融合Ghost Module的轻量化分割网络
  • STL之序列式容器(Vector/Deque/List)
  • 深度学习篇---大模型ERNIE Bot
  • 第2章 分词和嵌入
  • 大企业的AI应用如何更懂业务?
  • PhalApi 2.x:让PHP接口开发从“简单”到“极简”的开源框架
  • CExercise_08_字符串_2统计该字符串中每个字符出现的次数,统计过程中忽略大小写的差异,并打印最终每个字符出现的次数。
  • 二分查找法
  • 使用 LLaMA-Factory 微调 llama3 模型(二)
  • 动力电池自动点焊机:新能源汽车制造的智能焊接利器
  • CWGAN-GP 原理及实现(pytorch版)
  • 合肥金融网站开发/seo网络营销外包公司
  • 企业网站托管外包平台/深圳aso优化
  • 素材网官网免费/seo推广方式是什么呢
  • 廊坊网站建设制作电话/网络营销案例范文
  • 一站式服务平台登录/sem与seo的区别
  • 建站之星网站模板商城/处理事件seo软件