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的组建,所以需要由监听方自行处理同步问题
这几个是我做串口通信时候参考:
