untiy的串口通信是垃圾中的垃圾,只能使用线程监听串口消息,而不能使用c#提供的更方便安全的注册委托的方法,根本原因是mono没有完全实现c#的using System.IO.Ports下的内容,导致unity中只能用被阉割过的串口
首先,引入命名空间
using System.IO.Ports;
这是一个最简单的开启串口的演示
SerialPort s = new SerialPort
{
//串口的名字 波特率 数据位 停止位 验证位 必须和硬件中设置相同,否则无法正常通信
PortName = "COM1",//串口的名字可以通过设备管理器的 “端口”查看
BaudRate = 115200,//波特率
DataBits = 8,//数据位
StopBits = StopBits.One,//停止位
Parity = Parity.None,//验证位
DtrEnable = true,
RtsEnable = true,
ReadTimeout = 1000
};
s.Open();
对于一个串口,我们可以通过一个线程监听串口发过来的消息
//接上放代码,打开一个串口
s.Open();
//监听当前串口的消息
Thread recT = new Thread(SerialPort_DataReceived);
recT.IsBackground = true;
recT.Start();
//接收线程的方法
public void SerialPort_DataReceived()
{
while (true)
{
if (s.IsOpen)
{
var length = s.BytesToRead;
byte[] bytestest = new byte[length];
s.Read(bytestest, 0, length); //得把数据读出来,不然缓存区域会一直有数据
//处理数据
}
}
}
关闭串口
s.Close();
对于纯c# 代码,可以使用委托更优雅的接收串口消息,因为线程接收的方式可以能出现数据粘包
但这个委托在Untiy中无法使用
SerialPort s;
private void Awake()
{
s.DataReceived += ReceiveData;
}
private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
//读取串口缓冲区的字节数据
byte[] result = new byte[s.BytesToRead];
}
以下是批量查找串口,批量接收消息,批量关闭
批量查找
/// <summary>
/// 获取本地可用串口列表
/// </summary>
/// <param name="ignoreCom1">是否忽略串口1 PC机默认有COM1</param>
/// <returns>返回串口名称列表</returns>
public List<SerialPort> GetPorts(bool ignoreCom1 = true)
{
Ports = new List<SerialPort>();
string[] proteNames = System.IO.Ports.SerialPort.GetPortNames();
foreach (string protName in proteNames)
{
if (ignoreCom1 && protName == "COM1") continue;
// if ( protName != "COM4"&&protName != "COM5") continue;
var s = new SerialPort
{
PortName = protName,
BaudRate = 115200,
DataBits = 8,
StopBits = StopBits.One,
Parity = Parity.None,
DtrEnable = true,
RtsEnable = true,
ReadTimeout = 1000
};
Ports.Add(s);
}
return Ports;
}
批量接收
/// <summary>
/// 打开串口(包括新启动和再次启动)
/// </summary>
/// <returns></returns>
public bool Start()
{
try
{
GetPorts();
如果串口开启了就关闭
//Stop();
foreach (SerialPort p in Ports)
{
try
{
//开启当前的串口
p.Open();
//监听当前串口的消息
Thread recT = new Thread(SerialPort_DataReceived);
recT.IsBackground = true;
recT.Start(p);
threadsDic.Add(p, recT);
}
catch (Exception ex)
{
Console.WriteLine($"打开串口{p.PortName}时发生错误{ex.Message}");
}
}
return true;
}
catch (Exception e)
{
Console.WriteLine(DateTime.Now.ToShortDateString() + e.Message + e.StackTrace);
return false;
}
}
/// <summary>
/// 接收信号触发事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void SerialPort_DataReceived(object obj)
{
while (true)
{
SerialPort tempPort = obj as SerialPort;
//更新最后获取信号的时间
//UpdateSignalTime?.Invoke(DateTime.Now, 0);
//进行数据分包
if (tempPort.IsOpen)
{
var length = tempPort.BytesToRead;
//对异常数据进行分包
if (length > 32) //这里是32位是因为我规定的硬件发送一条数据为32个字节
{
byte[] bytestest = new byte[length];
tempPort.Read(bytestest, 0, length); //得把数据读出来,不然缓存区域会一直有数据
ShuntPacker(tempPort, bytestest);
continue;
}
//少包丢弃
else if (length < 32)
{
continue;
}
byte[] bytes = new byte[length];
tempPort.Read(bytes, 0, length); //得把数据读出来,不然缓存区域会一直有数据
//处理一个包的数据
OnePackerHandle(tempPort, bytes);
}
else
{
Console.WriteLine("串口非正常关闭");
}
}
}
批量关闭
/// <summary>
/// 关闭所有串口 清空缓存数据 清空监听线程
/// </summary>
/// <returns></returns>
public void StopAllSerialPort()
{
foreach (SerialPort p in Ports)
{
StopOneSerialPort(p);
}
lastStr = null;
ReceivedData = null;
lock (lockAck)
{
if (AckCache != null && AckCache.Count > 0)
{
AckCache.Clear();
}
}
}
/// <summary>
/// 关闭一个串口
/// </summary>
/// <param name="serialPort"></param>
public void StopOneSerialPort(SerialPort serialPort)
{
try
{
if (serialPort != null && serialPort.IsOpen)
{
//关闭串口
serialPort.Close();
//关闭接收线程
threadsDic[serialPort].Abort();
threadsDic.Remove(serialPort);
}
}
catch (Exception e)
{
// LogInfo.WriteErrorLog(e.Message + "|||" + e.StackTrace);
}
}