Unity在Windows下使用串口通信

发表于2017-08-15
评论0 2.8k浏览
环境:Unity4.7.2,Windows7

之前工作开发PC端的程序,需要用到串口通信,也在网上查了一些东西,趟过了一些坑,在这里做一下记录

关于串口这个东西这篇文章讲的比较清晰:

代码:
using System.IO.Ports;
using System.Threading;
using System.Collections.Generic;
using System;
/// <summary>
/// 串口通信
/// </summary>
public class SerialPortItem
{
    /// <summary>
    /// 开启串口参数
    /// </summary>
    public class SerialPortParam
    {
        public string portName;
        public int BaudRate;
        public Parity Parity;
        public StopBits StopBits;
        public int DataBits;
        public Handshake Handshake;
        public bool RtsEnable;
    }
    private SerialPort serialPort;
    private bool isClose;
    private Thread serialPortThread;//收发串口线程
    //读取数据缓存
    private byte[] readDataBuffer = new byte[1024];
    private int readDataLen;//读取到数据长度
    //写数据缓存
    private List<byte> writeDataBuffer = new List<byte>();
    private bool isOpen;
    /// <summary>
    /// 是否开启端口
    /// </summary>
    public bool IsOpen
    {
        get { return isOpen; }
    }
    #region 事件
    /// <summary>
    /// 接到数据(子线程)
    /// </summary>
    public Action<byte[]> OnReceiveData;
    /// <summary>
    /// 错误(子线程)
    /// </summary>
    public Action<string> OnError;
    #endregion
    /// <summary>
    /// 开启端口
    /// </summary>
    /// <param name="param"></param>
    public void Open(SerialPortParam param)
    {
        serialPort = new SerialPort(param.portName);
        serialPort.BaudRate = param.BaudRate;
        serialPort.Parity = param.Parity;
        serialPort.StopBits = param.StopBits;
        serialPort.DataBits = param.DataBits;
        serialPort.Handshake = param.Handshake;
        serialPort.RtsEnable = param.RtsEnable;
        serialPort.ReadTimeout = 1;
        serialPort.WriteTimeout = 1;
        try
        {
            serialPort.Open();
        }
        catch (Exception ex)
        {
            if (OnError != null)
                OnError(ex.ToString());
            Close();
        }
        isOpen = true;
        isClose = false;
        serialPortThread = new Thread(new ParameterizedThreadStart(work));
        serialPortThread.Start(serialPort);
    }
    /// <summary>
    /// 发送数据
    /// </summary>
    /// <param name="bytes"></param>
    public void Send(byte[] bytes)
    {
        if (serialPort != null
            && serialPort.IsOpen)
        {
            lock (writeDataBuffer)
            {
                writeDataBuffer.AddRange(bytes);
            }
        }
    }
    public void Close()
    {
        isOpen = false;
        isClose = true;
        serialPort = null;
    }
    private void work(object obj)
    {
        SerialPort sp = (SerialPort)obj;
        while (true)
        {
            if (isClose)
                break;
            if (!sp.IsOpen)
            {
                break;
            }
            //读取
            try
            {
                readDataLen = sp.Read(readDataBuffer, 0, readDataBuffer.Length);
                if (readDataLen > 0)
                {
                    byte[] receiveBytes = new byte[readDataLen];
                    Array.Copy(readDataBuffer, 0, receiveBytes, 0, receiveBytes.Length);
                    if (OnReceiveData != null)
                        OnReceiveData(receiveBytes);
                }
            }
            catch (TimeoutException)
            {//正常结束
            }
            catch (Exception ex)
            {
                sp.Close();
                if (OnError != null)
                    OnError(ex.ToString());
            }
            //写入
            if (writeDataBuffer.Count > 0)
            {
                byte[] writeBytes = null;
                lock (writeDataBuffer)
                {
                    writeBytes = writeDataBuffer.ToArray();
                    writeDataBuffer.Clear();
                }
                try
                {
                    sp.Write(writeBytes, 0, writeBytes.Length);
                }
                catch (TimeoutException)
                {//正常结束
                }
                catch (Exception ex)
                {
                    sp.Close();
                    if (OnError != null)
                        OnError(ex.ToString());
                }
            }
        }
        sp.Close();
    }
}
用法很简单,Open开启串口,Send向串口发送数据,Close关闭串口,从串口接到消息后触发OnReceiveData事件,串口出现异常触发OnError

需要注意几点:
1.
serialPort.ReadTimeout = 1;
serialPort.WriteTimeout = 1;
因为Unity的SerialPort类不能触发DataReceived事件,所以必须自己来读取数据,而这两句是设置读写超时,否则线程会被阻止不能往下运行,设置后会触发TimeoutException异常是正常触发,捕获后不用管

2.
public Action<byte[]> OnReceiveData;和public Action<string> OnError;
接收到数据会触发这个事件,但是这个事件是在子线程触发的,不能直接调用Unity的组建,所以需要由监听方自行处理同步问题

这几个是我做串口通信时候参考:



如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: