Unity在Windows下使用串口通信
发表于2017-08-15
环境: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的组建,所以需要由监听方自行处理同步问题
这几个是我做串口通信时候参考: