关于unity串口通信的坑,数据处理

修改记录

1.20211229 修改List读取,线程占用无法关闭重启问题

1.API平台坑——这个坑较小,网上有资料可查,易更改。

将Unity3D的API平台切换成.NET2.0,切换方法: “Edit–>project Setting–>Player–>Other Setting –>Api Compatibility level”。在这里将“.NET2.0 Subset”切换为“.NET4.X”(.NET2.0也可以)。以unity2019.3.2为例

2.按字节数组发送处理信息,信息缺失

在使用线程接收byte数据时,按字节数组发送处理信息,会出现数据分两次接收问题(往往在第一次接收时,只接收第一个数据)`

        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);
        }

解决方法:

**

1.队列转存,然后再读取(需要设置读取长度)

**

using UnityEngine;
using System.Collections;

using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.Text;

public class SerialPortReciever : MonoBehaviour
{

    //串口的通信类
    private SerialPort sp;
    //队列(先后存储消息,以便处理)
    private Queue<string> queueDataPool;
    private List<string> list;
    private List<string> strList = new List<string>();

    //处理数据的线程
    private Thread tPort;
    //接收数据的线程
    private Thread tPortDeal;
    //输出池
    private string strOutPool = string.Empty;
    //最终的值
    string finalstring = string.Empty;
    //临时的值
    string tempstring = string.Empty;

    // Use this for initialization
    void Start()
    {
        //创建一个队列
        queueDataPool = new Queue<string>();
        //创建一个串口
        sp = new SerialPort("COM5", 9600, Parity.None, 8, StopBits.One);
        //判断是否打开串口
        if (!sp.IsOpen)
        {
            sp.Open();
        }
        //创建一个线程(方法),开始执行是调用的方法
        tPort = new Thread(DealData);
        tPort.Start();
        tPortDeal = new Thread(ReceiveData);
        tPortDeal.Start();
    }

    // Update is called once per frame
    void Update()
    {
        //当前线程的执行状态
        if (!tPortDeal.IsAlive)
        {
            tPortDeal = new Thread(ReceiveData);
            tPortDeal.Start();
        }
        if (!tPort.IsAlive)
        {
            tPort = new Thread(DealData);
            tPort.Start();

        }

    }

    //读取信息
    private void ReceiveData()
    {
        try
        {
            Byte[] buf = new Byte[1];
            string sbReadline2str = string.Empty;
            if (sp.IsOpen) sp.Read(buf, 0, 1);
            foreach (var item in buf)
            {
                Debug.Log(item.ToString());
            }
          
            if (buf.Length == 0)
            {
                return;
            }
            if (buf != null)
            {
                for (int i = 0; i < buf.Length; i++)
                {
                    sbReadline2str += Encoding.Default.GetString(buf);
                    queueDataPool.Enqueue(sbReadline2str);

                }
            }
        }
        catch (Exception ex)
        {
            Debug.Log(ex);
        }
    }

    //满16个字节打印
    private void DealData()
    {

        while (queueDataPool.Count != 0)
        {
            list = new List<string>(queueDataPool);
            queueDataPool.Clear();
            for (int i = 0; i < list.Count; i ++)
            {
                strOutPool += list[i];
                strList.Add(strOutPool);
                strOutPool = string.Empty;
            }
            
              //  Debug.Log(strList.Count);

            for (int i = 0; i < queueDataPool.Count; i++)
            {
                strOutPool += queueDataPool.Dequeue();

                //switch (queueDataPool.Peek())
                //{
                //    default:
                //        break;
                //}
                if (strOutPool.Length == 16)
                {
                    Debug.Log(strOutPool);


                }
                // Debug.Log(strOutPool);
            }
        }

    }

    //输出信息
    private void SendSerialPortData(string data)
    {
        if (sp.IsOpen)
        {
            sp.WriteLine(data);
        }
    }

    //当程序退出时的操作
    void OnApplicationQuit()
    {
        sp.Close();
    }
}

2.存入list,按需获取(修改)

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

public class PortControl : MonoBehaviour
{
    #region 定义串口属性 
    public string portName = "COM5";//串口名
    public int baudRate = 9600;//波特率
    public Parity parity = Parity.None;//效验位
    public int dataBits = 8;//数据位
    public StopBits stopBits = StopBits.One;//停止位
    SerialPort sp = null;
    Thread dataReceiveThread;
    public static List<byte> bytelist = new List<byte>();  
    #endregion

    public ThreeAxis threeAxis;
    void Start()
    {
        OpenPort();
        dataReceiveThread = new Thread(new ThreadStart(DataReceiveFunction));
        dataReceiveThread.Start();
    }
    #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
    
    #region 接收数据
    void DataReceiveFunction()
    {
        while (sp != null && sp.IsOpen)
        {
                int bytes = sp.BytesToRead;
                byte[] buffer = new byte[bytes];
                try
                {
                    sp.Read(buffer, 0, bytes);
                    if (bytes == 0)
                    {
                        continue;
                    }
                    else
                    {
                        bytelist.AddRange(buffer);
                    }
                }
                catch (Exception ex)
                {
                }
            }
            Thread.Sleep(100);
    }
    #endregion

    #region 发送数据
    public void WriteData(string dataStr)
    {
        if (sp.IsOpen)
        {
            sp.Write(dataStr);
        }
    }

同样需要设定初始值,比如:

 if (bytelist.Count >3)//3是帧头加帧尾加最小一位数据
        {
            #region 根据帧头判断数据类型

            switch (bytelist[0])
            {
                case :
                    break;
                  
            }
            #endregion
            bytelist.Clear();//处理一次数据,清空list
        }

需要注意: 在每次读取list数据,然后就清空整个list,再进行下一次数据处理,可能会造成数据丢失,建议按位取数据,清除已取出的数据。

工具

comdemo
串口调试工具
虚拟串口工具

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值