Unity串口通信 遇到的问题与解决

2 篇文章 0 订阅

一、串口通信的流程有:

1)扫描串口

2)打开串口

3)发送数据 (byte[]数据格式发送)

4)接收数据(byte[]数据格式接收)

5)处理数据

6)关闭串口

二、代码

在Unity中创建一个脚本SXPortTest.cs,并挂到Camera上。代码如下:

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

public class SXPortTest : MonoBehaviour
{
    private SerialPort sp;
    double x;
    double y;
    double z;
    string[] TxData = new string[5];
    // Start is called before the first frame update
    void Start()
    {
        TxData[3] = "5003003d00039986";
        
        string[] portArray = ScanPorts_TryFail();//使用试错函数,可以解决COM被占用问题
        Debug.Log("串口号:" + portArray.ToString());
        OpenSerialPort(portArray[0], 9600, Parity.None, 8, StopBits.One);
        SendData();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    //试错方式扫描   第三种扫描端口的方法
    public string[] ScanPorts_TryFail()
    {
        List<string> tempPost = new List<string>();
        bool mark = false;
        for (int i = 0; i < 10; i++)
        {
            try
            {
                SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
                sp.Open();
                sp.Close();
                tempPost.Add("COM" + (i + 1).ToString());
                Debug.Log("串口号i:" + i);
                mark = true;
            }
            catch (System.Exception)
            {
                continue;
            }

        }
        if (mark)
        {
            string[] portList = tempPost.ToArray();
            return portList;
        }
        else
        {
            return null;
        }
    }

    #region 发送数据

    /// <summary>
    /// 发送数据
    /// 
    /// 进制转换方法:5003003d00039986
    /// 1)两位分割 50 03 00 3d 00 03 99 86
    /// 2)转二进制 0101000
    /// 3)转十进制 80
    /// 
    /// 如果 fromBase 为 16,则可以在 value 参数指定的数字前面加上“0x”或“0X”。
    /// 
    /// </summary>
    /// <param name="send">byte数据</param>
    /// <param name="offSet">起始位</param>
    /// <param name="count">byte长度</param>
    public void SendData()
    {
        byte[] Data = new byte[2];
        try
        {
            if (sp.IsOpen)
            {
                for (int i = 0; i < 8; i++)
                {
                    Data[0] = Convert.ToByte(TxData[3].Substring(i * 2, 2), 16);
                    Debug.Log("发送的数据 字节型  Data[0]:" + Data[0]);
                    Debug.Log("发送的数据 字节型  Data:" + Data);
                    sp.Write(Data, 0, 1);//循环发送(如果输入字符为0A0BB,则只发送0A,0B)
                }
            }
            else
            {
                sp.Open();
                for (int i = 0; i < 8; i++)
                {
                    Data[0] = Convert.ToByte(TxData[3].Substring(i * 2, 2), 16); 
                    sp.Write(Data, 0, 1);//循环发送(如果输入字符为0A0BB,则只发送0A,0B)
                }

            }
        }
        catch (Exception ex)
        {
            Debug.Log(ex);
            Debug.Log("请先打开串口");//弹出提示框
        }
    }
#endregion

    #region 打开串口 读取数据 处理数据
    /// <summary>
    /// 打开串口
    /// </summary>
    /// <param name="_portName">端口号</param>
    /// <param name="_baudRate">波特率</param>
    /// <param name="_parity">校验位</param>
    /// <param name="dataBits">数据位</param>
    /// <param name="_stopbits">停止位</param>
    public void OpenSerialPort(string _portName, int _baudRate, Parity _parity, int dataBits, StopBits _stopbits)
    {
        try
        {
            sp = new SerialPort(_portName, _baudRate, _parity, dataBits, _stopbits);//绑定端口
            sp.Open();
            Debug.Log("串口打开");
            //使用委托
            //sp.DataReceived += DataReceived;
            //使用线程
            Thread thread = new Thread(new ThreadStart(DataReceived));
            thread.Start();
        }
        catch (Exception ex)
        {
            sp = new SerialPort();
            Debug.Log(ex);
        }
    }

    /// <summary>
    /// 接收数据 线程
    /// </summary>
    public void DataReceived()
    {
        while (true)
        {
            if (sp.IsOpen)
            {
                int count = sp.BytesToRead;
                if (count > 0)
                {
                    byte[] readBuffer = new byte[count];  //数据 也是byte[]类型
                    try
                    {
                        sp.Read(readBuffer, 0, count);

                        DataProcessing_Old(readBuffer);//数据处理

                        //DataProcessing_New(readBuffer);//数据处理

                       // DataProcessing_Test(readBuffer);//数据处理
                    }
                    catch (Exception ex)
                    {
                        Debug.Log(ex.Message);
                    }
                }
            }
            Thread.Sleep(10);
        }
    }


    /// <summary>
    /// 接收到的数据进行  数据处理 测试的
    /// </summary>
    /// <param name="data">字节数组</param>
    public void DataProcessing_Test(byte[] data)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < data.Length; i++)
        {
            sb.Append(data[i]);
            
        }
        Debug.Log("Test:"+sb.ToString());
    }   
    /// <summary>
    ///数据处理 原本的
    /// </summary>
    /// <param name="data">字节数组</param>
    public void DataProcessing_Old(byte[] data)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < data.Length; i++)
        {
            sb.AppendFormat("{0:x2}" + "", data[i]);//{0:X2}将第一个参数转换成大写的十六进制文本,长度为2,不足前面补0
        }
        Debug.Log("OLD"+sb.ToString());
    }  
    /// <summary>
    /// 数据处理 师兄的
    /// </summary>
    /// <param name="data">字节数组</param>
    public void DataProcessing_New(byte[] data)
    {
        if(data.Length == 11)
        {
            if(data[0] == 80 && data[1] == 3 && data[2] == 6)
            {
                double temp3 = data[3];
                double temp4 = data[4];

                double temp5 = data[5];
                double temp6 = data[6];

                double temp7 = data[7];
                double temp8 = data[8];

                int temp3i = Convert.ToInt32(temp3);
                int temp4i = Convert.ToInt32(temp4);

                int temp5i = Convert.ToInt32(temp5);
                int temp6i = Convert.ToInt32(temp6);

                int temp7i = Convert.ToInt32(temp7);
                int temp8i = Convert.ToInt32(temp8);

                x = Convert.ToDouble(((temp3i << 8) | temp4i)) / 32768 * 180;
                y = Convert.ToDouble(((temp5i << 8) | temp6i)) / 32768 * 180;
                z = Convert.ToDouble(((temp7i << 8) | temp8i)) / 32768 * 180;

                if (x>180)
                {
                    x = x - 360;
                }                
                if (y>180)
                {
                    y = y - 360;
                }                
                if (z>180)
                {
                    z = z - 360;
                }
            }
        }
    }

#endregion
}

打开串口通信工具:

打开虚拟串口,我用的是VSPD虚拟串口工具,添加虚拟串口1,2

打开串口的调试器,我用的是SSCOM

 

打开Unity,运行,Console会有串口打开的Log

在串口调试软件中的数据发送区写上发送的数据,然后点击发送,接收区会收到发送的数据,Unity的Console上会有接收的数据显示

至此。通信完成。

三、代码解释(对于我开发过程中产生的问题的解释)

TxData[3] = "5003003d00039986";

 这是我的下位机的机号,暂时我并未测试下位机通信是否正常。

Data[0] = Convert.ToByte(TxData[3].Substring(i * 2, 2), 16);

 public static byte ToByte(string value, int fromBase);             是一个8位16进制的数据

如果 fromBase 为 16,则可以在 value 参数指定的数字前面加上“0x”或“0X”。

这里的数据转换过程如下:

首先分割数据,两位一组50 03 00 3d 00 03 99 86

每一个组前要加上 0X : 0X50 0X03 0X00 0X3d 0X00 0X03 0X99 0X86

转二进制:01010000 00000011 00000000 00111101 00000000 00000011 10011001 10000110

转十进制:80 3 0 61 0 3 153 137

如果传输的时候,没有加上HEX发送的话,接收到的数据就是35 30 30 33 30 30 33 64 30 30 30 33 39 39 38 36 85 76(最后两位是校验位)

        0x35的二进制是 0011 0101 对应的十进制是53 对应的ASCII是5 也就是第一位。

同理 0x30的二进制是 0011 0000 对应的十进制是48 对应的ASCII是0。

sb.AppendFormat("{0:x2}" + "", data[i]);//{0:X2}将第一个参数转换成大写的十六进制文本,长度为2,不足前面补0

将接收到的8位16进制转换为两位16进制的数据。

至此结束。感谢大家观看,欢迎指正。

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值