Unity串口通信、接受和发送数据、C#

这篇具有很好参考价值的文章主要介绍了Unity串口通信、接受和发送数据、C#。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、串口简介


串行接口(串口)通常指COM接口,是采用串行通信方式的扩展接口。串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。特别适用于远距离通信。

查看串口:右键 我的电脑-管理-设备管理器-端口

Unity串口通信、接受和发送数据、C#

选择一个端口,双击查看属性。

Unity串口通信、接受和发送数据、C#

这里通过串口属性,可以知道以下数据:
波特率:这是一个衡量符号传输速率的参数。
数据位:这是衡量通信中实际数据位的参数。
停止位:用于表示单个包的最后一位。
奇偶校验:在串口通信中一种简单的检错方式。
对于两个进行通信的端口,这些参数必须匹配。

3、串口通信原理:

串行接口在嵌入式系统中是一种重要的数据通信接口,其本质功能是作为CPU和串行设备间的编码转换器。在发送数据时,数据从CPU经串行端口,字节数据转换为串行的位;在接收数据时,串行的位转换为字节数据。

4、常用的协议:

RS-232: 标准串口,最常用的一种串行通讯接口采取不平衡传输方式,即所谓单端通讯, 是为点对点通讯而设计的。
RS-422: 支持点对多的双向通信。采用单独的发送和接收通道,因此不必控制数据方向,各装置之间任何必须的信号交换均可以按软件方式(XON/XOFF握手)或硬件方式(一对单独的双绞线)实现。
RS-485: 从RS-422基础上发展而来的, RS-485可以采用二线与四线方式,二线制可实现真正的多点双向通信,而采用四线连接时,与RS-422一样只能实现点对多的通信,但它比RS-422有改进,无论四线还是二线连接方式总线上可多接到32个设备。
串口的接口标准规范9针串口:

Unity串口通信、接受和发送数据、C#

针脚功能:


1、数据载波检测(DCD)
2、串口接收数据(RXD)
3、串口发出数据(TXD)
4、数据终端就绪(DTR)
5、信号地线(GND)
6、数据发送就绪(DSR)
7、发送数据请求(RTS)
8、清除发送(CTS)
9、铃声指示(RI)

我在现在用的是CH340芯片进行传输

Unity串口通信、接受和发送数据、C#

二、使用C#和Unity进行串口编程


在对串口进行编程时候,我们要向串口发送指令,然后我们解析串口返回的指令。从.NET Framework 2.0开始,C#提供了SerialPort类用于实现串口控制。命名空间:System.IO.Ports。详细信息可以参看(MSDN技术文档)
1、 常用的字段:
PortName:获取或设置通信端口
BaudRate:获取或设置串行波特率
DataBits:获取或设置每个字节的标准数据位长度
Parity:获取或设置奇偶效验检查协议
StopBits:获取或设置每个字节的标准停止位数
2、 常用方法:
Close:关闭端口连接,将IsOpen属性设置false,并释放内部Stream对象
GetPortNames:获取当前计算机的串行端口名称数组
Open:打开一个新的串行端口连接
Read:从SerialPort输入缓冲区中读取
Write:将数据写入串行端口输出缓冲区
3、常用事件:
DataReceived:表示将处理SerialPort对象的数据接收事件的方法
DisPosed:通过调用释放组件时发生Dispose方法(继承自Component)
4、SerialPort 控件使用流程
流程是设置通信端口号及波特率、数据位、停止位和校验位,再打开端口连接、发送数据、接收数据,最后关闭端口连接步骤。
 
首先Unity是支持串口通信的,只不过Unity采用的是Mono .NET 2.0。之前版本对COM支持不是很好,所以导致Unity在串口通信方面有些问题。
小编用的版本是2018.4.0
首先想使用Unity开发串口通信,必须要做的 一点就是 要使用Mono.NET 2.0/4.0/其他
如下图:

Unity串口通信、接受和发送数据、C#

或 .net framework

Unity串口通信、接受和发送数据、C#

不修改的话是不能进行串口开发的 。

例子一:

修改完之后下面是代码环节,简单通俗易懂

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
using System.Threading;
using System;
using System.Text;
/// <summary>
/// 串口通信
/// </summary>
public class SerialPortControl
{
    public static string portName;//串口号
    public static int baudRate;//波特率
    public static Parity parity;//校验位
    public static int dataBit;//数据位
    public static StopBits stopBit;//停止位
    static SerialPort sp = new SerialPort();
    /// <summary>
    /// 串口号
    /// </summary>
    /// <param name="portname"></param>
    /// <returns></returns>
    public static string PortName(string portname)
    {
        portName = portname;
        return portName;
    }
    /// <summary>
    /// 波特率
    /// </summary>
    /// <param name="baud"></param>
    /// <returns></returns>
    public static int BauRate(int baud)
    {
        baudRate = baud;
        return baudRate;
    }
    /// <summary>
    /// 校验位
    /// </summary>
    /// <param name="paritys"></param>
    /// <returns></returns>
    public static Parity Paritys(Parity paritys)
    {
        parity = paritys;
        return parity;
    }
    /// <summary>
    /// 数据位
    /// </summary>
    /// <param name="dataBits"></param>
    /// <returns></returns>
    public static int DataBits(int dataBits)
    {
        dataBit = dataBits;
        return dataBit;
    }
    /// <summary>
    /// 停止位
    /// </summary>
    /// <param name="stopBits"></param>
    /// <returns></returns>
    public static StopBits StopBitss(StopBits stopBits)
    {
        stopBit = stopBits;
        return stopBit;
    }
    /// <summary>
    /// 字节流转字符串
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns></returns>
    public static string BytesTohexString(byte[] bytes)
    {
        if (bytes == null || bytes.Length < 1)
        {
            return string.Empty;
        }

        var count = bytes.Length;

        var cache = new StringBuilder();
        cache.Append("0x");
        for (int ii = 0; ii < count; ++ii)
        {
            var tempHex = Convert.ToString(bytes[ii], 16).ToUpper();
            cache.Append(tempHex.Length == 1 ? "0" + tempHex : tempHex);
        }

        return cache.ToString();
    }
    /// <summary>
    /// 字符串转字节流
    /// </summary>
    /// <param name="hexStr"></param>
    /// <returns></returns>
    public static byte[] HexStringToBytes(string hexStr)
    {
        if (string.IsNullOrEmpty(hexStr))
        {
            return new byte[0];
        }
        if (hexStr.StartsWith("0x"))
        {
            hexStr = hexStr.Remove(0, 2);
        }
        var count = hexStr.Length;
        var byteCount = count / 2;
        var result = new byte[byteCount];
        for (int ii = 0; ii < byteCount; ++ii)
        {
            var tempBytes = Byte.Parse(hexStr.Substring(2 * ii, 2), System.Globalization.NumberStyles.HexNumber);
            result[ii] = tempBytes;
        }
        return result;
    }
    
    //字符串转字节流 推荐======
    public static 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;
    }

    /// <summary>
    /// 打开端口,连接串口
    /// </summary>
    public static void OpenPort()
    {
        sp = new SerialPort(portName, baudRate, parity, dataBit, stopBit);
        sp.ReadTimeout = 1000;
        try
        {
            sp.Open();

            Debug.Log("打开端口成功");
        }
        catch (Exception e)
        {
            Debug.Log(e.Message);
        }
    }

    /// <summary>
    /// 关闭端口
    /// </summary>
    public static void ClosePort()
    {
        try
        {
            sp.Close();
            sp.Dispose();
            Debug.Log("关闭端口");
        }
        catch (Exception e)
        {
            Debug.Log(e.Message);
        }
    }

    byte[] buffer = new byte[5];
    int bytes = 0;

    /// <summary>
    /// 交互:接收端口数据
    /// </summary>
    public void DataReceiveFun()
    {
        while (true)
        {
            if (sp != null && sp.IsOpen)
            {
                try
                {
                    bytes = sp.Read(buffer, 0, buffer.Length);
                    sp.DiscardOutBuffer();
                    if (bytes == 0)
                    {
                        continue;
                    }
                    else
                    {
                        for (int i = 0; i < buffer.Length; i++)
                        {
                            Debug.Log(buffer[i].ToString("x8"));
                        }

                    }
                }
                catch (Exception e)
                {
                    Debug.Log(e);
                }
            }
            Thread.Sleep(500);
        }
    }
    /// <summary>
    /// 交互:发送数据
    /// </summary>
    /// <param name="dataStr"></param>
    public static void SendData(byte[] dataStr)
    {
        sp.Write(dataStr, 0, dataStr.Length);
        Debug.LogWarning("发送成功");
    }
}

 一些其他便捷功能:

    
//十进制转二进制

Console.WriteLine(Convert.ToString(69, 2));

//十进制转八进制

Console.WriteLine(Convert.ToString(69, 8));

//十进制转十六进制

Console.WriteLine(Convert.ToString(69, 16));

//二进制转十进制

Console.WriteLine(Convert.ToInt32("100111101", 2));

//八进制转十进制

Console.WriteLine(Convert.ToInt32("76", 8));

//16进制转换10进制

Console.WriteLine(Convert.ToInt32("FF", 16));
 /// <summary>
    /// 字符串转字节流
    /// </summary>
    /// <param name="hexStr"></param>
    /// <returns></returns>
    public static byte[] HexStringToBytes(string hexStr)
    {
        if (string.IsNullOrEmpty(hexStr))
        {
            return new byte[0];
        }
        if (hexStr.StartsWith("0x"))
        {
            hexStr = hexStr.Remove(0, 2);
        }
        var count = hexStr.Length;
        var byteCount = count / 2;
        var result = new byte[byteCount];
        for (int ii = 0; ii < byteCount; ++ii)
        {
            var tempBytes = Byte.Parse(hexStr.Substring(2 * ii, 2), System.Globalization.NumberStyles.HexNumber);
            result[ii] = tempBytes;
        }
        return result;
    }
     //第二种 常用转换方式 推荐
    public static 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;
    }

例子二:Mono版本

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

public class PortControl : MonoBehaviour
{
    #region 定义串口属性
    public GUIText gui;
    //public GUIText Test;
    //定义基本信息
    public string portName = "COM3";//串口名
    public int baudRate = 9600;//波特率
    public Parity parity = Parity.None;//效验位
    public int dataBits = 8;//数据位
    public StopBits stopBits = StopBits.One;//停止位
    SerialPort sp = null;
    Thread dataReceiveThread;
    //发送的消息
    string message = "";
    public List<byte> listReceive = new List<byte>();
    char[] strchar = new char[100];//接收的字符信息转换为字符数组信息
    string str;
    #endregion
    void Start()
    {
        OpenPort();
        dataReceiveThread = new Thread(new ThreadStart(DataReceiveFunction));
        dataReceiveThread.Start();
    }
    void Update()
    {

    }

    #region 创建串口,并打开串口
    public void OpenPort()
    {
        //创建串口
        sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
        sp.ReadTimeout = 400;
        try
        {
            sp.Open();
        }
        catch (Exception ex)
        {
            Debug.Log(ex.Message);
        }
    }
    #endregion



    #region 程序退出时关闭串口
    void OnApplicationQuit()
    {
        ClosePort();
    }
    public void ClosePort()
    {
        try
        {
            sp.Close();
            dataReceiveThread.Abort();
        }
        catch (Exception ex)
        {
            Debug.Log(ex.Message);
        }
    }
    #endregion


    /// <summary>
    /// 打印接收的信息
    /// </summary>
    void PrintData()
    {
        for (int i = 0; i < listReceive.Count; i++)
        {
            strchar[i] = (char)(listReceive[i]);
            str = new string(strchar);
        }
        Debug.Log(str);
    }

    #region 接收数据
    void DataReceiveFunction()
    {
        #region 按单个字节发送处理信息,不能接收中文
        //while (sp != null && sp.IsOpen)
        //{
        //    Thread.Sleep(1);
        //    try
        //    {
        //        byte addr = Convert.ToByte(sp.ReadByte());
        //        sp.DiscardInBuffer();
        //        listReceive.Add(addr);
        //        PrintData();
        //    }
        //    catch
        //    {
        //        //listReceive.Clear();
        //    }
        //}
        #endregion


        #region 按字节数组发送处理信息,信息缺失
        byte[] buffer = new byte[1024];
        int bytes = 0;
        while (true)
        {
            if (sp != null && sp.IsOpen)
            {
                try
                {
                    bytes = sp.Read(buffer, 0, buffer.Length);//接收字节
                    if (bytes == 0)
                    {
                        continue;
                    }
                    else
                    {
                        string strbytes = Encoding.Default.GetString(buffer);
                        Debug.Log(strbytes);
                    }
                }
                catch (Exception ex)
                {
                    if (ex.GetType() != typeof(ThreadAbortException))
                    {
                    }
                }
            }
            Thread.Sleep(10);
        }
        #endregion
    }
    #endregion



    #region 发送数据
    public void WriteData(string dataStr)
    {
        if (sp.IsOpen)
        {
            sp.Write(dataStr);
        }
    }
    void OnGUI()
    {
        message = GUILayout.TextField(message);
        if (GUILayout.Button("Send Input"))
        {
            WriteData(message);
        }
        string test = "AA BB 01 12345 01AB 0@ab 发送";//测试字符串
        if (GUILayout.Button("Send Test"))
        {
            WriteData(test);
        }
    }
    #endregion
}

一些问题: 

1、没有将Unity3D的API平台切换成.NET2.0,这时Unity编写SerialPort类会报错。
解决方法:将Unity3D的API平台切换成.NET2.0,切换方法: “Edit–>project Setting–>Player–>Other Setting –>Api Compatibility level”。在这里将“.NET2.0 Subset”切换为“.NET2.0”
2、Unity的目标平台没有切换为Windows平台,会提示该命名空间不支持SystemIO,提示你切换工具。
解决方法:把目标平台切换为Windows平台,否则是其他平台会报错误。
3、串口发送的信息不能正常解析
解决方法:把串口发送的消息使用字节流进行转换。(字符流转换)
4、串口接收信息的缺失问题
(1)接收字符串(string):port.ReadLine()
数据接收可能错误,数据丢失,数据接收不到
(2)接收字节数组(byte[]):port.Read()
接收数据断层,会分两次接收完整数据
(3)接收单个字节(byte):port.ReadByte()
将接收到的数据进行组合
5.第一次发送数据的时候,往往会丢失数据尾(和知名大佬总结得出,最后会在文章底部@大佬)
比如发送:64 64 80 89 第一次接收的可能是64 80 89 0
解决方法:
 

			//40405059 暂停
            if (paramByte[0] == (byte)64 && paramByte[1] == (byte)64 && paramByte[2] == (byte)80 && paramByte[3] == (byte)89)
            {
					Debug.Log("AA");
            }
			else if (paramByte[0] == (byte)64 && paramByte[1] == (byte)80 && paramByte[2] == (byte)89)
            {
					Debug.Log("AA");
            }

通过以上代码,可以完美避开这个坑,第二次就会正常。

每台电脑的串口都是不一样的,比如你从A电脑,插上去设备管理器显示的是COM 2,你程序中定义的是COM2,这样可以实现通讯。
如果你换了台电脑B,但是现在B电脑串口是COM10,你代码中还是COM2,就没办法完成通讯了。
解决方案一:通过读取TXT文档,来设置COM口。

public static string portName = "";//串口名称
void Start()
    {
        string path = Application.streamingAssetsPath + "/config.txt";
        string[] strs = File.ReadAllLines(path);
        if (strs.Length > 0) portName = strs[0];
        Debug.Log(strs.Length);
    }

Unity串口通信、接受和发送数据、C#

解决方案二:通过读取电脑注册表,来动态设置COM口。

public string getPortName = "";//串口名称
void Start()
	{
		List<string> protReg = GetPortFromReg();

		if (protReg.Count > 0)
		{
			getPortName = protReg[2];//0是默认第一接口.
		}
		else
		{
			Debug.Log("获取不到端口");
		}
		Debug.Log("当前COM口配置为:"+getPortName);
	}

这样就可以动态获取COM口,但是此方法多少还是有局限性,想要准确无误,还是要用解决一方法(通过TXT文本配置)

三步教会你 Unity串口通讯_unity串口通信__橙子先生的博客-CSDN博客

Unity串口通信、接受和发送数据、C#_unity 串口接收_与火星的孩子对话的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-411905.html

到了这里,关于Unity串口通信、接受和发送数据、C#的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot+jSerialComm实现Java串口通信 读取串口数据以及发送数据

    记录一下使用SpringBoot+jSerialComm实现Java串口通信,使用Java语言开发串口,对串口进行读写操作,在win和linux系统都是可以的,有一点好处是不需要导入额外的文件。 案例demo源码:SpringBoot+jSerialComm实现Java串口通信 读取串口数据以及发送数据 之前使用RXTXcomm实现Java串口通信,这

    2024年02月05日
    浏览(39)
  • SpringBoot+RXTXcomm实现Java串口通信 读取串口数据以及发送数据

    记录一下使用SpringBoot+RXTXcomm实现Java串口通信,使用Java语言开发串口,对串口进行读写操作。 案例源码:SpringBoot+RXTXcomm实现Java串口通信 读取串口数据以及发送数据 RXTXcomm.jar这个包支持的系统较多,但是更新太慢,在win系统下使用没有问题,但是在centos的工控机系统里使用

    2024年02月04日
    浏览(37)
  • C#串口通信从入门到精通(26)——多个串口多个线程发送数据和接收数据

    我们在开发串口程序的过程中有时候会遇到多个串口,并且多个串口也需要在多个线程进行操作,本文就来讲解如何实现多个串口在多线程下的安全发送与接收。 我们首先使用虚拟串口助手虚拟COM1、COM2这一对串口;COM3、COM4这一对串口,然后使用代码操作COM1,然后打开一个

    2024年02月11日
    浏览(56)
  • FPGA学习笔记(三)——串口通信之发送数据(调试过程)

    本学习笔记主要参考小梅哥B站教学视频,网址如下: https://www.bilibili.com/video/BV1va411c7Dz?p=1 使用的编译器为Vivado,HDL语言为verilog 一、串口通信之发送数据 原理 设计代码 测试代码 仿真结果 发现Send_en拉高之前,uart_tx就置为0了,不符合常理。 转到第二个发送信号处,发现Send

    2023年04月09日
    浏览(41)
  • 串口通信——发送和接收数据(8位和16位数据之间的转换)

    1.发送两个字节数据,就是16位的数据,每一次发送8位,发送两次,这里要进行数据的拆分,如发送一个0XFF56,接收得到的也是FF56(16进制显示); 2.接收两个字节的数据(这里通过串口助手以16进制发送一个数据),将拼接的数据(只能一个字节一个字节接收)除以100展示出来

    2024年01月17日
    浏览(97)
  • P27[9-3]STM32:串口通信(串口发送)(内含:1.接线图+2.实物图+3.代码部分+4.解决串口发送数据,数据是汉字,结果发送结果为乱码的现象)

    1.接线图如下: 跳线帽接在4~5引脚,2,3引脚连接PA9和PA10引脚。下图也可得出USART接PA9和PA10引脚。 TX和RX是交叉连接。PA9(黄线)是TX,接RXD。PA9(绿线)是RXD,接TX. 图中的串口模块和STINK都接电脑上,使之拥有独立供电。 2.实物图: 黄色为跳线帽,接4~5引脚。

    2024年02月09日
    浏览(40)
  • FPGA自学笔记--串口通信发送多字节数据(verilog版)

            关于uart协议实现这部分大家可以参考我上一篇的博客。《FPGA自学笔记--串口通信实现(vivadoverilog版)》。在上一篇博客中,主要实现了将单字节的数据,我们其实就是用上一篇博客的模块来实现多字节数据的发送。         在真实的数据传输过程中,我们不

    2023年04月17日
    浏览(34)
  • 基于串口通信技术——让数码管显示的数据发送给电脑,电脑控制单片机外设——15单片机

    目录 1.使用的单片机为IAPI15F2K61S2 2.使用的外设 3.各个外设的作用 1.数码管功能  2.LED灯 3.蜂鸣器与继电器 4.按键 5.串口通信 4.利用发送单个字符函数 发送字符型的数字值,为一个变量+\\\'0\\\',发送为字符型数字。 4.初始化 5.程序 1.main 2.iic.h 3.onewire.c 1.LED灯,继电器与蜂鸣器。 2.数

    2024年02月10日
    浏览(45)
  • STM32-串口通信(串口的接收和发送)

    本文在于记录自己的学习过程中遇到的问题和总结,各种情况下串口通信在STM32的实际使用方面占有很大的比重,本文主要对 串口通信 做一个简要的总结。 在STM32里,串口通信是USART,STM32可以通过串口和其他设备进行传输 并行数据 ,是 全双工 , 异步时钟控制 ,设备之间是

    2024年02月03日
    浏览(70)
  • 串口通信实现-串口发送(vivado&verilog版)

    串口系列知识分享: (1)串口通信实现-串口发送 (2)串口通信发送多字节数据 (3)串口通信实现-串口接收 (4)UART 通信-使用VIO进行板级验证 (5)串口接收-控制LED闪烁 (6)使用串口发送实现ACX720开发板时钟显示 (7)串口发送+RAM+VGA传图 此文介绍uart串口协议(串口发

    2024年02月14日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包